Skip to content

Commit

Permalink
fix(query): prefix table name to avoid ambiguous columns
Browse files Browse the repository at this point in the history
<!-- CLICK "Preview" FOR INSTRUCTIONS IN A MORE READABLE FORMAT -->

## Proposed changes

This fixes the "ambiguous column" error when adding a constraint on an eager load query where the constraint references the same table (for example when we want to add computational aggregation within the query) See the tests for more details.

## Types of changes

What types of changes does your code introduce?

_Put an `x` in the boxes that apply_

- [x] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## Checklist

_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._

- [x] I have read the [CONTRIBUTING](https://github.com/adonisjs/adonis-lucid/CONTRIBUTING.md) doc
- [x] Lint and unit tests pass locally with my changes
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] I have added necessary documentation (if appropriate)

## Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
  • Loading branch information
othierry authored and thetutlage committed Sep 1, 2018
1 parent 60619d2 commit 55fffb9
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/Lucid/Relations/BaseRelation.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class BaseRelation {
* @return {void}
*/
this._eagerLoadFn = function (query, fk, values) {
query.whereIn(fk, values)
query.whereIn(`${this.RelatedModel.table}.${fk}`, values)
}

/**
Expand Down
8 changes: 4 additions & 4 deletions test/unit/lucid-belongs-to.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ test.group('Relations | Belongs To', (group) => {
assert.equal(profiles.size(), 1)
assert.instanceOf(profiles.first().getRelated('user'), User)
assert.equal(profiles.first().getRelated('user').username, 'nikk')
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where "id" in (?)'))
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where `users`.`id` in (?)'))
assert.deepEqual(userQuery.bindings, helpers.formatBindings([2]))
})

Expand Down Expand Up @@ -189,7 +189,7 @@ test.group('Relations | Belongs To', (group) => {
assert.equal(profiles.first().getRelated('user').username, 'nikk')
assert.instanceOf(profiles.last().getRelated('user'), User)
assert.equal(profiles.last().getRelated('user').username, 'virk')
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where "id" in (?, ?)'))
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where `users`.`id` in (?, ?)'))
assert.deepEqual(userQuery.bindings, helpers.formatBindings([2, 1]))
})

Expand Down Expand Up @@ -639,7 +639,7 @@ test.group('Relations | Belongs To', (group) => {

await Car.query().with('user').fetch()

assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where "id" in (?)'))
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where `users`.`id` in (?)'))
assert.deepEqual(userQuery.bindings, helpers.formatBindings([1]))
})

Expand Down Expand Up @@ -872,7 +872,7 @@ test.group('Relations | Belongs To', (group) => {
await ioc.use('Database').table('cars').insert({ name: 'E180', model: 'Mercedes', user_id: 1 })

await Car.query().with('user').fetch()
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where "id" in (?) and "deleted_at" is null'))
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where `users`.`id` in (?) and "deleted_at" is null'))
})

test('apply global scope on related model when called withCount', async (assert) => {
Expand Down
56 changes: 46 additions & 10 deletions test/unit/lucid-has-many.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ test.group('Relations | Has Many', (group) => {
assert.instanceOf(user.getRelated('cars'), VanillaSerializer)
assert.equal(user.getRelated('cars').size(), 2)
assert.deepEqual(user.getRelated('cars').rows.map((car) => car.$parent), ['User', 'User'])
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "user_id" in (?)'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where `cars`.`user_id` in (?)'))
assert.deepEqual(carQuery.bindings, helpers.formatBindings([1]))
})

Expand Down Expand Up @@ -173,12 +173,48 @@ test.group('Relations | Has Many', (group) => {
builder.where('model', '>', '2000')
}).fetch()
const user = users.first()

assert.equal(user.getRelated('cars').size(), 1)
assert.equal(user.getRelated('cars').rows[0].name, 'audi')
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "model" > ? and "user_id" in (?)'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "model" > ? and `cars`.`user_id` in (?)'))
assert.deepEqual(carQuery.bindings, helpers.formatBindings(['2000', 1]))
})

test('add same table aggregation in constraints', async (assert) => {
class Car extends Model {
}

class User extends Model {
cars () {
return this.hasMany(Car)
}
}

Car._bootIfNotBooted()
User._bootIfNotBooted()

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

await ioc.use('Database').table('users').insert({ username: 'virk' })
await ioc.use('Database').table('cars').insert([
{ user_id: 1, name: 'merc', model: '1990' },
{ user_id: 1, name: 'audi', model: '2001' }
])

const users = await User.query().with('cars', (builder) => {
builder
.select('cars.*', ioc.use('Database').raw('count(`older_cars`.`id`) as older_cars_count'))
.joinRaw('left join cars older_cars on older_cars.model < cars.model')
.groupBy('cars.id')
}).fetch()
const user = users.first()
assert.equal(user.getRelated('cars').size(), 2)
assert.equal(user.getRelated('cars').rows[0].older_cars_count, '0')
assert.equal(user.getRelated('cars').rows[1].older_cars_count, '1')
assert.equal(carQuery.sql, helpers.formatQuery('select `cars`.*, count(`older_cars`.`id`) as older_cars_count from "cars" left join cars older_cars on older_cars.model < cars.model where `cars`.`user_id` in (?) group by `cars`.`id`'))
})

test('return serailizer instance when nothing exists', async (assert) => {
class Car extends Model {
}
Expand All @@ -199,7 +235,7 @@ test.group('Relations | Has Many', (group) => {
const users = await User.query().with('cars').fetch()
const user = users.first()
assert.equal(user.getRelated('cars').size(), 0)
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "user_id" in (?)'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where `cars`.`user_id` in (?)'))
assert.deepEqual(carQuery.bindings, helpers.formatBindings([1]))
})

Expand Down Expand Up @@ -319,8 +355,8 @@ test.group('Relations | Has Many', (group) => {
assert.equal(user.getRelated('cars').size(), 2)
assert.equal(user.getRelated('cars').first().getRelated('parts').size(), 2)
assert.equal(user.getRelated('cars').last().getRelated('parts').size(), 2)
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "user_id" in (?)'))
assert.equal(partQuery.sql, helpers.formatQuery('select * from "parts" where "car_id" in (?, ?)'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where `cars`.`user_id` in (?)'))
assert.equal(partQuery.sql, helpers.formatQuery('select * from "parts" where `parts`.`car_id` in (?, ?)'))
})

test('add query constraint to nested query', async (assert) => {
Expand Down Expand Up @@ -364,8 +400,8 @@ test.group('Relations | Has Many', (group) => {
assert.equal(user.getRelated('cars').size(), 2)
assert.equal(user.getRelated('cars').first().getRelated('parts').size(), 1)
assert.equal(user.getRelated('cars').last().getRelated('parts').size(), 1)
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "user_id" in (?)'))
assert.equal(partQuery.sql, helpers.formatQuery('select * from "parts" where "part_name" = ? and "car_id" in (?, ?)'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where `cars`.`user_id` in (?)'))
assert.equal(partQuery.sql, helpers.formatQuery('select * from "parts" where "part_name" = ? and `parts`.`car_id` in (?, ?)'))
})

test('add query constraint to child and grand child query', async (assert) => {
Expand Down Expand Up @@ -411,8 +447,8 @@ test.group('Relations | Has Many', (group) => {

assert.equal(user.getRelated('cars').size(), 1)
assert.equal(user.getRelated('cars').first().getRelated('parts').size(), 1)
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "name" = ? and "user_id" in (?)'))
assert.equal(partQuery.sql, helpers.formatQuery('select * from "parts" where "part_name" = ? and "car_id" in (?)'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "name" = ? and `cars`.`user_id` in (?)'))
assert.equal(partQuery.sql, helpers.formatQuery('select * from "parts" where "part_name" = ? and `parts`.`car_id` in (?)'))
})

test('get relation count', async (assert) => {
Expand Down Expand Up @@ -1035,7 +1071,7 @@ test.group('Relations | Has Many', (group) => {
await ioc.use('Database').table('users').insert([{ username: 'virk' }, { username: 'nikk' }])
await User.query().with('cars').fetch()

assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where "user_id" in (?, ?) and "deleted_at" is null'))
assert.equal(carQuery.sql, helpers.formatQuery('select * from "cars" where `cars`.`user_id` in (?, ?) and "deleted_at" is null'))
})

test('apply global scope on related model when called withCount', async (assert) => {
Expand Down
18 changes: 9 additions & 9 deletions test/unit/lucid-relations.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ test.group('Relations | HasOne', (group) => {
assert.instanceOf(result.rows[1].getRelated('profile'), Profile)
assert.equal(result.rows[0].getRelated('profile').profile_name, 'virk')
assert.equal(result.rows[1].getRelated('profile').profile_name, 'nikk')
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "user_id" in (?, ?)'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where `profiles`.`user_id` in (?, ?)'))
})

test('modify query builder when fetching relationships', async (assert) => {
Expand Down Expand Up @@ -490,7 +490,7 @@ test.group('Relations | HasOne', (group) => {
assert.instanceOf(result.rows[0].getRelated('profile'), Profile)
assert.isNull(result.rows[1].getRelated('profile'))
assert.equal(result.rows[0].getRelated('profile').profile_name, 'virk')
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "likes" > ? and "user_id" in (?, ?)'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "likes" > ? and `profiles`.`user_id` in (?, ?)'))
})

test('fetch nested relationships', async (assert) => {
Expand Down Expand Up @@ -524,8 +524,8 @@ test.group('Relations | HasOne', (group) => {

const user = await User.query().with('profile.picture').fetch()
assert.instanceOf(user.first().getRelated('profile').getRelated('picture'), Picture)
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "user_id" in (?)'))
assert.equal(pictureQuery.sql, helpers.formatQuery('select * from "pictures" where "profile_id" in (?)'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where `profiles`.`user_id` in (?)'))
assert.equal(pictureQuery.sql, helpers.formatQuery('select * from "pictures" where `pictures`.`profile_id` in (?)'))
})

test('add runtime constraints on nested relationships', async (assert) => {
Expand Down Expand Up @@ -561,8 +561,8 @@ test.group('Relations | HasOne', (group) => {
builder.where('storage_path', '/bar')
}).fetch()
assert.isNull(user.first().getRelated('profile').getRelated('picture'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "user_id" in (?)'))
assert.equal(pictureQuery.sql, helpers.formatQuery('select * from "pictures" where "storage_path" = ? and "profile_id" in (?)'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where `profiles`.`user_id` in (?)'))
assert.equal(pictureQuery.sql, helpers.formatQuery('select * from "pictures" where "storage_path" = ? and `pictures`.`profile_id` in (?)'))
})

test('add runtime constraints on child relationships and not grandchild', async (assert) => {
Expand Down Expand Up @@ -598,7 +598,7 @@ test.group('Relations | HasOne', (group) => {
builder.where('likes', '>', 3).with('picture')
}).fetch()
assert.isNull(user.first().getRelated('profile'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "likes" > ? and "user_id" in (?)'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "likes" > ? and `profiles`.`user_id` in (?)'))
assert.isNull(pictureQuery)
})

Expand Down Expand Up @@ -1216,7 +1216,7 @@ test.group('Relations | HasOne', (group) => {
assert.equal(users.first().getRelated('profile').picture_count, helpers.formatNumber(1))
assert.deepEqual(users.first().getRelated('profile').$sideLoaded, { picture_count: helpers.formatNumber(1) })
assert.equal(userQuery.sql, helpers.formatQuery('select * from "users"'))
assert.equal(profileQuery.sql, helpers.formatQuery('select *, (select count(*) from "pictures" where "profiles"."id" = "pictures"."profile_id") as "picture_count" from "profiles" where "user_id" in (?, ?)'))
assert.equal(profileQuery.sql, helpers.formatQuery('select *, (select count(*) from "pictures" where "profiles"."id" = "pictures"."profile_id") as "picture_count" from "profiles" where `profiles`.`user_id` in (?, ?)'))
})

test('eagerload when calling first', async (assert) => {
Expand Down Expand Up @@ -1675,7 +1675,7 @@ test.group('Relations | HasOne', (group) => {

await User.query().with('profile').fetch()

assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where "user_id" in (?, ?) and "deleted_at" is null'))
assert.equal(profileQuery.sql, helpers.formatQuery('select * from "profiles" where `profiles`.`user_id` in (?, ?) and "deleted_at" is null'))
})

test('apply global scope on related model when called withCount', async (assert) => {
Expand Down

0 comments on commit 55fffb9

Please sign in to comment.