Skip to content

Commit 8b5b312

Browse files
authored
Merge pull request #207 from AthennaIO/develop
chore(model): adjust dirty for JSONB fields
2 parents da8f7ff + f1fbe43 commit 8b5b312

File tree

14 files changed

+183
-217
lines changed

14 files changed

+183
-217
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@athenna/database",
3-
"version": "5.27.0",
3+
"version": "5.28.0",
44
"description": "The Athenna database handler for SQL/NoSQL.",
55
"license": "MIT",
66
"author": "João Lenon <lenon@athenna.io>",

src/constants/OriginalSymbol.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @athenna/database
3+
*
4+
* (c) João Lenon <lenon@athenna.io>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
/**
11+
* Symbol used to store the original value of a model.
12+
*/
13+
export const ORIGINAL_SYMBOL: unique symbol = Symbol('BaseModel.original')

src/models/BaseModel.ts

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
*/
99

1010
import {
11-
Collection,
1211
Is,
1312
Json,
14-
Options,
1513
String,
14+
Options,
15+
Collection,
1616
type PaginatedResponse,
1717
type PaginationOptions
1818
} from '@athenna/common'
@@ -21,6 +21,7 @@ import { Database } from '#src/facades/Database'
2121
import type { ModelRelations } from '#src/types'
2222
import { faker, type Faker } from '@faker-js/faker'
2323
import { ModelSchema } from '#src/models/schemas/ModelSchema'
24+
import { ORIGINAL_SYMBOL } from '#src/constants/OriginalSymbol'
2425
import { ModelFactory } from '#src/models/factories/ModelFactory'
2526
import { ModelGenerator } from '#src/models/factories/ModelGenerator'
2627
import { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'
@@ -435,31 +436,27 @@ export class BaseModel {
435436
* is a fresh instance and is not available in database
436437
* yet.
437438
*/
438-
private original?: Record<string, any>
439+
private [ORIGINAL_SYMBOL]?: Record<string, any>
439440

440441
/**
441442
* Set the original model values by deep copying
442443
* the model state.
443444
*/
444445
public setOriginal() {
445-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
446-
// @ts-ignore
447-
this.original = {}
446+
this[ORIGINAL_SYMBOL] = {}
448447

449-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
450-
// @ts-ignore
451-
Object.keys(Json.copy(Json.omit(this, ['original']))).forEach(key => {
448+
Object.keys(Json.copy(this)).forEach(key => {
452449
const value = this[key]
453450

454-
if (Is.Array(value) && value[0]?.original) {
451+
if (Is.Array(value) && value[0] && ORIGINAL_SYMBOL in value[0]) {
455452
return
456453
}
457454

458-
if (value && value.original) {
455+
if (Is.Object(value) && value && ORIGINAL_SYMBOL in value) {
459456
return
460457
}
461458

462-
this.original[key] = value
459+
this[ORIGINAL_SYMBOL][key] = value
463460
})
464461

465462
return this
@@ -482,10 +479,6 @@ export class BaseModel {
482479
* Execute the toJSON of relations.
483480
*/
484481
Object.keys(this).forEach(key => {
485-
if (key === 'original') {
486-
return
487-
}
488-
489482
if (relations.includes(key)) {
490483
if (Is.Array(this[key])) {
491484
json[key] = this[key].map(d => (d.toJSON ? d.toJSON() : d))
@@ -553,12 +546,12 @@ export class BaseModel {
553546
* or if it's a fresh instance.
554547
*/
555548
public isPersisted(): boolean {
556-
return !!this.original
549+
return !!this[ORIGINAL_SYMBOL]
557550
}
558551

559552
/**
560553
* Get values only that are different from
561-
* the original property to avoid updating
554+
* the original symbol to avoid updating
562555
* data that was not changed.
563556
*/
564557
public dirty() {
@@ -569,33 +562,20 @@ export class BaseModel {
569562
const dirty: Record<string, any> = {}
570563

571564
Object.keys(this).forEach(key => {
572-
if (key === 'original') {
573-
return
574-
}
575-
576-
const delta = Json.diff(this.original[key], this[key])
577-
578-
if (Is.Object(delta)) {
579-
if (!Object.keys(delta).length) {
580-
return
581-
}
582-
583-
dirty[key] = delta
565+
const orig = this[ORIGINAL_SYMBOL][key]
566+
const curr = this[key]
584567

568+
if (Json.isEqual(orig, curr)) {
585569
return
586570
}
587571

588-
if (Is.Array(delta)) {
589-
if (!delta.length) {
590-
return
591-
}
592-
593-
dirty[key] = delta
572+
if (Is.Object(curr) || Is.Array(curr)) {
573+
dirty[key] = Json.copy(curr)
594574

595575
return
596576
}
597577

598-
dirty[key] = delta
578+
dirty[key] = Json.diff(orig, curr)
599579
})
600580

601581
return dirty
@@ -655,7 +635,7 @@ export class BaseModel {
655635

656636
/**
657637
* Means data is not dirty because there are any
658-
* value that is different from original prop.
638+
* value that is different from original symbol.
659639
*/
660640
if (!Object.keys(data).length) {
661641
return this

templates/crud-service-test.edge

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default class {{ crudNamePascal }}ServiceTest {
4141
{{{ createBody }}}
4242
})
4343

44-
assert.containsSubset(data.toJSON(), {{ crudNameLower }}.toJSON())
44+
assert.containSubset(data.toJSON(), {{ crudNameLower }}.toJSON())
4545
}
4646

4747
@Test()
@@ -77,7 +77,7 @@ export default class {{ crudNamePascal }}ServiceTest {
7777
{{{ updateBody }}}
7878
})
7979

80-
assert.containsSubset(data.toJSON(), {
80+
assert.containSubset(data.toJSON(), {
8181
{{{ updateBody }}}
8282
})
8383
}

tests/unit/drivers/MongoDriverTest.ts

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ export default class MongoDriverTest {
565565

566566
const result = await this.driver.table('users').findOrFail()
567567

568-
assert.containsSubset(result, data)
568+
assert.containSubset(result, data)
569569
}
570570

571571
@Test()
@@ -582,7 +582,7 @@ export default class MongoDriverTest {
582582
return { _id: '1', name: 'Marie Curie' }
583583
})
584584

585-
assert.containsSubset(result, data)
585+
assert.containSubset(result, data)
586586
}
587587

588588
@Test()
@@ -619,7 +619,7 @@ export default class MongoDriverTest {
619619
})
620620
.find()
621621

622-
assert.containsSubset(result, { _id: '1', name: 'Marie Curie' })
622+
assert.containSubset(result, { _id: '1', name: 'Marie Curie' })
623623
}
624624

625625
@Test()
@@ -629,7 +629,7 @@ export default class MongoDriverTest {
629629

630630
const result = await this.driver.table('users').find()
631631

632-
assert.containsSubset(result, data)
632+
assert.containSubset(result, data)
633633
}
634634

635635
@Test()
@@ -656,7 +656,7 @@ export default class MongoDriverTest {
656656

657657
const result = await this.driver.table('users').findMany()
658658

659-
assert.containsSubset(result, data)
659+
assert.containSubset(result, data)
660660
}
661661

662662
@Test()
@@ -666,7 +666,7 @@ export default class MongoDriverTest {
666666

667667
const result = await this.driver.table('users').pluck('name')
668668

669-
assert.containsSubset(result, 'Charles Babbage')
669+
assert.containSubset(result, 'Charles Babbage')
670670
}
671671

672672
@Test()
@@ -676,7 +676,7 @@ export default class MongoDriverTest {
676676

677677
const result = await this.driver.table('users').pluckMany('name')
678678

679-
assert.containsSubset(result, ['Charles Babbage'])
679+
assert.containSubset(result, ['Charles Babbage'])
680680
}
681681

682682
@Test()
@@ -693,7 +693,7 @@ export default class MongoDriverTest {
693693

694694
const result = await this.driver.table('users').findMany()
695695

696-
assert.containsSubset(result, data)
696+
assert.containSubset(result, data)
697697
}
698698

699699
@Test()
@@ -710,7 +710,7 @@ export default class MongoDriverTest {
710710

711711
const result = await this.driver.table('users').paginate()
712712

713-
assert.containsSubset(result.data, data)
713+
assert.containSubset(result.data, data)
714714
assert.deepEqual(result.meta, {
715715
currentPage: 0,
716716
itemCount: 1,
@@ -733,7 +733,7 @@ export default class MongoDriverTest {
733733

734734
const result = await this.driver.table('users').paginate(0, 10, '/users')
735735

736-
assert.containsSubset(result.data, data)
736+
assert.containSubset(result.data, data)
737737
assert.deepEqual(result.meta, {
738738
currentPage: 0,
739739
itemCount: 1,
@@ -762,7 +762,7 @@ export default class MongoDriverTest {
762762

763763
const result = await this.driver.table('users').create(data)
764764

765-
assert.containsSubset(result, data)
765+
assert.containSubset(result, data)
766766
}
767767

768768
@Test()
@@ -782,7 +782,7 @@ export default class MongoDriverTest {
782782

783783
const result = await this.driver.table('users').createMany(data)
784784

785-
assert.containsSubset(result, data)
785+
assert.containSubset(result, data)
786786
}
787787

788788
@Test()
@@ -799,7 +799,7 @@ export default class MongoDriverTest {
799799

800800
const result = await this.driver.table('users').createOrUpdate(data)
801801

802-
assert.containsSubset(result, data)
802+
assert.containSubset(result, data)
803803
}
804804

805805
@Test()
@@ -809,7 +809,7 @@ export default class MongoDriverTest {
809809
await this.driver.table('users').create(data)
810810
const result = await this.driver.table('users').createOrUpdate({ ...data, name: 'Robert Kiyosaki Millennials' })
811811

812-
assert.containsSubset(result, { ...data, name: 'Robert Kiyosaki Millennials' })
812+
assert.containSubset(result, { ...data, name: 'Robert Kiyosaki Millennials' })
813813
}
814814

815815
@Test()
@@ -819,7 +819,7 @@ export default class MongoDriverTest {
819819
await this.driver.table('users').create(data)
820820
const result = await this.driver.table('users').update({ ...data, name: 'Robert Kiyosaki Millennials' })
821821

822-
assert.containsSubset(result, { ...data, name: 'Robert Kiyosaki Millennials' })
822+
assert.containSubset(result, { ...data, name: 'Robert Kiyosaki Millennials' })
823823
}
824824

825825
@Test()
@@ -835,7 +835,7 @@ export default class MongoDriverTest {
835835
.whereIn('_id', ['1', '2'])
836836
.update({ name: 'Robert Kiyosaki Millennials' })
837837

838-
assert.containsSubset(result, [
838+
assert.containSubset(result, [
839839
{ _id: '1', name: 'Robert Kiyosaki Millennials' },
840840
{ _id: '2', name: 'Robert Kiyosaki Millennials' }
841841
])
@@ -891,7 +891,7 @@ export default class MongoDriverTest {
891891

892892
const data = await this.driver.table('users').select('*').where('_id', '1').findMany()
893893

894-
assert.containsSubset(data, [{ _id: '1', name: 'Alan Turing' }])
894+
assert.containSubset(data, [{ _id: '1', name: 'Alan Turing' }])
895895
}
896896

897897
@Test()
@@ -1258,7 +1258,7 @@ export default class MongoDriverTest {
12581258

12591259
const data = await this.driver.table('users').groupBy('_id', 'name').havingNotIn('_id', ['1', '2']).findMany()
12601260

1261-
assert.containsSubset(data, [{ _id: '3', name: 'Alan Turing' }])
1261+
assert.containSubset(data, [{ _id: '3', name: 'Alan Turing' }])
12621262
}
12631263

12641264
@Test()
@@ -1279,7 +1279,7 @@ export default class MongoDriverTest {
12791279

12801280
const data = await this.driver.table('users').groupBy('_id', 'name').havingBetween('_id', ['1', '3']).findMany()
12811281

1282-
assert.containsSubset(data, [
1282+
assert.containSubset(data, [
12831283
{ _id: '1', name: 'Robert Kiyosaki' },
12841284
{ _id: '2', name: 'Warren Buffet' },
12851285
{ _id: '3', name: 'Alan Turing' }
@@ -1477,7 +1477,7 @@ export default class MongoDriverTest {
14771477

14781478
const data = await this.driver.table('users').groupBy('_id', 'name').orHavingNotIn('_id', ['1', '2']).findMany()
14791479

1480-
assert.containsSubset(data, [{ _id: '3', name: 'Alan Turing' }])
1480+
assert.containSubset(data, [{ _id: '3', name: 'Alan Turing' }])
14811481
}
14821482

14831483
@Test()
@@ -1498,7 +1498,7 @@ export default class MongoDriverTest {
14981498

14991499
const data = await this.driver.table('users').groupBy('_id', 'name').orHavingBetween('_id', ['1', '3']).findMany()
15001500

1501-
assert.containsSubset(data, [
1501+
assert.containSubset(data, [
15021502
{ _id: '1', name: 'Robert Kiyosaki' },
15031503
{ _id: '2', name: 'Warren Buffet' },
15041504
{ _id: '3', name: 'Alan Turing' }
@@ -1801,7 +1801,7 @@ export default class MongoDriverTest {
18011801

18021802
const data = await this.driver.table('users').whereNotIn('_id', ['1', '2']).findMany()
18031803

1804-
assert.containsSubset(data, [{ _id: '3', name: 'Alan Turing' }])
1804+
assert.containSubset(data, [{ _id: '3', name: 'Alan Turing' }])
18051805
}
18061806

18071807
@Test()
@@ -1822,7 +1822,7 @@ export default class MongoDriverTest {
18221822

18231823
const data = await this.driver.table('users').whereBetween('_id', ['1', '3']).findMany()
18241824

1825-
assert.containsSubset(data, [
1825+
assert.containSubset(data, [
18261826
{ _id: '1', name: 'Robert Kiyosaki' },
18271827
{ _id: '2', name: 'Warren Buffet' },
18281828
{ _id: '3', name: 'Alan Turing' }
@@ -2115,7 +2115,7 @@ export default class MongoDriverTest {
21152115

21162116
const data = await this.driver.table('users').orWhereNotIn('_id', ['1', '2']).findMany()
21172117

2118-
assert.containsSubset(data, [{ _id: '3', name: 'Alan Turing' }])
2118+
assert.containSubset(data, [{ _id: '3', name: 'Alan Turing' }])
21192119
}
21202120

21212121
@Test()
@@ -2128,7 +2128,7 @@ export default class MongoDriverTest {
21282128

21292129
const data = await this.driver.table('users').orWhereBetween('_id', ['1', '3']).findMany()
21302130

2131-
assert.containsSubset(data, [
2131+
assert.containSubset(data, [
21322132
{ _id: '1', name: 'Robert Kiyosaki' },
21332133
{ _id: '2', name: 'Warren Buffet' },
21342134
{ _id: '3', name: 'Alan Turing' }

0 commit comments

Comments
 (0)