Skip to content

Commit 231853e

Browse files
committed
feat: support _is_null and _is_not_null operators
1 parent 3a259d1 commit 231853e

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

README.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ __Please help me build OSS__ 👉 [GitHub Sponsors](https://github.com/sponsors/
105105

106106
## Getting started
107107

108-
Install JSON Server
108+
Install JSON Server
109109

110110
```
111111
npm install -g json-server
@@ -142,7 +142,7 @@ Also when doing requests, it's good to know that:
142142
- If you make POST, PUT, PATCH or DELETE requests, changes will be automatically and safely saved to `db.json` using [lowdb](https://github.com/typicode/lowdb).
143143
- Your request body JSON should be object enclosed, just like the GET output. (for example `{"name": "Foobar"}`)
144144
- Id values are not mutable. Any `id` value in the body of your PUT or PATCH request will be ignored. Only a value set in a POST request will be respected, but only if not already taken.
145-
- A POST, PUT or PATCH request should include a `Content-Type: application/json` header to use the JSON in the request body. Otherwise it will return a 2XX status code, but without changes being made to the data.
145+
- A POST, PUT or PATCH request should include a `Content-Type: application/json` header to use the JSON in the request body. Otherwise it will return a 2XX status code, but without changes being made to the data.
146146

147147
## Routes
148148

@@ -239,6 +239,18 @@ Add `_like` to filter (RegExp supported)
239239
GET /posts?title_like=server
240240
```
241241

242+
Add `_is_null` for getting a null value
243+
244+
```
245+
GET /todos?completeDate_is_null
246+
```
247+
248+
Add `_is_not_null` for getting a non-null value
249+
250+
```
251+
GET /todos?completeDate_is_not_null
252+
```
253+
242254
### Full-text search
243255

244256
Add `q`

__tests__/server/plural.js

+23
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ describe('Server', () => {
4242
{ id: 5, body: 'quux', published: false, postId: 2, userId: 1 },
4343
]
4444

45+
db.todos = [
46+
{ id: 1, completeDate: null },
47+
{ id: 2, completeDate: null },
48+
{ id: 3, completeDate: '2022-11-20T13:02:47.210Z' },
49+
{ id: 4, completeDate: '2023-12-05T17:58:17.420Z' },
50+
]
51+
4552
db.buyers = [
4653
{ id: 1, name: 'Aileen', country: 'Colombia', total: 100 },
4754
{ id: 2, name: 'Barney', country: 'Colombia', total: 200 },
@@ -305,6 +312,22 @@ describe('Server', () => {
305312
})
306313
})
307314

315+
describe('GET /:resource?attr_is_null', () => {
316+
test('should respond with null value array', () =>
317+
request(server)
318+
.get('/todos?completeDate_is_null')
319+
.expect('Content-Type', /json/)
320+
.expect(200, db.todos.slice(0, 2)))
321+
})
322+
323+
describe('GET /:resource?attr_is_not_null', () => {
324+
test('should respond with non-null value array', () =>
325+
request(server)
326+
.get('/todos?completeDate_is_not_null')
327+
.expect('Content-Type', /json/)
328+
.expect(200, db.todos.slice(2)))
329+
})
330+
308331
describe('GET /:resource?attr_gte=&attr_lte=', () => {
309332
test('should respond with a limited array', () =>
310333
request(server)

src/server/router/plural.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ module.exports = (db, name, opts) => {
8181
_.has(arr[i], query) ||
8282
query === 'callback' ||
8383
query === '_' ||
84+
/_is_null$/.test(query) ||
85+
/_is_not_null$/.test(query) ||
8486
/_lte$/.test(query) ||
8587
/_gte$/.test(query) ||
8688
/_ne$/.test(query) ||
@@ -117,22 +119,30 @@ module.exports = (db, name, opts) => {
117119
// Always use an array, in case req.query is an array
118120
const arr = [].concat(req.query[key])
119121

122+
const isNull = /_is_null$/.test(key)
123+
const isNotNull = /_is_not_null$/.test(key)
120124
const isDifferent = /_ne$/.test(key)
121125
const isRange = /_lte$/.test(key) || /_gte$/.test(key)
122126
const isLike = /_like$/.test(key)
123-
const path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
127+
const path = key.replace(
128+
/(_is_null|_is_not_null|_lte|_gte|_ne|_like)$/,
129+
'',
130+
)
124131

125132
chain = chain.filter((element) => {
126133
return arr
127-
.map(function (value) {
134+
.map((value) => {
128135
// get item value based on path
129136
// i.e post.title -> 'foo'
130137
const elementValue = _.get(element, path)
138+
const isElementValueNull =
139+
typeof elementValue === 'undefined' || elementValue === null
140+
141+
if (isNull) return isElementValueNull
142+
if (isNotNull) return !isElementValueNull
131143

132144
// Prevent toString() failing on undefined or null values
133-
if (elementValue === undefined || elementValue === null) {
134-
return undefined
135-
}
145+
if (isElementValueNull) return undefined
136146

137147
if (isRange) {
138148
const isLowerThan = /_gte$/.test(key)

0 commit comments

Comments
 (0)