From fbfadbeec0373041ec02622016021512e95c9ca8 Mon Sep 17 00:00:00 2001 From: Zao Soula Date: Wed, 18 Dec 2024 18:02:32 +0100 Subject: [PATCH] feat(preloader): add preloadOnce to preload a relationship only once (#1078) --- src/orm/preloader/index.ts | 12 +++++++++++ src/orm/query_builder/index.ts | 9 ++++++++ src/types/model.ts | 2 ++ src/types/relations.ts | 4 ++++ test/orm/model_belongs_to.spec.ts | 36 +++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+) diff --git a/src/orm/preloader/index.ts b/src/orm/preloader/index.ts index 2850bd0c..d942c823 100644 --- a/src/orm/preloader/index.ts +++ b/src/orm/preloader/index.ts @@ -128,6 +128,18 @@ export class Preloader implements PreloaderContract { 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 */ diff --git a/src/orm/query_builder/index.ts b/src/orm/query_builder/index.ts index e34dc9b3..f1a68499 100644 --- a/src/orm/query_builder/index.ts +++ b/src/orm/query_builder/index.ts @@ -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 diff --git a/src/types/model.ts b/src/types/model.ts index 0b41283f..7052c993 100644 --- a/src/types/model.ts +++ b/src/types/model.ts @@ -42,6 +42,7 @@ import { WithAggregate, WithCount, PreloadWithoutCallback, + PreloadOnce, } from './relations.js' /** @@ -481,6 +482,7 @@ export interface ModelQueryBuilderContract, this> + preloadOnce: PreloadOnce, this> /** * Aggregates diff --git a/src/types/relations.ts b/src/types/relations.ts index 3291aff3..7c9df8ae 100644 --- a/src/types/relations.ts +++ b/src/types/relations.ts @@ -1065,6 +1065,9 @@ export interface PreloadWithoutCallback { >(relation: Name): Builder } +export interface PreloadOnce + extends PreloadWithoutCallback {} + /** * Shape of the preloader to preload relationships */ @@ -1074,6 +1077,7 @@ export interface PreloaderContract { load: Preload preload: Preload + preloadOnce: PreloadOnce debug(debug: boolean): this sideload(values: ModelObject): this diff --git a/test/orm/model_belongs_to.spec.ts b/test/orm/model_belongs_to.spec.ts index 4b547fbf..79b668a8 100644 --- a/test/orm/model_belongs_to.spec.ts +++ b/test/orm/model_belongs_to.spec.ts @@ -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 + } + + 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()