mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-16 01:01:38 +00:00
Add search API
* update prisma * Add search API in page * add API with fetch * Update search with global state
This commit is contained in:
23
lib/API/index.ts
Normal file
23
lib/API/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { SearchType } from 'lib/API/types';
|
||||
|
||||
const search = async (q: string, page = 1) => {
|
||||
const body = {
|
||||
q,
|
||||
page,
|
||||
};
|
||||
|
||||
const response = await fetch('/api/search', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result: SearchType = await response.json();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
export { search };
|
14
lib/API/types.ts
Normal file
14
lib/API/types.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export interface SearchType {
|
||||
page: number;
|
||||
result: SearchResult[];
|
||||
hasNext: boolean;
|
||||
totalPage: number;
|
||||
message: string;
|
||||
}
|
||||
export interface SearchResult {
|
||||
id: string;
|
||||
title: string;
|
||||
date: string;
|
||||
url: string;
|
||||
desc: string;
|
||||
}
|
14
lib/utils/debounce.ts
Normal file
14
lib/utils/debounce.ts
Normal file
@ -0,0 +1,14 @@
|
||||
function debounce<Params extends any[]>(
|
||||
func: (...args: Params) => void,
|
||||
ms: number
|
||||
) {
|
||||
let timeout: NodeJS.Timeout;
|
||||
return function (this: unknown, ...args: Params) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
func.apply(this, args);
|
||||
}, ms);
|
||||
};
|
||||
}
|
||||
|
||||
export default debounce;
|
@ -14,7 +14,7 @@
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@next/mdx": "^12.0.9",
|
||||
"@prisma/client": "^3.8.1",
|
||||
"@prisma/client": "^3.9.1",
|
||||
"algoliasearch": "^4.12.0",
|
||||
"classnames": "^2.3.1",
|
||||
"date-fns": "^2.28.0",
|
||||
@ -56,7 +56,7 @@
|
||||
"jest": "^27.4.7",
|
||||
"postcss": "^8.4.5",
|
||||
"prettier": "^2.5.1",
|
||||
"prisma": "^3.8.1",
|
||||
"prisma": "^3.9.1",
|
||||
"tailwindcss": "^3.0.17",
|
||||
"typescript": "4.5.5"
|
||||
}
|
||||
|
@ -10,12 +10,23 @@ export default async function handler(
|
||||
) {
|
||||
const search = async () => {
|
||||
const searchBody = req.body;
|
||||
console.log(searchBody);
|
||||
|
||||
try {
|
||||
const { q } = searchBody;
|
||||
|
||||
const result = await prisma.posts.findMany({
|
||||
if (!q) throw new Error();
|
||||
|
||||
const queryOrder: {
|
||||
orderBy: {
|
||||
title: 'asc';
|
||||
};
|
||||
} = {
|
||||
orderBy: {
|
||||
title: 'asc',
|
||||
},
|
||||
};
|
||||
|
||||
const queryWhere = {
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
@ -30,6 +41,9 @@ export default async function handler(
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const querySelect = {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
@ -37,42 +51,53 @@ export default async function handler(
|
||||
url: true,
|
||||
desc: true,
|
||||
},
|
||||
});
|
||||
|
||||
const data = {
|
||||
result,
|
||||
};
|
||||
|
||||
return res.status(200).json(result);
|
||||
const count = await prisma.posts.count(queryWhere);
|
||||
|
||||
let data = {};
|
||||
const totalPage = Math.ceil(count / 10);
|
||||
|
||||
if (count > 10) {
|
||||
const page = searchBody.page ?? 1;
|
||||
|
||||
const result = await prisma.posts.findMany({
|
||||
take: 10,
|
||||
skip: (page - 1) * 10,
|
||||
...queryOrder,
|
||||
...queryWhere,
|
||||
...querySelect,
|
||||
});
|
||||
|
||||
data = {
|
||||
page,
|
||||
result,
|
||||
hasNext: totalPage - page > 0,
|
||||
totalPage,
|
||||
message: 'ok',
|
||||
};
|
||||
} else {
|
||||
const result = await prisma.posts.findMany({
|
||||
...queryOrder,
|
||||
...queryWhere,
|
||||
...querySelect,
|
||||
});
|
||||
|
||||
data = {
|
||||
page: 1,
|
||||
result,
|
||||
hasNext: false,
|
||||
totalPage,
|
||||
message: 'ok',
|
||||
};
|
||||
}
|
||||
|
||||
return res.status(200).json(data);
|
||||
} catch {
|
||||
return res.status(404).json({
|
||||
message: 'Not found.',
|
||||
});
|
||||
}
|
||||
|
||||
// try {
|
||||
// const { name } = q;
|
||||
// if (Array.isArray(name)) throw new Error();
|
||||
|
||||
// const user = await prisma.users.findFirst({
|
||||
// select: {
|
||||
// username: true,
|
||||
// emil: true,
|
||||
// },
|
||||
// where: {
|
||||
// username: name,
|
||||
// },
|
||||
// });
|
||||
// user
|
||||
// ? res.status(200).json(user)
|
||||
// : res.status(404).json({
|
||||
// message: 'Not found.',
|
||||
// });
|
||||
// } catch (e) {
|
||||
// return res.status(404).json({
|
||||
// message: 'Not found.',
|
||||
// });
|
||||
// }
|
||||
};
|
||||
|
||||
switch (req.method) {
|
||||
|
@ -1,19 +1,44 @@
|
||||
import { ChangeEventHandler, ReactElement } from 'react';
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
ReactElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Head from 'next/head';
|
||||
import cn from 'classnames';
|
||||
import { FiSearch } from 'react-icons/fi';
|
||||
import { ActionKind, useRUAContext } from 'lib/store';
|
||||
import debounce from 'lib/utils/debounce';
|
||||
import { search } from 'lib/API';
|
||||
import { SearchType } from 'lib/API/types';
|
||||
|
||||
const MainLayout = dynamic(() => import('layouts/MainLayout'));
|
||||
|
||||
const Search = () => {
|
||||
const { state, dispatch } = useRUAContext();
|
||||
|
||||
const handleInput: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
const [searchResult, setSearchResult] = useState<SearchType>();
|
||||
const querySearch = async (q: string, page = 1) => {
|
||||
const result = await search(q, page);
|
||||
|
||||
if (result?.message == 'ok') {
|
||||
setSearchResult(result);
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const debounceSearch = useCallback(debounce(querySearch, 350), []);
|
||||
|
||||
const handleInput: ChangeEventHandler<HTMLInputElement> = async (e) => {
|
||||
dispatch({ type: ActionKind.SETQUERY, payload: e.target.value });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
debounceSearch(state.searchQuery, 1);
|
||||
}, [debounceSearch, state.searchQuery]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@ -40,6 +65,12 @@ const Search = () => {
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
{searchResult?.result.map((result) => (
|
||||
<p key={result.id}>{result.title}</p>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -4,27 +4,51 @@ const { PrismaClient } = prismaClient;
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const content = await prisma.posts.findMany({
|
||||
const result = await prisma.posts.findMany({
|
||||
orderBy: {
|
||||
title: 'asc',
|
||||
},
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
content: {
|
||||
contains: 'rust',
|
||||
contains: 'javascript',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: {
|
||||
contains: 'rust',
|
||||
contains: 'javascript',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
date: true,
|
||||
url: true,
|
||||
desc: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(content);
|
||||
const count = await prisma.posts.count({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
content: {
|
||||
contains: 'javascript',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: {
|
||||
contains: 'javascript',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
console.log(count);
|
||||
}
|
||||
|
||||
main().then();
|
||||
|
36
yarn.lock
36
yarn.lock
@ -820,22 +820,22 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@prisma/client@^3.8.1":
|
||||
version "3.8.1"
|
||||
resolved "https://registry.npmmirror.com/@prisma/client/download/@prisma/client-3.8.1.tgz#c11eda8e84760867552ffde4de7b48fb2cf1e1c0"
|
||||
integrity sha512-NxD1Xbkx1eT1mxSwo1RwZe665mqBETs0VxohuwNfFIxMqcp0g6d4TgugPxwZ4Jb4e5wCu8mQ9quMedhNWIWcZQ==
|
||||
"@prisma/client@^3.9.1":
|
||||
version "3.9.1"
|
||||
resolved "https://registry.npmmirror.com/@prisma/client/-/client-3.9.1.tgz#565c8121f1220637bcab4a1d1f106b8c1334406c"
|
||||
integrity sha512-aLwfXKLvL+loQ0IuPPCXkcq8cXBg1IeoHHa5lqQu3dJHdj45wnislA/Ny4UxRQjD5FXqrfAb8sWtF+jhdmjFTg==
|
||||
dependencies:
|
||||
"@prisma/engines-version" "3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f"
|
||||
"@prisma/engines-version" "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009"
|
||||
|
||||
"@prisma/engines-version@3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f":
|
||||
version "3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f"
|
||||
resolved "https://registry.npmmirror.com/@prisma/engines-version/download/@prisma/engines-version-3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f.tgz#4c8d9744b5e54650a8ba5fde0a711399d6adba24"
|
||||
integrity sha512-G2JH6yWt6ixGKmsRmVgaQYahfwMopim0u/XLIZUo2o/mZ5jdu7+BL+2V5lZr7XiG1axhyrpvlyqE/c0OgYSl3g==
|
||||
"@prisma/engines-version@3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009":
|
||||
version "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009"
|
||||
resolved "https://registry.npmmirror.com/@prisma/engines-version/-/engines-version-3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009.tgz#ea03ffa723382a526dc6625ce6eae9b6ad984400"
|
||||
integrity sha512-5Dh+qTDhpPR66w6NNAnPs+/W/Qt4r1DSd+qhfPFcDThUK4uxoZKGlPb2IYQn5LL+18aIGnmteDf7BnVMmvBNSQ==
|
||||
|
||||
"@prisma/engines@3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f":
|
||||
version "3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f"
|
||||
resolved "https://registry.npmmirror.com/@prisma/engines/download/@prisma/engines-3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f.tgz#4479099b99f6a082ce5843ee7208943ccedd127f"
|
||||
integrity sha512-bHYubuItSN/DGYo36aDu7xJiJmK52JOSHs4MK+KbceAtwS20BCWadRgtpQ3iZ2EXfN/B1T0iCXlNraaNwnpU2w==
|
||||
"@prisma/engines@3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009":
|
||||
version "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009"
|
||||
resolved "https://registry.npmmirror.com/@prisma/engines/-/engines-3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009.tgz#e5c345cdedb7be83d11c1e0c5ab61d866b411256"
|
||||
integrity sha512-qM+uJbkelB21bnK44gYE049YTHIjHysOuj0mj5U2gDGyNLfmiazlggzFPCgEjgme4U5YB2tYs6Z5Hq08Kl8pjA==
|
||||
|
||||
"@rushstack/eslint-patch@^1.0.8":
|
||||
version "1.1.0"
|
||||
@ -5061,12 +5061,12 @@ pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.4.6:
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
prisma@^3.8.1:
|
||||
version "3.8.1"
|
||||
resolved "https://registry.npmmirror.com/prisma/download/prisma-3.8.1.tgz#44395cef7cbb1ea86216cb84ee02f856c08a7873"
|
||||
integrity sha512-Q8zHwS9m70TaD7qI8u+8hTAmiTpK+IpvRYF3Rgb/OeWGQJOMgZCFFvNCiSfoLEQ95wilK7ctW3KOpc9AuYnRUA==
|
||||
prisma@^3.9.1:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.npmmirror.com/prisma/-/prisma-3.9.1.tgz#7510a8bf06018a5313b9427b1127ce4750b1ce5c"
|
||||
integrity sha512-IGcJAu5LzlFv+i+NNhOEh1J1xVVttsVdRBxmrMN7eIH+7mRN6L89Hz1npUAiz4jOpNlHC7n9QwaOYZGxTqlwQw==
|
||||
dependencies:
|
||||
"@prisma/engines" "3.8.0-43.34df67547cf5598f5a6cd3eb45f14ee70c3fb86f"
|
||||
"@prisma/engines" "3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
|
Reference in New Issue
Block a user