Skip to content

Commit f4d9c89

Browse files
committed
handle search filtering with underscore
1 parent 17a979d commit f4d9c89

File tree

5 files changed

+42
-57
lines changed

5 files changed

+42
-57
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ https://user-images.githubusercontent.com/9990165/177367837-a2692e5d-b694-454e-8
5656
<img width="150px" src="docs/readme-assets/mobile-screens/Screenshot15.png">
5757
</p>
5858

59-
## How you can use this
59+
## Usage
6060

61-
- build your own projects on top of this (blog, social network, e-commerce, Saas...), suitable for any small to medium size web app that can run in a single Linux box, not every start up has billion users from first day
61+
- build your own projects on top of this (blog, social network, e-commerce, SaaS...), suitable for any small to medium size web app that can run in a single Linux box, not every start up has billion users from first day
6262
- if you want to go serverless route you can still reuse a lot of code and implementation decisions from this project, few notes: 1. you need to remove custom http server and let Next.js app run natively, 2. you can't run production app in a single Docker container, 3. you must use different Multer storage type for uploads
6363
- reuse any specific design decision, feature or configuration (i.e. VS Code devcontainer can be reused for any Node.js project, theming plugin, email/password login with `next-auth`, etc...)
6464
- use it for learning or as a collection of working examples for reference
@@ -665,7 +665,7 @@ Here is the brief overview of what you can find in it:
665665
- [Github Actions](docs/github-actions.md) - building Docker container, running tests, handling environment variables, handling `NODE_ENV` and `APP_ENV` variables, VPS deployment using SSH action
666666
- [Traefik](docs/traefik.md) - setting up live production environment based on Docker, renewing Let's Encrypt certificate
667667
- [VS Code](docs/vs-code.md) - ESLint and Prettier setup, running Jest tests, devcontainers setup
668-
- [todo](docs/todo.md) - my personal simple task tracker
668+
- [todo](docs/todo.md) - my simple personal task tracker
669669

670670
## Contributing
671671

docs/prisma.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,9 @@ import { User } from '.prisma/client';
6060
- [docs](https://www.prisma.io/docs/guides/upgrade-guides/upgrading-versions/upgrading-to-prisma-4#breaking-changes)
6161
- validate schema `npx prisma validate`
6262
- nothing changed, all works
63+
64+
### Full text search with Postgres
65+
66+
- `_` matches space literally, I need that and not `&` to match phrase with space `cat dog`
67+
- `cat & dog` matches those two words **anywhere in same content**, in any order, `cat some text dog`
68+
- Github [issue](https://github.com/prisma/prisma/issues/8939)

lib-server/services/posts.ts

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
PostWithAuthor,
88
} from 'types/models/Post';
99
import { PaginatedResponse, SortDirection } from 'types';
10+
import { filterSearchTerm } from 'utils';
1011

1112
// -------- pages/api/posts/[id].ts
1213

@@ -121,51 +122,22 @@ export const getPosts = async (
121122
} = postsGetData;
122123

123124
const byAuthor = userId || email || username;
125+
const search = filterSearchTerm(searchTerm);
124126

125127
const where = {
126128
where: {
127129
published,
128130
...(byAuthor && {
129131
author: {
130-
OR: [
131-
{
132-
id: userId,
133-
},
134-
{
135-
email,
136-
},
137-
{
138-
username,
139-
},
140-
],
132+
OR: [{ id: userId }, { email }, { username }],
141133
},
142134
}),
143-
...(searchTerm && {
135+
...(search && {
144136
OR: [
145-
{
146-
title: {
147-
search: searchTerm,
148-
},
149-
},
150-
{
151-
content: {
152-
search: searchTerm,
153-
},
154-
},
155-
{
156-
author: {
157-
username: {
158-
search: searchTerm,
159-
},
160-
},
161-
},
162-
{
163-
author: {
164-
name: {
165-
search: searchTerm,
166-
},
167-
},
168-
},
137+
{ title: { search } },
138+
{ content: { search } },
139+
{ author: { username: { search } } },
140+
{ author: { name: { search } } },
169141
],
170142
}),
171143
},

lib-server/services/users.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
UsersGetData,
1111
UserUpdateServiceData,
1212
} from 'types/models/User';
13+
import { filterSearchTerm } from 'utils';
1314

1415
/**
1516
*
@@ -133,26 +134,12 @@ export const getUsers = async (
133134
sortDirection = 'desc',
134135
} = usersGetData;
135136

137+
const search = filterSearchTerm(searchTerm, 'or');
138+
136139
const where = {
137140
where: {
138-
...(searchTerm && {
139-
OR: [
140-
{
141-
name: {
142-
search: searchTerm,
143-
},
144-
},
145-
{
146-
username: {
147-
search: searchTerm,
148-
},
149-
},
150-
{
151-
email: {
152-
search: searchTerm,
153-
},
154-
},
155-
],
141+
...(search && {
142+
OR: [{ name: { search } }, { username: { search } }, { email: { search } }],
156143
}),
157144
},
158145
};

utils/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,23 @@ export const isGithubActionsAppEnv = (): boolean => {
3838
* Note: this might give wrong path in tests
3939
*/
4040
export const rootDirAbsolutePath = process.cwd();
41+
42+
/**
43+
* filter special chars and replace spaces with '_'
44+
*/
45+
export const filterSearchTerm = (
46+
searchTerm: string | undefined,
47+
operator: 'space' | 'or' = 'space'
48+
): string | undefined => {
49+
// 'cat_dog' matches 'cat dog'
50+
const joinBy = operator === 'space' ? '_' : ' | ';
51+
52+
return (
53+
searchTerm &&
54+
searchTerm
55+
.trim()
56+
.replace(/[^a-z0-9\s]+/gi, '') // remove special chars
57+
.split(/\s+/)
58+
.join(joinBy)
59+
);
60+
};

0 commit comments

Comments
 (0)