From 53128a92de637b0328bd664d6cd41275ab1bf12a Mon Sep 17 00:00:00 2001 From: Yoshino-s Date: Thu, 16 Mar 2023 14:11:46 +0000 Subject: [PATCH] search --- .dockerignore | 9 ++ .env | 2 +- Dockerfile | 13 +-- components/Header/Header.tsx | 94 +++++++++++++++++++ components/ParagraphGrid/ParagraphGrid.tsx | 2 +- docker-compose.yml | 5 +- migrate.ts | 50 ++++++++++ next.config.js | 6 +- package.json | 1 + pages/_app.tsx | 14 +++ pages/index.tsx | 12 +-- pages/paragraph/[id].tsx | 2 +- pages/search/[word].tsx | 70 ++++++++++++++ pages/tag copy/[name].tsx | 61 ++++++++++++ pages/tag/[name].tsx | 2 +- .../20230314084213_dev/migration.sql | 13 --- .../20230314090553_dev/migration.sql | 22 ----- .../20230316135037_dev/migration.sql | 17 ++++ .../20230316135533_dev/migration.sql | 2 + prisma/migrations/migration_lock.toml | 2 +- prisma/schema.prisma | 14 ++- yarn.lock | 13 +++ 22 files changed, 358 insertions(+), 68 deletions(-) create mode 100644 .dockerignore create mode 100644 components/Header/Header.tsx create mode 100644 migrate.ts create mode 100644 pages/search/[word].tsx create mode 100644 pages/tag copy/[name].tsx delete mode 100644 prisma/migrations/20230314084213_dev/migration.sql delete mode 100644 prisma/migrations/20230314090553_dev/migration.sql create mode 100644 prisma/migrations/20230316135037_dev/migration.sql create mode 100644 prisma/migrations/20230316135533_dev/migration.sql diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..18c4237 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.env +Dockerfile +docker-compose.yml +.dockerignore +node_modules +npm-debug.log +README.md +.next +.git \ No newline at end of file diff --git a/.env b/.env index 368b148..28afa16 100644 --- a/.env +++ b/.env @@ -8,4 +8,4 @@ MINIO_ACCESS_KEY=spider MINIO_SECRET_KEY=spiderman! MINIO_ENDPOINT=http://docker.pve:9001/api/v1 MINIO_ENABLED=1 -DATABASE_URL=postgres://postgres:postgres@database.pve/spider \ No newline at end of file +DATABASE_URL=mysql://vault:vault@database.pve/spider \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index b7ef4f8..1fae422 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,22 +4,17 @@ FROM base AS deps RUN apk add --no-cache libc6-compat WORKDIR /app -COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ +COPY package.json yarn.lock ./ RUN yarn config set registry https://nexus.yoshino-s.xyz/repository/npm/ -RUN \ - if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ - elif [ -f package-lock.json ]; then npm ci; \ - elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \ - else echo "Lockfile not found." && exit 1; \ - fi +RUN yarn --frozen-lockfile FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . -RUN yarn build - +RUN yarn prisma generate && yarn build + FROM base AS runner WORKDIR /app diff --git a/components/Header/Header.tsx b/components/Header/Header.tsx new file mode 100644 index 0000000..fe20215 --- /dev/null +++ b/components/Header/Header.tsx @@ -0,0 +1,94 @@ +import { ActionIcon, createStyles, Group, Header, rem, TextInput } from "@mantine/core"; +import { useForm } from "@mantine/form"; +import { IconSearch } from "@tabler/icons"; +import { useRouter } from "next/router"; + +const useStyles = createStyles((theme) => ({ + header: { + paddingLeft: theme.spacing.md, + paddingRight: theme.spacing.md, + }, + + inner: { + height: rem(56), + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }, + + links: { + [theme.fn.smallerThan("md")]: { + display: "none", + }, + }, + + search: { + [theme.fn.smallerThan("xs")]: { + display: "none", + }, + }, + + link: { + display: "block", + lineHeight: 1, + padding: `${rem(8)} ${rem(12)}`, + borderRadius: theme.radius.sm, + textDecoration: "none", + color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.colors.gray[7], + fontSize: theme.fontSizes.sm, + fontWeight: 500, + + "&:hover": { + backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0], + }, + }, +})); + +interface HeaderSearchProps { + links: { link: string; label: string }[]; +} + +export function HeaderSearch({ links }: HeaderSearchProps) { + const { classes } = useStyles(); + const router = useRouter(); + + const form = useForm({ + initialValues: { + search: "", + }, + }); + + const items = links.map((link) => ( + + {link.label} + + )); + + function submit({ search }: { search: string }) { + router.push({ + pathname: "/search/[word]", + query: { word: search }, + }); + } + + return ( +
+
+ {items} +
+ + + + + + +
+
+
+ ); +} diff --git a/components/ParagraphGrid/ParagraphGrid.tsx b/components/ParagraphGrid/ParagraphGrid.tsx index fa2957b..5b6bd5e 100644 --- a/components/ParagraphGrid/ParagraphGrid.tsx +++ b/components/ParagraphGrid/ParagraphGrid.tsx @@ -52,7 +52,7 @@ export default function ParagraphGrid({ {paragraphs.map((paragraph) => { return ( - + (props.colorScheme); @@ -25,6 +27,18 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) { + diff --git a/pages/index.tsx b/pages/index.tsx index 64dcfd8..279625c 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,7 +1,5 @@ -import { Button } from "@mantine/core"; import { Paragraph } from "@prisma/client"; import { GetServerSidePropsContext, GetServerSidePropsResult } from "next"; -import { useRouter } from "next/router"; import ParagraphGrid from "../components/ParagraphGrid/ParagraphGrid"; import { prismaClient } from "../lib/db"; @@ -14,15 +12,7 @@ interface ListProps { } export default function HomePage(props: ListProps) { - const router = useRouter(); - - return ( - router.push("/statistic")}>Statistic} - {...props} - /> - ); + return ; } export async function getServerSideProps( diff --git a/pages/paragraph/[id].tsx b/pages/paragraph/[id].tsx index aa8625f..3ac27e1 100644 --- a/pages/paragraph/[id].tsx +++ b/pages/paragraph/[id].tsx @@ -48,7 +48,7 @@ export default function ParagraphPage({ paragraph }: { paragraph: Paragraph }) { - {paragraph.tags.map((tag) => ( + {paragraph.tags.split(",").map((tag) => ( diff --git a/pages/search/[word].tsx b/pages/search/[word].tsx new file mode 100644 index 0000000..96abb90 --- /dev/null +++ b/pages/search/[word].tsx @@ -0,0 +1,70 @@ +import { Paragraph } from "@prisma/client"; +import { GetServerSidePropsContext, GetServerSidePropsResult } from "next"; + +import ParagraphGrid from "../../components/ParagraphGrid/ParagraphGrid"; +import { prismaClient } from "../../lib/db"; + +interface ListProps { + paragraphs: Omit[]; + skip: number; + take: number; + total: number; + word: string; +} + +export default function TagPage(props: ListProps) { + return ; +} + +export async function getServerSideProps( + ctx: GetServerSidePropsContext +): Promise> { + const skip = Number(ctx.query.skip ?? 0); + const take = Number(ctx.query.take ?? 12); + const word = ctx.params?.word; + + if (typeof word !== "string") { + return { notFound: true }; + } + + const condition = { + content: { + search: word, + }, + tags: { + search: word, + }, + author: { + search: word, + }, + title: { + search: word, + }, + }; + + const [total, paragraphs] = await Promise.all([ + prismaClient.paragraph.count({ + where: condition, + }), + await prismaClient.paragraph.findMany({ + where: condition, + skip: Number(skip), + take: Number(take), + orderBy: { + time: "desc", + }, + select: { + id: true, + title: true, + tags: true, + time: true, + author: true, + cover: true, + }, + }), + ]); + paragraphs.forEach((paragraph) => { + paragraph.time = paragraph.time.getTime() as any; + }); + return { props: { word, paragraphs, skip, take, total } }; +} diff --git a/pages/tag copy/[name].tsx b/pages/tag copy/[name].tsx new file mode 100644 index 0000000..a631d0e --- /dev/null +++ b/pages/tag copy/[name].tsx @@ -0,0 +1,61 @@ +import { Paragraph } from "@prisma/client"; +import { GetServerSidePropsContext, GetServerSidePropsResult } from "next"; + +import ParagraphGrid from "../../components/ParagraphGrid/ParagraphGrid"; +import { prismaClient } from "../../lib/db"; + +interface ListProps { + paragraphs: Omit[]; + skip: number; + take: number; + total: number; + tag: string; +} + +export default function TagPage(props: ListProps) { + return ; +} + +export async function getServerSideProps( + ctx: GetServerSidePropsContext +): Promise> { + const skip = Number(ctx.query.skip ?? 0); + const take = Number(ctx.query.take ?? 12); + const tag = ctx.params?.name; + + if (!tag || typeof tag !== "string") { + return { notFound: true }; + } + + const condition = { + tags: { + contains: tag, + }, + }; + + const [total, paragraphs] = await Promise.all([ + prismaClient.paragraph.count({ + where: condition, + }), + await prismaClient.paragraph.findMany({ + where: condition, + skip: Number(skip), + take: Number(take), + orderBy: { + time: "desc", + }, + select: { + id: true, + title: true, + tags: true, + time: true, + author: true, + cover: true, + }, + }), + ]); + paragraphs.forEach((paragraph) => { + paragraph.time = paragraph.time.getTime() as any; + }); + return { props: { tag, paragraphs, skip, take, total } }; +} diff --git a/pages/tag/[name].tsx b/pages/tag/[name].tsx index 85621ad..a631d0e 100644 --- a/pages/tag/[name].tsx +++ b/pages/tag/[name].tsx @@ -29,7 +29,7 @@ export async function getServerSideProps( const condition = { tags: { - has: tag, + contains: tag, }, }; diff --git a/prisma/migrations/20230314084213_dev/migration.sql b/prisma/migrations/20230314084213_dev/migration.sql deleted file mode 100644 index 254086a..0000000 --- a/prisma/migrations/20230314084213_dev/migration.sql +++ /dev/null @@ -1,13 +0,0 @@ --- CreateTable -CREATE TABLE "paragraph" ( - "id" TEXT NOT NULL, - "author" TEXT NOT NULL, - "content" TEXT NOT NULL, - "cover" TEXT, - "markdown" BOOLEAN, - "tags" TEXT[], - "time" DATE NOT NULL, - "title" TEXT NOT NULL, - - CONSTRAINT "paragraph_pkey" PRIMARY KEY ("id") -); diff --git a/prisma/migrations/20230314090553_dev/migration.sql b/prisma/migrations/20230314090553_dev/migration.sql deleted file mode 100644 index d51e0ae..0000000 --- a/prisma/migrations/20230314090553_dev/migration.sql +++ /dev/null @@ -1,22 +0,0 @@ -/* - Warnings: - - - You are about to drop the `paragraph` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropTable -DROP TABLE "paragraph"; - --- CreateTable -CREATE TABLE "Paragraph" ( - "id" TEXT NOT NULL, - "author" TEXT NOT NULL, - "content" TEXT NOT NULL, - "cover" TEXT, - "markdown" BOOLEAN, - "tags" TEXT[], - "time" DATE NOT NULL, - "title" TEXT NOT NULL, - - CONSTRAINT "Paragraph_pkey" PRIMARY KEY ("id") -); diff --git a/prisma/migrations/20230316135037_dev/migration.sql b/prisma/migrations/20230316135037_dev/migration.sql new file mode 100644 index 0000000..ec91521 --- /dev/null +++ b/prisma/migrations/20230316135037_dev/migration.sql @@ -0,0 +1,17 @@ +-- CreateTable +CREATE TABLE `Paragraph` ( + `id` VARCHAR(191) NOT NULL, + `author` VARCHAR(191) NOT NULL, + `content` VARCHAR(191) NOT NULL, + `cover` VARCHAR(191) NULL, + `markdown` BOOLEAN NULL, + `tags` VARCHAR(191) NOT NULL, + `time` DATE NOT NULL, + `title` VARCHAR(191) NOT NULL, + + INDEX `Paragraph_author_idx`(`author`), + INDEX `Paragraph_time_idx`(`time`), + INDEX `Paragraph_title_idx`(`title`), + FULLTEXT INDEX `Paragraph_content_author_title_tags_idx`(`content`, `author`, `title`, `tags`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/migrations/20230316135533_dev/migration.sql b/prisma/migrations/20230316135533_dev/migration.sql new file mode 100644 index 0000000..99ca840 --- /dev/null +++ b/prisma/migrations/20230316135533_dev/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `Paragraph` MODIFY `content` LONGTEXT NOT NULL; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml index fbffa92..e5a788a 100644 --- a/prisma/migrations/migration_lock.toml +++ b/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually # It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file +provider = "mysql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 40df40a..967c771 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,19 +1,25 @@ generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + previewFeatures = ["fullTextSearch", "fullTextIndex"] } datasource db { - provider = "postgres" + provider = "mysql" url = env("DATABASE_URL") } model Paragraph { id String @id author String - content String + content String @db.LongText cover String? markdown Boolean? - tags String[] + tags String time DateTime @db.Date title String + + @@index([author]) + @@index([time]) + @@index([title]) + @@fulltext([content, author, title, tags]) } diff --git a/yarn.lock b/yarn.lock index ce46178..54baaa2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1745,6 +1745,14 @@ dependencies: "@mantine/utils" "6.0.0" +"@mantine/form@^6.0.2": + version "6.0.2" + resolved "https://nexus.yoshino-s.xyz/repository/npm/@mantine/form/-/form-6.0.2.tgz#560b0e2b9e5775ec564e87c2c4d8bcf46e43f805" + integrity sha512-M18h8NBhV3P1iq+A1xS1x4dFN+xREu9k6/NmY5ftwYf4UwhVgiscKQhJ28ZC+m+oAtMZmdBhsHM5LVnFquPQJA== + dependencies: + fast-deep-equal "^3.1.3" + klona "^2.0.5" + "@mantine/hooks@6.0.0": version "6.0.0" resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.0.tgz#08b67946e0b45f67181efa9e37df68f92a8ee6d1" @@ -8678,6 +8686,11 @@ klona@^2.0.4: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== +klona@^2.0.5: + version "2.0.6" + resolved "https://nexus.yoshino-s.xyz/repository/npm/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== + language-subtag-registry@~0.3.2: version "0.3.21" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"