mirror of
https://github.com/typicode/json-server.git
synced 2026-03-13 09:35:37 +08:00
Add contains, startsWith, endsWith string query operators (#1714)
* Initial plan * Add contains, startsWith, endsWith query operators for partial string matching Co-authored-by: typicode <5502029+typicode@users.noreply.github.com> * Delete package-lock.json * docs: document contains, startsWith, endsWith operators in README Co-authored-by: typicode <5502029+typicode@users.noreply.github.com> * test: add numeric-value tests for contains, startsWith, endsWith operators Co-authored-by: typicode <5502029+typicode@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: typicode <5502029+typicode@users.noreply.github.com> Co-authored-by: typicode <typicode@gmail.com>
This commit is contained in:
@@ -167,6 +167,9 @@ Operators:
|
||||
- `gt` greater than, `gte` greater than or equal
|
||||
- `eq` equal, `ne` not equal
|
||||
- `in` included in comma-separated list
|
||||
- `contains` string contains (case-insensitive)
|
||||
- `startsWith` string starts with (case-insensitive)
|
||||
- `endsWith` string ends with (case-insensitive)
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -175,6 +178,9 @@ GET /posts?views:gt=100
|
||||
GET /posts?title:eq=Hello
|
||||
GET /posts?id:in=1,2,3
|
||||
GET /posts?author.name:eq=typicode
|
||||
GET /posts?title:contains=hello
|
||||
GET /posts?title:startsWith=Hello
|
||||
GET /posts?title:endsWith=world
|
||||
```
|
||||
|
||||
### Sort
|
||||
|
||||
@@ -35,6 +35,24 @@ await test('matchesWhere', async (t) => {
|
||||
[{ a: { foo: 10 } }, true],
|
||||
[{ a: { foo: 10, eq: 10 } }, true],
|
||||
[{ missing: { foo: 1 } }, true],
|
||||
// contains
|
||||
[{ c: { contains: 'x' } }, true],
|
||||
[{ c: { contains: 'X' } }, true],
|
||||
[{ c: { contains: 'z' } }, false],
|
||||
[{ a: { contains: '1' } }, false],
|
||||
[{ c: { contains: 1 } }, false],
|
||||
// startsWith
|
||||
[{ c: { startsWith: 'x' } }, true],
|
||||
[{ c: { startsWith: 'X' } }, true],
|
||||
[{ c: { startsWith: 'z' } }, false],
|
||||
[{ a: { startsWith: '1' } }, false],
|
||||
[{ c: { startsWith: 1 } }, false],
|
||||
// endsWith
|
||||
[{ c: { endsWith: 'x' } }, true],
|
||||
[{ c: { endsWith: 'X' } }, true],
|
||||
[{ c: { endsWith: 'z' } }, false],
|
||||
[{ a: { endsWith: '1' } }, false],
|
||||
[{ c: { endsWith: 1 } }, false],
|
||||
]
|
||||
|
||||
for (const [query, expected] of cases) {
|
||||
|
||||
@@ -57,6 +57,18 @@ export function matchesWhere(obj: JsonObject, where: JsonObject): boolean {
|
||||
const inValues = Array.isArray(op.in) ? op.in : [op.in]
|
||||
if (!inValues.some((v) => (field as any) === (v as any))) return false
|
||||
}
|
||||
if (knownOps.includes('contains')) {
|
||||
if (typeof field !== 'string') return false
|
||||
if (!field.toLowerCase().includes(String(op.contains).toLowerCase())) return false
|
||||
}
|
||||
if (knownOps.includes('startsWith')) {
|
||||
if (typeof field !== 'string') return false
|
||||
if (!field.toLowerCase().startsWith(String(op.startsWith).toLowerCase())) return false
|
||||
}
|
||||
if (knownOps.includes('endsWith')) {
|
||||
if (typeof field !== 'string') return false
|
||||
if (!field.toLowerCase().endsWith(String(op.endsWith).toLowerCase())) return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,24 @@ await test('parseWhere', async (t) => {
|
||||
title: { in: ['hello', 'world'] },
|
||||
},
|
||||
],
|
||||
[
|
||||
'title:contains=ello',
|
||||
{
|
||||
title: { contains: 'ello' },
|
||||
},
|
||||
],
|
||||
[
|
||||
'title:startsWith=hel',
|
||||
{
|
||||
title: { startsWith: 'hel' },
|
||||
},
|
||||
],
|
||||
[
|
||||
'title:endsWith=rld',
|
||||
{
|
||||
title: { endsWith: 'rld' },
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
for (const [query, expected] of cases) {
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
export const WHERE_OPERATORS = ['lt', 'lte', 'gt', 'gte', 'eq', 'ne', 'in'] as const
|
||||
export const WHERE_OPERATORS = [
|
||||
'lt',
|
||||
'lte',
|
||||
'gt',
|
||||
'gte',
|
||||
'eq',
|
||||
'ne',
|
||||
'in',
|
||||
'contains',
|
||||
'startsWith',
|
||||
'endsWith',
|
||||
] as const
|
||||
|
||||
export type WhereOperator = (typeof WHERE_OPERATORS)[number]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user