Skip to content

Commit

Permalink
feat(base_model): add clause variant to findBy method (#1020)
Browse files Browse the repository at this point in the history
* feat(base_model): add findBy and findByOrFail clause alternative

* test(base_model): add test about findBy
  • Loading branch information
RomainLanz committed Mar 26, 2024
1 parent c22f019 commit 059c472
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 3 deletions.
33 changes: 31 additions & 2 deletions src/orm/base_model/index.ts
Expand Up @@ -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<string, unknown>, 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<string, unknown>,
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')
}
Expand All @@ -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<string, unknown>, 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<string, unknown>,
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()
}

Expand Down
20 changes: 19 additions & 1 deletion src/types/model.ts
Expand Up @@ -975,6 +975,15 @@ export interface LucidModel {
options?: ModelAdapterOptions
): Promise<InstanceType<T>>

/**
* Find one using a clause
*/
findBy<T extends LucidModel>(
this: T,
clause: Record<string, unknown>,
options?: ModelAdapterOptions
): Promise<null | InstanceType<T>>

/**
* Find one using a key-value pair
*/
Expand All @@ -985,6 +994,15 @@ export interface LucidModel {
options?: ModelAdapterOptions
): Promise<null | InstanceType<T>>

/**
* Find one using a clause or fail
*/
findByOrFail<T extends LucidModel>(
this: T,
clause: Record<string, unknown>,
options?: ModelAdapterOptions
): Promise<InstanceType<T>>

/**
* Find one using a key-value pair or fail
*/
Expand All @@ -996,7 +1014,7 @@ export interface LucidModel {
): Promise<InstanceType<T>>

/**
* Find multiple models instance using a key/value pair
* Find multiple models instance using a clause
*/
findManyBy<T extends LucidModel>(
this: T,
Expand Down
58 changes: 58 additions & 0 deletions test/orm/base_model.spec.ts
Expand Up @@ -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()
Expand Down

0 comments on commit 059c472

Please sign in to comment.