Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions packages/pinia-orm/src/query/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export class Query<M extends Model = Model> {

protected getNewHydrated = false

protected hydrationKey?: string

/**
* Hydrated models. They are stored to prevent rerendering of child components.
*/
Expand All @@ -114,28 +116,29 @@ export class Query<M extends Model = Model> {
/**
* Create a new query instance.
*/
constructor (database: Database, model: M, cache: WeakCache<string, Collection<M> | GroupedCollection<M>> | undefined, hydratedData: Map<string, M>, pinia?: Pinia) {
constructor (database: Database, model: M, cache: WeakCache<string, Collection<M> | GroupedCollection<M>> | undefined, hydratedData: Map<string, M>, pinia?: Pinia, hydrationKey?: string) {
this.database = database
this.model = model
this.pinia = pinia
this.cache = cache
this.hydratedDataCache = hydratedData
this.getNewHydrated = false
this.hydrationKey = hydrationKey
}

/**
* Create a new query instance for the given model.
*/
newQuery (model: string): Query<M> {
this.getNewHydrated = true
return new Query<M>(this.database, this.database.getModel(model), this.cache, this.hydratedDataCache, this.pinia)
return new Query<M>(this.database, this.database.getModel(model), this.cache, this.hydratedDataCache, this.pinia, this.hydrationKey)
}

/**
* Create a new query instance with constraints for the given model.
*/
newQueryWithConstraints (model: string): Query<M> {
const newQuery = new Query<M>(this.database, this.database.getModel(model), this.cache, this.hydratedDataCache, this.pinia)
const newQuery = new Query<M>(this.database, this.database.getModel(model), this.cache, this.hydratedDataCache, this.pinia, this.hydrationKey)

// Copy query constraints
newQuery.eagerLoad = { ...this.eagerLoad }
Expand All @@ -153,7 +156,7 @@ export class Query<M extends Model = Model> {
* Create a new query instance from the given relation.
*/
newQueryForRelation (relation: Relation): Query<M> {
return new Query<M>(this.database, relation.getRelated() as M, this.cache, new Map<string, M>(), this.pinia)
return new Query<M>(this.database, relation.getRelated() as M, this.cache, new Map<string, M>(), this.pinia, this.hydrationKey)
}

/**
Expand Down Expand Up @@ -482,20 +485,12 @@ export class Query<M extends Model = Model> {
*/
get<T extends 'group' | 'collection' = 'collection'>(triggerHook?: boolean): T extends 'group' ? GroupedCollection<M> : Collection<M>
get (triggerHook = true): Collection<M> | GroupedCollection<M> {
this.hydrationKey = this.hydrationKey ?? this.generateHydrationKey()
if (!this.fromCache || !this.cache) { return this.internalGet(triggerHook) }

const key = this.cacheConfig.key
? this.cacheConfig.key + JSON.stringify(this.cacheConfig.params)
: generateKey(this.model.$entity(), {
where: this.wheres,
groups: this.groups,
orders: this.orders,
eagerLoads: this.eagerLoad,
skip: this.skip,
take: this.take,
hidden: this.hidden,
visible: this.visible,
})
: this.hydrationKey
const result = this.cache.get(key)

if (result) { return result }
Expand Down Expand Up @@ -582,6 +577,19 @@ export class Query<M extends Model = Model> {
return models.filter(model => comparator(model))
}

protected generateHydrationKey (): string {
return generateKey(this.model.$entity(), {
where: this.wheres,
groups: this.groups,
orders: this.orders,
eagerLoads: this.eagerLoad,
skip: this.skip,
take: this.take,
hidden: this.hidden,
visible: this.visible,
})
}

/**
* Get comparator for the where clause.
*/
Expand Down Expand Up @@ -1019,8 +1027,7 @@ export class Query<M extends Model = Model> {
const isDeleting = currentModel.$self().deleting(currentModel)

if (isDeleting === false) { notDeletableIds.push(currentModel.$getIndexId()) } else {
this.hydratedDataCache.delete('set' + this.model.$entity() + currentModel.$getIndexId())
this.hydratedDataCache.delete('get' + this.model.$entity() + currentModel.$getIndexId())
this.hydratedDataCache.delete(this.model.$entity() + currentModel.$getIndexId())
afterHooks.push(() => currentModel.$self().deleted(currentModel))
this.checkAndDeleteRelations(currentModel)
}
Expand Down Expand Up @@ -1066,11 +1073,11 @@ export class Query<M extends Model = Model> {
*/
protected getHydratedModel (record: Element, options?: ModelOptions): M {
const id = this.model.$entity() + this.model.$getKey(record, true)
const operationId = options?.operation + id
const operationId = id
let savedHydratedModel = this.hydratedDataCache.get(operationId)

if (options?.action === 'update') {
this.hydratedDataCache.delete('get' + id)
if (options?.action === 'update' || this.hydrationKey === undefined) {
this.hydratedDataCache.delete(id)
savedHydratedModel = undefined
}

Expand All @@ -1084,7 +1091,9 @@ export class Query<M extends Model = Model> {
.$newInstance(record, { relations: false, ...(options || {}), ...newOptions })
const hydratedModel = getNewInsance()

if (isEmpty(this.eagerLoad) && options?.operation !== 'set') { this.hydratedDataCache.set(operationId, hydratedModel) }
if (isEmpty(this.eagerLoad) && options?.operation !== 'set' && this.hydrationKey !== undefined) {
this.hydratedDataCache.set(operationId, hydratedModel)
}

return hydratedModel
}
Expand Down
2 changes: 1 addition & 1 deletion packages/pinia-orm/tests/feature/hooks/creating.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('feature/hooks/creating', () => {
{ id: 2, name: 'John Doe 2', age: 40 },
])

expect(useRepo(User).hydratedDataCache.size).toBe(2)
expect(useRepo(User).hydratedDataCache.size).toBe(0)
expect(creatingMethod).toHaveBeenCalledTimes(2)
expect(updatingMethod).toHaveBeenCalledTimes(0)
expect(savingMethod).toHaveBeenCalledTimes(2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,37 @@ describe('feature/relations/constraints/constraints', () => {
expect(users[1].phone!.type!.id).toBe(2)
expect(users[2].phone!.type).toBe(null)
})

it('loads with and without relations correctly', () => {
const usersRepo = useRepo(User)
const phonesRepo = useRepo(Phone)
const typesRepo = useRepo(Type)
usersRepo.cache()?.clear()

usersRepo.save([
{ id: 1, name: 'John Doe', roles: [{ id: 1, pivot: { level: 1 }, phone: { id: 4, number: '999' } }, { id: 2 }, { id: 4 }] },
{ id: 2, name: 'John Doe', roles: [{ id: 1, pivot: { level: 2 } }] },
{ id: 3, name: 'Johnny Doe' },
])

phonesRepo.save([
{ id: 1, userId: 1, number: '123' },
{ id: 2, userId: 2, number: '345' },
{ id: 3, userId: 3, number: '789' },
])
typesRepo.save([
{ id: 1, phoneId: 1, name: 'iPhone' },
{ id: 2, phoneId: 2, name: 'Android' },
])

const users2 = usersRepo.get()
const users = usersRepo
.with('roles', (query) => {
query.with('phone')
})
.get()

expect(users[0].roles.length).toBe(3)
expect(users2[0].roles).toBe(undefined)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('unit/model/Model_Meta_Field', () => {
username: 'JD',
})

await new Promise(resolve => setTimeout(resolve, 1500))
await new Promise(resolve => setTimeout(resolve, 2000))

userRepo.save({
id: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('unit/repository/Repository', () => {
expect(userRepo.hydratedDataCache.size).toBe(0)

userRepo.piniaStore().save({ 1: { id: 1, name: 'John' } })
expect(userRepo.hydratedDataCache.size).toBe(1)
expect(userRepo.hydratedDataCache.size).toBe(0)

userRepo.piniaStore().update({ 1: { id: 1, name: 'John 2' } })
expect(userRepo.hydratedDataCache.size).toBe(0)
Expand Down
Loading