Skip to content

Commit

Permalink
feat(preloader): add preloadOnce to preload a relationship only once (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
zaosoula authored Dec 18, 2024
1 parent 4862c7d commit fbfadbe
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/orm/preloader/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ export class Preloader implements PreloaderContract<LucidRow> {
return this.load(name, callback)
}

/**
* Define a relationship to preload, but only if they are not
* already preloaded
*/
preloadOnce(name: any): this {
if (!this.preloads[name]) {
return this.load(name)
}

return this
}

/**
* Toggle query debugging
*/
Expand Down
9 changes: 9 additions & 0 deletions src/orm/query_builder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,15 @@ export class ModelQueryBuilder
return this
}

/**
* Define a relationship to preload, but only if they are not
* already preloaded
*/
preloadOnce(relationName: any): this {
this.preloader.preloadOnce(relationName)
return this
}

/**
* Perform update by incrementing value for a given column. Increments
* can be clubbed with `update` as well
Expand Down
2 changes: 2 additions & 0 deletions src/types/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
WithAggregate,
WithCount,
PreloadWithoutCallback,
PreloadOnce,
} from './relations.js'

/**
Expand Down Expand Up @@ -481,6 +482,7 @@ export interface ModelQueryBuilderContract<Model extends LucidModel, Result = In
* Define relationships to be preloaded
*/
preload: Preload<InstanceType<Model>, this>
preloadOnce: PreloadOnce<InstanceType<Model>, this>

/**
* Aggregates
Expand Down
4 changes: 4 additions & 0 deletions src/types/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,9 @@ export interface PreloadWithoutCallback<Model extends LucidRow, Builder> {
<Name extends ExtractModelRelations<Model>>(relation: Name): Builder
}

export interface PreloadOnce<Model extends LucidRow, Builder>
extends PreloadWithoutCallback<Model, Builder> {}

/**
* Shape of the preloader to preload relationships
*/
Expand All @@ -1074,6 +1077,7 @@ export interface PreloaderContract<Model extends LucidRow> {

load: Preload<Model, this>
preload: Preload<Model, this>
preloadOnce: PreloadOnce<Model, this>

debug(debug: boolean): this
sideload(values: ModelObject): this
Expand Down
36 changes: 36 additions & 0 deletions test/orm/model_belongs_to.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,42 @@ test.group('Model | BelongsTo | preload', (group) => {
assert.equal(profiles[0].user.id, profiles[0].userId)
})

test('preload relationship once', async ({ assert, fs }) => {
const app = new AppFactory().create(fs.baseUrl, () => {})
await app.init()
const db = getDb()
const adapter = ormAdapter(db)
const BaseModel = getBaseModel(adapter)
class User extends BaseModel {
@column({ isPrimary: true })
declare id: number
}

class Profile extends BaseModel {
@column()
declare userId: number

@belongsTo(() => User)
declare user: BelongsTo<typeof User>
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ display_name: 'Hvirk', user_id: 1 })

Profile.boot()

let callbackCalled = false

const profiles = await Profile.query()
.preload('user', () => {
callbackCalled = true
})
.preloadOnce('user')
assert.lengthOf(profiles, 1)
assert.equal(profiles[0].user.id, profiles[0].userId)
assert.isTrue(callbackCalled)
})

test('set property value to null when no preload rows were found', async ({ assert, fs }) => {
const app = new AppFactory().create(fs.baseUrl, () => {})
await app.init()
Expand Down

0 comments on commit fbfadbe

Please sign in to comment.