From 059c4722c64e7dc2cd09c6ab5d7745ef0d99eb75 Mon Sep 17 00:00:00 2001 From: Romain Lanz <2793951+RomainLanz@users.noreply.github.com> Date: Tue, 26 Mar 2024 22:07:09 +0100 Subject: [PATCH] feat(base_model): add clause variant to findBy method (#1020) * feat(base_model): add findBy and findByOrFail clause alternative * test(base_model): add test about findBy --- src/orm/base_model/index.ts | 33 +++++++++++++++++++-- src/types/model.ts | 20 ++++++++++++- test/orm/base_model.spec.ts | 58 +++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/orm/base_model/index.ts b/src/orm/base_model/index.ts index 9cf34981..57204c10 100644 --- a/src/orm/base_model/index.ts +++ b/src/orm/base_model/index.ts @@ -703,7 +703,21 @@ class BaseModelImpl implements LucidRow { /** * Find model instance using a key/value pair */ - static async findBy(key: string, value: any, options?: ModelAdapterOptions) { + // @ts-expect-error - Return type should be inferred when used in a model + static findBy(clause: Record, options?: ModelAdapterOptions) + // @ts-expect-error - Return type should be inferred when used in a model + static findBy(key: string, value: any, options?: ModelAdapterOptions) + static async findBy( + key: string | Record, + value?: any | ModelAdapterOptions, + options?: ModelAdapterOptions + ) { + if (typeof key === 'object') { + return this.query(value as ModelAdapterOptions) + .where(key) + .first() + } + if (value === undefined) { throw new Exception('"findBy" expects a value. Received undefined') } @@ -714,10 +728,25 @@ class BaseModelImpl implements LucidRow { /** * Find model instance using a key/value pair */ - static async findByOrFail(key: string, value: any, options?: ModelAdapterOptions) { + // @ts-expect-error - Return type should be inferred when used in a model + static findByOrFail(clause: Record, options?: ModelAdapterOptions) + // @ts-expect-error - Return type should be inferred when used in a model + static findByOrFail(key: string, value: any, options?: ModelAdapterOptions) + static async findByOrFail( + key: string | Record, + value?: any | ModelAdapterOptions, + options?: ModelAdapterOptions + ) { + if (typeof key === 'object') { + return this.query(value as ModelAdapterOptions) + .where(key) + .firstOrFail() + } + if (value === undefined) { throw new Exception('"findByOrFail" expects a value. Received undefined') } + return this.query(options).where(key, value).firstOrFail() } diff --git a/src/types/model.ts b/src/types/model.ts index cd0d5d03..7a2d7e5c 100644 --- a/src/types/model.ts +++ b/src/types/model.ts @@ -975,6 +975,15 @@ export interface LucidModel { options?: ModelAdapterOptions ): Promise> + /** + * Find one using a clause + */ + findBy( + this: T, + clause: Record, + options?: ModelAdapterOptions + ): Promise> + /** * Find one using a key-value pair */ @@ -985,6 +994,15 @@ export interface LucidModel { options?: ModelAdapterOptions ): Promise> + /** + * Find one using a clause or fail + */ + findByOrFail( + this: T, + clause: Record, + options?: ModelAdapterOptions + ): Promise> + /** * Find one using a key-value pair or fail */ @@ -996,7 +1014,7 @@ export interface LucidModel { ): Promise> /** - * Find multiple models instance using a key/value pair + * Find multiple models instance using a clause */ findManyBy( this: T, diff --git a/test/orm/base_model.spec.ts b/test/orm/base_model.spec.ts index 67796f1b..6556877b 100644 --- a/test/orm/base_model.spec.ts +++ b/test/orm/base_model.spec.ts @@ -3780,6 +3780,64 @@ test.group('Base Model | fetch', (group) => { assert.equal(users[1].$primaryKeyValue, 1) }) + test('findBy using a clause', async ({ fs, assert }) => { + 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 + + @column() + declare username: string + + @column() + declare email: string + } + + await db + .insertQuery() + .table('users') + .multiInsert([{ username: 'virk' }, { username: 'nikk' }]) + + const user = await User.findBy({ username: 'virk' }) + assert.isDefined(user) + assert.equal(user?.username, 'virk') + }) + + test('findBy using a key/value pair', async ({ fs, assert }) => { + 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 + + @column() + declare username: string + + @column() + declare email: string + } + + await db + .insertQuery() + .table('users') + .multiInsert([{ username: 'virk' }, { username: 'nikk' }]) + + const user = await User.findBy('username', 'virk') + assert.isDefined(user) + assert.equal(user?.username, 'virk') + }) + test('find many using a clause', async ({ fs, assert }) => { const app = new AppFactory().create(fs.baseUrl, () => {}) await app.init()