Skip to content

Commit b985487

Browse files
committed
feat: add object support
1 parent dfc99f0 commit b985487

File tree

5 files changed

+155
-54
lines changed

5 files changed

+155
-54
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ Create a `db.json` (or `db.json5`) file
2424
"comments": [
2525
{ "id": "1", "text": "a comment about post 1", "postId": "1" },
2626
{ "id": "2", "text": "another comment about post 1", "postId": "1" }
27-
]
27+
],
28+
"profile": {
29+
"name": "typicode"
30+
}
2831
}
2932
```
3033

@@ -64,6 +67,12 @@ PATCH /posts/:id
6467
DELETE /posts/:id
6568
```
6669

70+
```
71+
GET /profile
72+
PUT /profile
73+
PATCH /profile
74+
```
75+
6776
## Params
6877

6978
### Conditions

src/app.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const db = new Low<Data>(new Memory<Data>(), {})
3838
db.data = {
3939
posts: [{ id: '1', title: 'foo' }],
4040
comments: [{ id: '1', postId: '1' }],
41+
object: { f1: 'foo' },
4142
}
4243
const app = createApp(db, { static: [tmpDir] })
4344

@@ -58,6 +59,8 @@ await test('createApp', async (t) => {
5859
const COMMENTS = '/comments'
5960
const POST_COMMENTS = '/comments?postId=1'
6061
const NOT_FOUND = '/not-found'
62+
const OBJECT = '/object'
63+
const OBJECT_1 = '/object/1'
6164

6265
const arr: Test[] = [
6366
// Static
@@ -74,25 +77,35 @@ await test('createApp', async (t) => {
7477
{ method: 'GET', url: POST_NOT_FOUND, statusCode: 404 },
7578
{ method: 'GET', url: COMMENTS, statusCode: 200 },
7679
{ method: 'GET', url: POST_COMMENTS, statusCode: 200 },
80+
{ method: 'GET', url: OBJECT, statusCode: 200 },
81+
{ method: 'GET', url: OBJECT_1, statusCode: 404 },
7782
{ method: 'GET', url: NOT_FOUND, statusCode: 404 },
7883

7984
{ method: 'POST', url: POSTS, statusCode: 201 },
8085
{ method: 'POST', url: POST_1, statusCode: 404 },
8186
{ method: 'POST', url: POST_NOT_FOUND, statusCode: 404 },
87+
{ method: 'POST', url: OBJECT, statusCode: 404 },
88+
{ method: 'POST', url: OBJECT_1, statusCode: 404 },
8289
{ method: 'POST', url: NOT_FOUND, statusCode: 404 },
8390

8491
{ method: 'PUT', url: POSTS, statusCode: 404 },
8592
{ method: 'PUT', url: POST_1, statusCode: 200 },
93+
{ method: 'PUT', url: OBJECT, statusCode: 200 },
94+
{ method: 'PUT', url: OBJECT_1, statusCode: 404 },
8695
{ method: 'PUT', url: POST_NOT_FOUND, statusCode: 404 },
8796
{ method: 'PUT', url: NOT_FOUND, statusCode: 404 },
8897

8998
{ method: 'PATCH', url: POSTS, statusCode: 404 },
9099
{ method: 'PATCH', url: POST_1, statusCode: 200 },
100+
{ method: 'PATCH', url: OBJECT, statusCode: 200 },
101+
{ method: 'PATCH', url: OBJECT_1, statusCode: 404 },
91102
{ method: 'PATCH', url: POST_NOT_FOUND, statusCode: 404 },
92103
{ method: 'PATCH', url: NOT_FOUND, statusCode: 404 },
93104

94105
{ method: 'DELETE', url: POSTS, statusCode: 404 },
95106
{ method: 'DELETE', url: POST_1, statusCode: 200 },
107+
{ method: 'DELETE', url: OBJECT, statusCode: 404 },
108+
{ method: 'DELETE', url: OBJECT_1, statusCode: 404 },
96109
{ method: 'DELETE', url: POST_NOT_FOUND, statusCode: 404 },
97110
{ method: 'DELETE', url: NOT_FOUND, statusCode: 404 },
98111
]

src/app.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,41 @@ export function createApp(db: Low<Data>, options: AppOptions = {}) {
6666
next()
6767
})
6868

69+
app.put('/:name', async (req, res, next) => {
70+
const { name = '' } = req.params
71+
if (isItem(req.body)) {
72+
res.locals['data'] = await service.update(name, req.body)
73+
}
74+
next()
75+
})
76+
6977
app.put('/:name/:id', async (req, res, next) => {
7078
const { name = '', id = '' } = req.params
7179
if (isItem(req.body)) {
72-
res.locals['data'] = await service.update(name, id, req.body)
80+
res.locals['data'] = await service.updateById(name, id, req.body)
81+
}
82+
next()
83+
})
84+
85+
app.patch('/:name', async (req, res, next) => {
86+
const { name = '' } = req.params
87+
if (isItem(req.body)) {
88+
res.locals['data'] = await service.patch(name, req.body)
7389
}
7490
next()
7591
})
7692

7793
app.patch('/:name/:id', async (req, res, next) => {
7894
const { name = '', id = '' } = req.params
7995
if (isItem(req.body)) {
80-
res.locals['data'] = await service.patch(name, id, req.body)
96+
res.locals['data'] = await service.patchById(name, id, req.body)
8197
}
8298
next()
8399
})
84100

85101
app.delete('/:name/:id', async (req, res, next) => {
86102
const { name = '', id = '' } = req.params
87-
res.locals['data'] = await service.destroy(name, id)
103+
res.locals['data'] = await service.destroyById(name, id)
88104
next()
89105
})
90106

src/service.test.ts

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const service = new Service(db)
1313

1414
const POSTS = 'posts'
1515
const COMMENTS = 'comments'
16+
const OBJECT = 'object'
17+
1618
const UNKNOWN_RESOURCE = 'xxx'
1719
const UNKNOWN_ID = 'xxx'
1820

@@ -40,10 +42,15 @@ const post3 = {
4042
const comment1 = { id: '1', title: 'a', postId: '1' }
4143
const items = 3
4244

45+
const obj = {
46+
f1: 'foo',
47+
}
48+
4349
function reset() {
4450
db.data = structuredClone({
4551
posts: [post1, post2, post3],
4652
comments: [comment1],
53+
object: obj,
4754
})
4855
}
4956

@@ -57,6 +64,8 @@ type Test = {
5764

5865
await test('findById', () => {
5966
reset()
67+
if (!Array.isArray(db.data?.[POSTS]))
68+
throw new Error('posts should be an array')
6069
assert.deepEqual(service.findById(POSTS, '1', {}), db.data?.[POSTS]?.[0])
6170
assert.equal(service.findById(POSTS, UNKNOWN_ID, {}), undefined)
6271
assert.deepEqual(service.findById(POSTS, '1', { _embed: ['comments'] }), {
@@ -236,6 +245,10 @@ await test('find', async (t) => {
236245
name: UNKNOWN_RESOURCE,
237246
res: undefined,
238247
},
248+
{
249+
name: OBJECT,
250+
res: obj,
251+
},
239252
]
240253
for (const tc of arr) {
241254
await t.test(`${tc.name} ${JSON.stringify(tc.params)}`, () => {
@@ -261,44 +274,65 @@ await test('create', async () => {
261274
})
262275

263276
await test('update', async () => {
277+
reset()
278+
const obj = { f1: 'bar' }
279+
const res = await service.update(OBJECT, obj)
280+
assert.equal(res, obj)
281+
282+
assert.equal(
283+
await service.update(UNKNOWN_RESOURCE, obj),
284+
undefined,
285+
'should ignore unknown resources',
286+
)
287+
assert.equal(
288+
await service.update(POSTS, {}),
289+
undefined,
290+
'should ignore arrays',
291+
)
292+
})
293+
294+
await test('updateById', async () => {
264295
reset()
265296
const post = { id: 'xxx', title: 'updated post' }
266-
const res = await service.update(POSTS, post1.id, post)
297+
const res = await service.updateById(POSTS, post1.id, post)
267298
assert.equal(res?.['id'], post1.id, 'id should not change')
268299
assert.equal(res?.['title'], post.title)
269300

270301
assert.equal(
271-
await service.update(UNKNOWN_RESOURCE, post1.id, post),
302+
await service.updateById(UNKNOWN_RESOURCE, post1.id, post),
272303
undefined,
273304
)
274-
assert.equal(await service.update(POSTS, UNKNOWN_ID, post), undefined)
305+
assert.equal(await service.updateById(POSTS, UNKNOWN_ID, post), undefined)
275306
})
276307

277-
await test('patch', async () => {
308+
await test('patchById', async () => {
278309
reset()
279310
const post = { id: 'xxx', title: 'updated post' }
280-
const res = await service.patch(POSTS, post1.id, post)
311+
const res = await service.patchById(POSTS, post1.id, post)
281312
assert.notEqual(res, undefined)
282313
assert.equal(res?.['id'], post1.id)
283314
assert.equal(res?.['title'], post.title)
284315

285-
assert.equal(await service.patch(UNKNOWN_RESOURCE, post1.id, post), undefined)
286-
assert.equal(await service.patch(POSTS, UNKNOWN_ID, post), undefined)
316+
assert.equal(
317+
await service.patchById(UNKNOWN_RESOURCE, post1.id, post),
318+
undefined,
319+
)
320+
assert.equal(await service.patchById(POSTS, UNKNOWN_ID, post), undefined)
287321
})
288322

289323
await test('destroy', async () => {
290324
reset()
291-
let prevLength = db.data?.[POSTS]?.length || 0
292-
await service.destroy(POSTS, post1.id)
325+
let prevLength = Number(db.data?.[POSTS]?.length) || 0
326+
await service.destroyById(POSTS, post1.id)
293327
assert.equal(db.data?.[POSTS]?.length, prevLength - 1)
294328
assert.deepEqual(db.data?.[COMMENTS], [{ ...comment1, postId: null }])
295329

296330
reset()
297331
prevLength = db.data?.[POSTS]?.length || 0
298-
await service.destroy(POSTS, post1.id, [COMMENTS])
332+
await service.destroyById(POSTS, post1.id, [COMMENTS])
299333
assert.equal(db.data[POSTS].length, prevLength - 1)
300334
assert.equal(db.data[COMMENTS].length, 0)
301335

302-
assert.equal(await service.destroy(UNKNOWN_RESOURCE, post1.id), undefined)
303-
assert.equal(await service.destroy(POSTS, UNKNOWN_ID), undefined)
336+
assert.equal(await service.destroyById(UNKNOWN_RESOURCE, post1.id), undefined)
337+
assert.equal(await service.destroyById(POSTS, UNKNOWN_ID), undefined)
304338
})

0 commit comments

Comments
 (0)