Skip to content

Commit

Permalink
feat: implement updateOrCreate
Browse files Browse the repository at this point in the history
closes #484
  • Loading branch information
thetutlage committed Jan 12, 2020
1 parent 28c20bf commit b957c6e
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 2 deletions.
10 changes: 10 additions & 0 deletions adonis-typings/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,16 @@ declare module '@ioc:Adonis/Lucid/Model' {
options?: ModelAdapterOptions,
): Promise<InstanceType<T>>

/**
* Returns the first row or save it to the database
*/
updateOrCreate<T extends ModelConstructorContract> (
this: T,
search: any,
updatePayload: any,
options?: ModelAdapterOptions,
): Promise<InstanceType<T>>

/**
* Fetch all rows
*/
Expand Down
35 changes: 33 additions & 2 deletions src/Orm/BaseModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,44 @@ export class BaseModel implements ModelContract {

if (!row) {
row = new this() as InstanceType<T>
row.$options = query.clientOptions
row.fill(Object.assign({}, search, savePayload))
return row
}

/**
* Copying options from the select query client and use the same
* one's for persistance
*/
if (query.client.isTransaction) {
row.$trx = query.client as TransactionClientContract
} else {
row.$options = query.clientOptions
}

return row
}

/**
* Updates or creates a new row inside the database
*/
public static async updateOrCreate<T extends ModelConstructorContract> (
this: T,
search: any,
updatedPayload: any,
options?: ModelAdapterOptions,
) {
const row = await this.firstOrNew(search, updatedPayload, options)

/**
* Update if row was found
*/
if (row.$persisted) {
row.merge(updatedPayload)
}

await row.save()
return row
}

/**
* Create a array of model instances from the adapter result
*/
Expand Down
Binary file added test-helpers/tmp/db.sqlite
Binary file not shown.
125 changes: 125 additions & 0 deletions test/orm/base-model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1390,6 +1390,131 @@ test.group('Base Model | fetch', (group) => {
assert.equal(user!.email, 'nikk@gmail.com')
assert.equal(user!.username, 'nikk')
})

test('update the existing row when search criteria matches', async (assert) => {
class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@column()
public email: string

@column()
public points: number
}

await db.insertQuery().table('users').insert({ username: 'virk' })
const user = await User.updateOrCreate({ username: 'virk' }, { points: 20 })
assert.isTrue(user.$persisted)
assert.equal(user.points, 20)
assert.equal(user.username, 'virk')

const users = await db.query().from('users')

assert.lengthOf(users, 1)
assert.equal(users[0].points, 20)
})

test('execute updateOrCreate update action inside a transaction', async (assert) => {
class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@column()
public email: string

@column()
public points: number
}

await db.insertQuery().table('users').insert({ username: 'virk' })
const trx = await db.transaction()

const user = await User.updateOrCreate({ username: 'virk' }, { points: 20 }, { client: trx })

assert.isTrue(user.$persisted)
assert.equal(user.points, 20)
assert.equal(user.username, 'virk')

await trx.rollback()

const users = await db.query().from('users')
assert.lengthOf(users, 1)

assert.equal(users[0].username, 'virk')
assert.equal(users[0].points, 0)
})

test('create a new row when search criteria fails', async (assert) => {
class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@column()
public email: string

@column()
public points: number
}

await db.insertQuery().table('users').insert({ username: 'virk' })
const user = await User.updateOrCreate({ username: 'nikk' }, { points: 20 })

assert.isTrue(user.$persisted)
assert.equal(user.points, 20)
assert.equal(user.username, 'nikk')

const users = await db.query().from('users')
assert.lengthOf(users, 2)

assert.equal(users[0].username, 'virk')
assert.equal(users[0].points, 0)

assert.equal(users[1].username, 'nikk')
assert.equal(users[1].points, 20)
})

test('execute updateOrCreate create action inside a transaction', async (assert) => {
class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@column()
public email: string

@column()
public points: number
}

await db.insertQuery().table('users').insert({ username: 'virk' })
const trx = await db.transaction()

const user = await User.updateOrCreate({ username: 'nikk' }, { points: 20 }, { client: trx })

assert.isTrue(user.$persisted)
assert.equal(user.points, 20)
assert.equal(user.username, 'nikk')

await trx.rollback()

const users = await db.query().from('users')
assert.lengthOf(users, 1)

assert.equal(users[0].username, 'virk')
assert.equal(users[0].points, 0)
})
})

test.group('Base Model | hooks', (group) => {
Expand Down

0 comments on commit b957c6e

Please sign in to comment.