Skip to content

Commit

Permalink
fix(belongsTo): ignore null bindings when eagerloading
Browse files Browse the repository at this point in the history
eagerloading will return null without reaching database, since null bindings throws exception
  • Loading branch information
thetutlage committed Sep 8, 2017
1 parent cd6041d commit c3b5da3
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/Lucid/Relations/BelongsTo.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,26 @@ const CE = require('../../Exceptions')
* @constructor
*/
class BelongsTo extends BaseRelation {
/**
* Returns the first row for the related model
*
* @method first
*
* @return {Object|Null}
*/
first () {
if (!this.parentInstance.$persisted) {
throw CE.RuntimeException.unSavedModel(this.parentInstance.constructor.name)
}

if (!this.$primaryKeyValue) {
return null
}

this._decorateQuery()
return this.relatedQuery.first()
}

/**
* Map values from model instances to an array. It is required
* to make `whereIn` query when eagerloading results.
Expand Down
101 changes: 101 additions & 0 deletions test/unit/lucid-belongs-to.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* file that was distributed with this source code.
*/

require('../../lib/iocResolver').setFold(require('@adonisjs/fold'))
const test = require('japa')
const fs = require('fs-extra')
const path = require('path')
Expand Down Expand Up @@ -634,4 +635,104 @@ test.group('Relations | Belongs To', (group) => {
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where "id" in (?)'))
assert.deepEqual(userQuery.bindings, helpers.formatBindings([1]))
})

test('do not load relation with null value in foreign key', async (assert) => {
class User extends Model {
}

class Car extends Model {
user () {
return this.belongsTo(User)
}
}

User._bootIfNotBooted()
Car._bootIfNotBooted()

let userQuery = null
let carQuery = null
User.onQuery((query) => (userQuery = query))
Car.onQuery((query) => (carQuery = query))

await ioc.use('Database').table('users').insert({ username: 'virk' })
await ioc.use('Database').table('cars').insert({ name: 'E180', model: 'Mercedes', user_id: null })

const car = await Car.query().select(['id', 'name', 'user_id']).where('id', 1).first()
await car.load('user')
const json = car.toJSON()

assert.deepEqual(json, {
id: 1,
name: 'E180',
user: null,
user_id: null
})

assert.equal(userQuery, null)
assert.equal(carQuery.sql, helpers.formatQuery('select "id", "name", "user_id" from "cars" where "id" = ? limit ?'))
assert.deepEqual(carQuery.bindings, helpers.formatBindings([1, 1]))
})

test('do not eager load relation with null value in foreign key', async (assert) => {
class User extends Model {
}

class Car extends Model {
user () {
return this.belongsTo(User)
}
}

User._bootIfNotBooted()
Car._bootIfNotBooted()

let userQuery = null
let carQuery = null
User.onQuery((query) => (userQuery = query))
Car.onQuery((query) => (carQuery = query))

await ioc.use('Database').table('users').insert({ username: 'virk' })
await ioc.use('Database').table('cars').insert({ name: 'E180', model: 'Mercedes', user_id: null })

const car = await Car
.query()
.select(['id', 'name', 'user_id'])
.where('id', 1)
.with('user')
.first()

const json = car.toJSON()

assert.deepEqual(json, {
id: 1,
name: 'E180',
user: null,
user_id: null
})

assert.equal(userQuery, null)
assert.equal(carQuery.sql, helpers.formatQuery('select "id", "name", "user_id" from "cars" where "id" = ? limit ?'))
assert.deepEqual(carQuery.bindings, helpers.formatBindings([1, 1]))
})

test('throw exception when not eagerloading', async (assert) => {
class User extends Model {
}

class Car extends Model {
user () {
return this.belongsTo(User)
}
}

User._bootIfNotBooted()
Car._bootIfNotBooted()

await ioc.use('Database').table('users').insert({ username: 'virk' })
await ioc.use('Database').table('cars').insert({ name: 'E180', model: 'Mercedes', user_id: null })

const car = await Car.query().where('id', 1).first()
const fn = () => car.user().toSQL()
assert.throw(fn, 'E_UNSAVED_MODEL_INSTANCE: Cannot process relation, since Car model is not persisted to database or relational value is undefined')
})
})

0 comments on commit c3b5da3

Please sign in to comment.