Skip to content

Commit

Permalink
Showing 3 changed files with 205 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/Lucid/Relations/BelongsToMany.js
Original file line number Diff line number Diff line change
@@ -605,6 +605,11 @@ class BelongsToMany extends BaseRelation {
return this.relatedQuery.query
}

addWhereOn (context) {
this._makeJoinQuery()
context.on(`${this.$primaryTable}.${this.primaryKey}`, '=', `${this.$pivotTable}.${this.foreignKey}`)
}

/**
* Attach existing rows inside pivot table as a relationship
*
26 changes: 25 additions & 1 deletion test/unit/helpers/index.js
Original file line number Diff line number Diff line change
@@ -140,6 +140,27 @@ module.exports = {
table.string('name')
table.timestamps()
table.timestamp('deleted_at').nullable()
}),
db.schema.createTable('categories', function (table) {
table.increments('id')
table.string('name')
table.timestamps()
table.timestamp('deleted_at').nullable()
}),
db.schema.createTable('sections', function (table) {
table.increments('id')
table.integer('category_id')
table.string('name')
table.boolean('is_active')
table.timestamps()
table.timestamp('deleted_at').nullable()
}),
db.schema.createTable('post_section', function (table) {
table.increments('id')
table.integer('post_id')
table.integer('section_id')
table.timestamps()
table.timestamp('deleted_at').nullable()
})
])
},
@@ -155,7 +176,10 @@ module.exports = {
db.schema.dropTable('my_users'),
db.schema.dropTable('posts'),
db.schema.dropTable('post_user'),
db.schema.dropTable('countries')
db.schema.dropTable('countries'),
db.schema.dropTable('categories'),
db.schema.dropTable('sections'),
db.schema.dropTable('post_section')
])
},

197 changes: 175 additions & 22 deletions test/unit/lucid-has-many-through.spec.js
Original file line number Diff line number Diff line change
@@ -482,43 +482,196 @@ test.group('Relations | Has Many Through - Belongs To', (group) => {
assert.equal(countries.first().getRelated('users').size(), 2)
assert.equal(countries.last().getRelated('users').size(), 1)
})
})

test.group('Relations | Has Many Through - Belongs To Many', (group) => {
group.before(async () => {
ioc.singleton('Adonis/Src/Database', function () {
const config = new Config()
config.set('database', {
connection: 'testing',
testing: helpers.getConfig()
})
return new DatabaseManager(config)
})
ioc.alias('Adonis/Src/Database', 'Database')

await fs.ensureDir(path.join(__dirname, './tmp'))
await helpers.createTables(ioc.use('Adonis/Src/Database'))
})

group.afterEach(async () => {
await ioc.use('Adonis/Src/Database').table('categories').truncate()
await ioc.use('Adonis/Src/Database').table('sections').truncate()
await ioc.use('Adonis/Src/Database').table('posts').truncate()
await ioc.use('Adonis/Src/Database').table('post_section').truncate()
})

group.after(async () => {
await helpers.dropTables(ioc.use('Adonis/Src/Database'))
ioc.use('Database').close()
try {
await fs.remove(path.join(__dirname, './tmp'))
} catch (error) {
if (process.platform !== 'win32' || error.code !== 'EBUSY') {
throw error
}
}
}).timeout(0)

test('create correct query', (assert) => {
class Post extends Model {
}

class Section extends Model {
posts () {
return this.belongsToMany(Post)
}
}

class Category extends Model {
posts () {
return this.manyThrough(Section, 'posts')
}
}

Category._bootIfNotBooted()
Section._bootIfNotBooted()
Post._bootIfNotBooted()

const category = new Category()
category.id = 1
category.$persisted = true

const query = category.posts().toSQL()
assert.equal(query.sql, helpers.formatQuery('select "posts".* from "posts" inner join "post_section" on "posts"."id" = "post_section"."post_id" inner join "sections" on "sections"."id" = "post_section"."section_id" where "sections"."category_id" = ?'))
})

test('selected related rows', async (assert) => {
class Post extends Model {
}

class Section extends Model {
posts () {
return this.belongsToMany(Post)
}
}

class Category extends Model {
posts () {
return this.manyThrough(Section, 'posts')
}
}

Category._bootIfNotBooted()
Section._bootIfNotBooted()
Post._bootIfNotBooted()

await ioc.use('Database').table('categories').insert([{ name: 'Sql' }, { name: 'Javascript' }])
await ioc.use('Database').table('sections').insert([
{ name: 'Loops', category_id: 2 },
{ name: 'Conditionals', category_id: 2 }
])
await ioc.use('Database').table('posts').insert({ title: 'For each loop' })
await ioc.use('Database').table('post_section').insert({ post_id: 1, section_id: 1 })

const js = await Category.find(2)
const posts = await js.posts().fetch()
assert.equal(posts.size(), 1)
assert.equal(posts.rows[0].title, 'For each loop')
})

test('eagerload related rows', async (assert) => {
class User extends Model {
class Post extends Model {
}

class Profile extends Model {
user () {
return this.belongsTo(User)
class Section extends Model {
posts () {
return this.belongsToMany(Post)
}
}

class Country extends Model {
users () {
return this.manyThrough(Profile, 'user')
class Category extends Model {
posts () {
return this.manyThrough(Section, 'posts')
}
}

User._bootIfNotBooted()
Country._bootIfNotBooted()
Profile._bootIfNotBooted()
Category._bootIfNotBooted()
Section._bootIfNotBooted()
Post._bootIfNotBooted()

await ioc.use('Database').table('countries').insert([{ name: 'India', id: 2 }, { name: 'Uk', id: 3 }])
await ioc.use('Database').table('categories').insert([{ name: 'Sql' }, { name: 'Javascript' }])

await ioc.use('Database').table('users').insert([
{ username: 'virk' },
{ username: 'nikk' }
await ioc.use('Database').table('sections').insert([
{ name: 'Loops', category_id: 2 },
{ name: 'Conditionals', category_id: 2 },
{ name: 'Transactions', category_id: 1 }
])

await ioc.use('Database').table('profiles').insert([
{ user_id: 1, profile_name: 'Virk', country_id: 2 },
{ user_id: 1, profile_name: 'Virk', country_id: 3 },
{ user_id: 2, profile_name: 'Nikk', country_id: 2 }
await ioc.use('Database').table('posts').insert([{ title: 'For each loop' }, { title: 'Transactions 101' }])

await ioc.use('Database').table('post_section').insert([
{ post_id: 1, section_id: 1 },
{ post_id: 2, section_id: 3 }
])

const countries = await Country.query().with('users').orderBy('id', 'asc').fetch()
assert.equal(countries.size(), 2)
assert.equal(countries.first().getRelated('users').size(), 2)
assert.equal(countries.last().getRelated('users').size(), 1)
const categories = await Category.query().with('posts').orderBy('id', 'asc').fetch()
assert.instanceOf(categories, VanillaSerializer)
assert.equal(categories.size(), 2)
assert.equal(categories.last().getRelated('posts').size(), 1)
assert.equal(categories.last().getRelated('posts').toJSON()[0].title, 'For each loop')
assert.equal(categories.first().getRelated('posts').size(), 1)
assert.equal(categories.first().getRelated('posts').toJSON()[0].title, 'Transactions 101')
})

test('add constraints when eager loading', async (assert) => {
class Post extends Model {
}

class Section extends Model {
posts () {
return this.belongsToMany(Post)
}
}

class Category extends Model {
posts () {
return this.manyThrough(Section, 'posts')
}
}

Category._bootIfNotBooted()
Section._bootIfNotBooted()
Post._bootIfNotBooted()

let postsQuery = null
Post.onQuery((query) => (postsQuery = query))

await ioc.use('Database').table('categories').insert([{ name: 'Sql' }, { name: 'Javascript' }])

await ioc.use('Database').table('sections').insert([
{ name: 'Loops', category_id: 2, is_active: true },
{ name: 'Conditionals', category_id: 2, is_active: true },
{ name: 'Transactions', category_id: 1 }
])

await ioc.use('Database').table('posts').insert([{ title: 'For each loop' }, { title: 'Transactions 101' }])

await ioc.use('Database').table('post_section').insert([
{ post_id: 1, section_id: 1 },
{ post_id: 2, section_id: 3 }
])

const categories = await Category.query().with('posts', (builder) => {
builder.where('sections.is_active', true)
}).orderBy('id', 'asc').fetch()

assert.equal(postsQuery.sql, helpers.formatQuery('select "posts".*, "sections"."category_id" as "through_category_id" from "posts" inner join "post_section" on "posts"."id" = "post_section"."post_id" inner join "sections" on "sections"."id" = "post_section"."section_id" where "sections"."is_active" = ? and "sections"."category_id" in (?, ?)'))
assert.instanceOf(categories, VanillaSerializer)
assert.equal(categories.size(), 2)
assert.equal(categories.last().getRelated('posts').size(), 1)
assert.equal(categories.last().getRelated('posts').toJSON()[0].title, 'For each loop')
assert.equal(categories.first().getRelated('posts').size(), 0)
})
})

0 comments on commit 4b3380c

Please sign in to comment.