diff --git a/adonis-typings/model.ts b/adonis-typings/model.ts index 82e8c6f7..e501a24b 100644 --- a/adonis-typings/model.ts +++ b/adonis-typings/model.ts @@ -138,6 +138,11 @@ declare module '@ioc:Adonis/Lucid/Model' { */ first (): Promise | null> + /** + * Return the first matching row or fail + */ + firstOrFail (): Promise> + /** * Define relationships to be preloaded */ @@ -317,22 +322,64 @@ declare module '@ioc:Adonis/Lucid/Model' { /** * Creating model */ - create (this: T, values: ModelObject): InstanceType + create ( + this: T, + values: ModelObject, + options?: ModelOptions, + ): InstanceType /** - * Creating model by invoking actions on adapter + * Find one using the primary key */ - findBy ( + find ( this: T, - key: string, value: any, options?: ModelOptions, ): Promise> /** - * Fetch all rows and convert them to model instances + * Find one using the primary key or fail + */ + findOrFail ( + this: T, + value: any, + options?: ModelOptions, + ): Promise> + + /** + * Find many using an array of primary keys + */ + findMany ( + this: T, + value: any[], + options?: ModelOptions, + ): Promise[]> + + /** + * Returns the first row or save it to the database + */ + firstOrSave ( + this: T, + search: any, + savePayload?: any, + options?: ModelOptions, + ): Promise> + + /** + * Returns the first row or create a new instance of model without + * persisting it + */ + firstOrNew ( + this: T, + search: any, + savePayload?: any, + options?: ModelOptions, + ): Promise> + + /** + * Fetch all rows */ - findAll (this: T, options?: ModelOptions): Promise[]> + all (this: T, options?: ModelOptions): Promise[]> /** * Returns the query for fetching a model instance diff --git a/example/index.ts b/example/index.ts index cfc74c7d..3454598f 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,14 +1,14 @@ -import { BaseModel } from '@ioc:Adonis/Lucid/Orm' +// import { BaseModel } from '@ioc:Adonis/Lucid/Orm' +// import Database from '@ioc:Adonis/Lucid/Database' -class Profile extends BaseModel { -} +// class Profile extends BaseModel { +// } -class User extends BaseModel { - public username: string +// class User extends BaseModel { +// public username: string +// public profile: Profile[] +// } - public profile: Profile -} - -const user = new User() -const profile = user.$getRelated('profile') -console.log(profile) +// user.saveRelated('profile', new Profile()) +// const profile = user.$getRelated('profile') +// console.log(profile) diff --git a/src/Orm/BaseModel/index.ts b/src/Orm/BaseModel/index.ts index ee1887b2..98d59ebc 100644 --- a/src/Orm/BaseModel/index.ts +++ b/src/Orm/BaseModel/index.ts @@ -299,19 +299,77 @@ export class BaseModel implements ModelContract { /** * Find model instance using a key/value pair */ - public static async findBy ( + public static async find ( this: T, - key: string, value: any, options?: any, ) { - return this.query(options).where(key, value).first() + return this.query(options).where(this.$primaryKey, value).first() } + /** + * Find model instance using a key/value pair + */ + public static async findOrFail ( + this: T, + value: any, + options?: any, + ) { + return this.query(options).where(this.$primaryKey, value).firstOrFail() + } + + /** + * Find model instance using a key/value pair + */ + public static async findMany ( + this: T, + value: any[], + options?: any, + ) { + return this.query(options).whereIn(this.$primaryKey, value).exec() + } + + /** + * Find model instance using a key/value pair + */ + public static async firstOrSave ( + this: T, + search: any, + savePayload?: any, + options?: ModelOptions, + ) { + const row = await this.firstOrNew(search, savePayload, options) + if (!row.$persisted) { + await row.save() + } + + return row + } + + /** + * Find model instance using a key/value pair + */ + public static async firstOrNew ( + this: T, + search: any, + savePayload?: any, + options?: ModelOptions, + ) { + let row = await this.query(options).where(search).first() + + if (!row) { + row = new this() as InstanceType + row.$options = options + row.fill(Object.assign({}, search, savePayload)) + return row + } + + return row + } /** * Create a array of model instances from the adapter result */ - public static async findAll ( + public static async all ( this: T, options?: any, ) { diff --git a/src/Orm/QueryBuilder/index.ts b/src/Orm/QueryBuilder/index.ts index 7bbcc4e0..86e7ae39 100644 --- a/src/Orm/QueryBuilder/index.ts +++ b/src/Orm/QueryBuilder/index.ts @@ -159,6 +159,19 @@ export class ModelQueryBuilder extends Chainable implements ModelQueryBuilderCon return result[0] || null } + /** + * Fetch and return first results from the results set. This method + * will implicitly set a `limit` on the query + */ + public async firstOrFail (): Promise { + const result = await this.limit(1)['exec']() + if (!result.length) { + throw new Error('Row not found') + } + + return result[0] + } + /** * Define a relationship to be preloaded */ diff --git a/test/adapter.spec.ts b/test/adapter.spec.ts index e9844e11..c9f4fb39 100644 --- a/test/adapter.spec.ts +++ b/test/adapter.spec.ts @@ -110,30 +110,7 @@ test.group('Adapter', (group) => { assert.lengthOf(users, 0) }) - test('get model instance using the find call', async (assert) => { - const db = getDb() - const BaseModel = getBaseModel(ormAdapter()) - - class User extends BaseModel { - public static $table = 'users' - - @column({ primary: true }) - public id: number - - @column() - public username: string - } - User.$boot() - - const [id] = await db.table('users').returning('id').insert({ username: 'virk' }) - - const user = await User.findBy('username', 'virk') - assert.instanceOf(user, User) - assert.isFalse(user!.$isDirty) - assert.deepEqual(user!.$attributes, { id: id, username: 'virk' }) - }) - - test('get array of model instances using the findAll call', async (assert) => { + test('get array of model instances using the all call', async (assert) => { const db = getDb() const BaseModel = getBaseModel(ormAdapter()) @@ -152,7 +129,7 @@ test.group('Adapter', (group) => { [{ username: 'virk' }, { username: 'nikk' }], ) - const users = await User.findAll() + const users = await User.all() assert.lengthOf(users, 2) assert.instanceOf(users[0], User)