Skip to content
This repository was archived by the owner on May 25, 2025. It is now read-only.

Commit e8c5149

Browse files
authored
feat: make patch throw when item is missing from DB (#26)
* feat: make patch throw when item is missing from DB * chore: apply comments * chore: remove `createIfMissing` from `patch`
1 parent aa4ec6d commit e8c5149

File tree

3 files changed

+85
-21
lines changed

3 files changed

+85
-21
lines changed

src/commondao/common.dao.model.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,18 +285,20 @@ export interface CommonDaoPatchByIdOptions<DBM extends BaseDBEntity>
285285
extends CommonDaoSaveBatchOptions<DBM> {
286286
/**
287287
* Defaults to false.
288-
* With false, if the row doesn't exist - it will be auto-created with `dao.create`.
289-
* With true, if the row doesn't exist - it will throw an error.
288+
* With false, if the row doesn't exist - it will throw an error.
289+
* With true, if the row doesn't exist - it will be auto-created with `dao.create`.
290290
*
291291
* Use true when you expect the row to exist and it would be an error if it doesn't.
292292
*/
293-
requireToExist?: boolean
293+
createIfMissing?: boolean
294294
}
295295

296296
export interface CommonDaoPatchOptions<DBM extends BaseDBEntity>
297297
extends CommonDaoSaveBatchOptions<DBM> {
298298
/**
299299
* If true - patch will skip loading from DB, and will just optimistically patch passed object.
300+
*
301+
* Consequently, when the row doesn't exist - it will be auto-created with `dao.create`.
300302
*/
301303
skipDBRead?: boolean
302304
}

src/commondao/common.dao.test.ts

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ test('should propagate pipe errors', async () => {
156156

157157
test('patchById', async () => {
158158
const id = '123456'
159+
const testItem: TestItemBM = {
160+
id,
161+
k1: 'k1',
162+
created: 1529539200 as UnixTimestamp,
163+
updated: 1529539200 as UnixTimestamp,
164+
}
165+
await dao.save(testItem)
166+
159167
const r = await dao.patchById(id, {
160168
k1: 'k111',
161169
})
@@ -173,7 +181,7 @@ test('patchById', async () => {
173181
`)
174182
})
175183

176-
test('patchById requireToExist', async () => {
184+
test('patchById createIfMissing false', async () => {
177185
const id = '123456'
178186
expect(
179187
await pExpectedErrorString(
@@ -183,11 +191,69 @@ test('patchById requireToExist', async () => {
183191
k1: 'k111',
184192
},
185193
{
186-
requireToExist: true,
194+
createIfMissing: false,
187195
},
188196
),
189197
),
190-
).toMatchInlineSnapshot(`"AssertionError: TEST_TABLE.patchById row is required, but missing"`)
198+
).toMatchInlineSnapshot(`"AssertionError: DB row required, but not found in TEST_TABLE"`)
199+
})
200+
201+
describe('patch', () => {
202+
test('should patch when the data exists', async () => {
203+
const testItem: TestItemBM = {
204+
id: 'id1',
205+
k1: 'k1',
206+
created: 1529539200 as UnixTimestamp,
207+
updated: 1529539200 as UnixTimestamp,
208+
}
209+
await dao.save(testItem)
210+
211+
await dao.patch(testItem, {
212+
k1: 'k111',
213+
})
214+
215+
const updatedTestItem = await dao.requireById('id1')
216+
expect(updatedTestItem).toMatchObject({ k1: 'k111' })
217+
})
218+
219+
test('should throw when the data does not exist', async () => {
220+
const testItem: TestItemBM = {
221+
id: 'id1',
222+
k1: 'k1',
223+
created: 1529539200 as UnixTimestamp,
224+
updated: 1529539200 as UnixTimestamp,
225+
}
226+
227+
const error = await pExpectedErrorString(
228+
dao.patch(testItem, {
229+
k1: 'k111',
230+
}),
231+
)
232+
233+
expect(error).toBe(`AppError: DB row required, but not found in TEST_TABLE`)
234+
})
235+
236+
test('should create the data when it does not exist and `skipDBRead` is specified', async () => {
237+
const testItem: TestItemBM = {
238+
id: 'id1',
239+
k1: 'k1',
240+
created: 1529539200 as UnixTimestamp,
241+
updated: 1529539200 as UnixTimestamp,
242+
}
243+
244+
await dao.patch(
245+
testItem,
246+
{
247+
k1: 'k111',
248+
},
249+
{
250+
skipDBRead: true,
251+
},
252+
)
253+
254+
const updatedTestItem = await dao.requireById('id1')
255+
expect(updatedTestItem).toMatchObject({ k1: 'k111' })
256+
})
191257
})
192258

193259
test('patch', async () => {

src/commondao/common.dao.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
679679
}
680680
} else {
681681
const table = opt.table || this.cfg.table
682-
_assert(!opt.requireToExist, `${table}.patchById row is required, but missing`, {
682+
_assert(opt.createIfMissing, `DB row required, but not found in ${table}`, {
683683
id,
684684
table,
685685
})
@@ -728,28 +728,24 @@ export class CommonDao<BM extends BaseDBEntity, DBM extends BaseDBEntity = BM, I
728728
}
729729
Object.assign(bm, patch)
730730
} else {
731-
const loaded = await this.getById(bm.id as ID, {
731+
const loaded = await this.requireById(bm.id as ID, {
732732
// Skipping validation here for performance reasons.
733733
// Validation is going to happen on save anyway, just down below.
734734
skipValidation: true,
735735
...opt,
736736
})
737737

738-
if (loaded) {
739-
const loadedWithPatch: BM = {
740-
...loaded,
741-
...patch,
742-
}
738+
const loadedWithPatch: BM = {
739+
...loaded,
740+
...patch,
741+
}
743742

744-
// Make `bm` exactly the same as `loadedWithPatch`
745-
_objectAssignExact(bm, loadedWithPatch)
743+
// Make `bm` exactly the same as `loadedWithPatch`
744+
_objectAssignExact(bm, loadedWithPatch)
746745

747-
if (_deepJsonEquals(loaded, loadedWithPatch)) {
748-
// Skipping the save operation, as data is the same
749-
return bm
750-
}
751-
} else {
752-
Object.assign(bm, patch)
746+
if (_deepJsonEquals(loaded, loadedWithPatch)) {
747+
// Skipping the save operation, as data is the same
748+
return bm
753749
}
754750
}
755751

0 commit comments

Comments
 (0)