Add search API

* update prisma
* Add search API in page
* add API with fetch
* Update search with global state
This commit is contained in:
DefectingCat
2022-02-08 17:57:08 +08:00
parent 89f290218b
commit 5e1f58a144
8 changed files with 188 additions and 57 deletions

23
lib/API/index.ts Normal file
View 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
View 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
View 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;

View File

@ -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"
}

View File

@ -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) {

View File

@ -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>
</>
);
};

View File

@ -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();

View File

@ -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"