Skip to content

Commit a9fd092

Browse files
authored
fix(pinia-orm): Hooks should update cache & hydration (#1113)
- Add working shared hydration cache - Hooks which are updating data are rehydrated to use casts
1 parent 487336d commit a9fd092

File tree

8 files changed

+63
-15
lines changed

8 files changed

+63
-15
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import type { Model } from '../model/Model'
22

3-
export const cache = <M extends Model = Model>() => new Map<string, M>()
3+
export const cache = new Map<string, Model>()

packages/pinia-orm/src/model/Model.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -800,11 +800,13 @@ export class Model {
800800
* Get primary key value for the model. If the model has the composite key,
801801
* it will return an array of ids.
802802
*/
803-
$getKey(record?: Element): string | number | (string | number)[] | null {
803+
$getKey(record?: Element, concatCompositeKey = false): string | number | (string | number)[] | null {
804804
record = record ?? this
805805

806-
if (this.$hasCompositeKey())
807-
return this.$getCompositeKey(record)
806+
if (this.$hasCompositeKey()) {
807+
const compositeKey = this.$getCompositeKey(record)
808+
return concatCompositeKey ? compositeKey?.join('') ?? null : compositeKey
809+
}
808810

809811
const id = record[this.$getKeyName() as string]
810812

packages/pinia-orm/src/query/Query.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ export class Query<M extends Model = Model> {
339339
* Set the relationships that should be eager loaded.
340340
*/
341341
with(name: string, callback: EagerLoadConstraint = () => {}): this {
342+
this.getNewHydrated = true
342343
this.eagerLoad[name] = callback
343344

344345
return this
@@ -645,8 +646,9 @@ export class Query<M extends Model = Model> {
645646
* Revive single model from the given schema.
646647
*/
647648
reviveOne(schema: Element): Item<M> {
648-
const id = this.model.$getIndexId(schema)
649+
this.getNewHydrated = false
649650

651+
const id = this.model.$getIndexId(schema)
650652
const item = this.commit('get')[id] ?? null
651653

652654
if (!item)
@@ -711,13 +713,17 @@ export class Query<M extends Model = Model> {
711713
* Create and persist model with default values.
712714
*/
713715
new(persist = true): M | null {
714-
const model = this.hydrate({}, { operation: persist ? 'get' : 'set' })
716+
let model = this.hydrate({}, { operation: persist ? 'set' : 'get' })
715717
const isCreating = model.$self().creating(model)
716718
const isSaving = model.$self().saving(model)
717719
if (isCreating === false || isSaving === false)
718720
return null
719721

722+
if (model.$isDirty())
723+
model = this.hydrate(model.$getAttributes(), { operation: persist ? 'set' : 'get' })
724+
720725
if (persist) {
726+
this.hydratedDataCache.set(this.model.$entity() + model.$getKey(undefined, true), this.hydrate(model.$getAttributes(), { operation: 'get' }))
721727
model.$self().created(model)
722728
model.$self().saved(model)
723729
this.commit('insert', this.compile(model))
@@ -780,7 +786,7 @@ export class Query<M extends Model = Model> {
780786
for (const id in elements) {
781787
const record = elements[id]
782788
const existing = currentData[id]
783-
const model = existing
789+
let model = existing
784790
? this.hydrate({ ...existing, ...record }, { operation: 'set', action: 'update' })
785791
: this.hydrate(record, { operation: 'set', action: 'save' })
786792

@@ -789,6 +795,9 @@ export class Query<M extends Model = Model> {
789795
if (isSaving === false || isUpdatingOrCreating === false)
790796
continue
791797

798+
if (model.$isDirty())
799+
model = this.hydrate(model.$getAttributes(), { operation: 'set', action: existing ? 'update' : 'save' })
800+
792801
afterSavingHooks.push(() => model.$self().saved(model, record))
793802
afterSavingHooks.push(() => existing ? model.$self().updated(model, record) : model.$self().created(model, record))
794803
newData[id] = model.$getAttributes()
@@ -1017,8 +1026,7 @@ export class Query<M extends Model = Model> {
10171026
* an update event trigger in vue if the object is used.
10181027
*/
10191028
protected getHydratedModel(record: Element, options?: ModelOptions): M {
1020-
const modelKey = this.model.$getKeyName()
1021-
const id = (!isArray(modelKey) ? [modelKey] : modelKey).map(key => record[key]).join('')
1029+
const id = this.model.$getKey(record, true)
10221030
const savedHydratedModel = id && this.hydratedDataCache.get(this.model.$entity() + id)
10231031

10241032
if (

packages/pinia-orm/src/repository/Repository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class Repository<M extends Model = Model> {
6666
constructor(database: Database, pinia?: Pinia) {
6767
this.database = database
6868
this.pinia = pinia
69-
this.hydratedDataCache = hydratedDataCache<M>()
69+
this.hydratedDataCache = hydratedDataCache as Map<string, M>
7070
}
7171

7272
/**

packages/pinia-orm/tests/feature/hooks/creating.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ describe('feature/hooks/creating', () => {
4949
{ id: 2, name: 'John Doe 2', age: 40 },
5050
])
5151

52+
expect(useRepo(User).hydratedDataCache.size).toBe(2)
5253
expect(creatingMethod).toHaveBeenCalledTimes(2)
5354
expect(updatingMethod).toHaveBeenCalledTimes(0)
5455
expect(savingMethod).toHaveBeenCalledTimes(2)

packages/pinia-orm/tests/feature/hooks/retrieved.spec.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, expect, it, vi } from 'vitest'
1+
import { beforeEach, describe, expect, it, vi } from 'vitest'
22

33
import { Model, useRepo } from '../../../src'
44
import { Num, Str } from '../../../src/decorators'
@@ -7,6 +7,10 @@ import {
77
} from '../../helpers'
88

99
describe('feature/hooks/retrieved', () => {
10+
beforeEach(() => {
11+
Model.clearRegistries()
12+
})
13+
1014
it('is not triggered when trying to retrieve a non existing record', () => {
1115
class User extends Model {
1216
static entity = 'users'
@@ -42,7 +46,7 @@ describe('feature/hooks/retrieved', () => {
4246
@Num(0) age!: number
4347

4448
static retrieved() {
45-
// Doing retrieved stuff
49+
console.warn('retrieved')
4650
}
4751
}
4852

@@ -69,7 +73,7 @@ describe('feature/hooks/retrieved', () => {
6973
@Num(0) age!: number
7074

7175
static retrieved() {
72-
// Doing retrieved stuff
76+
console.warn('retrieved')
7377
}
7478
}
7579

packages/pinia-orm/tests/feature/repository/new.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { describe, expect, it } from 'vitest'
22

33
import { Model, useRepo } from '../../../src'
4-
import { Attr, Bool, Num, Str, Uid } from '../../../src/decorators'
4+
import { Attr, Bool, Cast, Num, Str, Uid } from '../../../src/decorators'
55
import { assertState, mockUid } from '../../helpers'
6+
import { ArrayCast } from '../../../src/model/casts/ArrayCast'
67

78
describe('feature/repository/new', () => {
89
it('inserts with a models default values', () => {
@@ -28,6 +29,37 @@ describe('feature/repository/new', () => {
2829
})
2930
})
3031

32+
it('it trigger casts on hooks', () => {
33+
class User extends Model {
34+
static entity = 'users'
35+
36+
@Uid() declare id: string
37+
38+
@Cast(() => ArrayCast) @Attr('{}') declare items: string[]
39+
@Str('John Doe') declare name: string
40+
@Num(21) declare age: number
41+
@Bool(true) declare active: boolean
42+
43+
static creating(model: User) {
44+
model.items = ['t', 's']
45+
}
46+
}
47+
48+
mockUid(['uid1'])
49+
50+
const userRepo = useRepo(User)
51+
52+
userRepo.new()
53+
54+
assertState({
55+
users: {
56+
uid1: { id: 'uid1', name: 'John Doe', items: '["t","s"]', age: 21, active: true },
57+
},
58+
})
59+
60+
expect(userRepo.hydratedDataCache.get('usersuid1')?.items).toBeInstanceOf(Array)
61+
})
62+
3163
it('throws if a primary key is not capable of being generated', () => {
3264
class User extends Model {
3365
static entity = 'users'

packages/pinia-orm/tests/setup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createPinia, setActivePinia } from 'pinia'
22
import { beforeAll, beforeEach, vi } from 'vitest'
33
import { Vue2, createApp, install, isVue2 } from 'vue-demi'
44

5-
import { Model, createORM } from '../src'
5+
import { Model, createORM, useRepo } from '../src'
66

77
vi.mock('nanoid/non-secure', () => ({
88
nanoid: vi.fn(),
@@ -36,4 +36,5 @@ beforeEach(() => {
3636
app.use(pinia)
3737
setActivePinia(pinia)
3838
Model.clearBootedModels()
39+
useRepo(Model).hydratedDataCache.clear()
3940
})

0 commit comments

Comments
 (0)