Skip to content

Commit

Permalink
feat: pass sideloaded values to preloaded relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Oct 4, 2019
1 parent 4fcc600 commit 92c10de
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/Orm/BaseModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,7 @@ export class BaseModel implements ModelContract {
preloader.preload(relationName, callback)
}

preloader.sideload(this.$sideloaded)
await preloader.processAllForOne(this, constructor.query(this.$options).client)
}

Expand Down
20 changes: 19 additions & 1 deletion src/Orm/Preloader/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import { Exception } from '@poppinss/utils'
import {
ModelObject,
ModelContract,
RelationContract,
PreloaderContract,
Expand All @@ -32,6 +33,11 @@ type PreloadNode = {
* a model
*/
export class Preloader implements PreloaderContract {
/**
* Sideloaded attributes that will be passed to the model instances
*/
private _sideloaded: ModelObject = {}

/**
* Registered preloads
*/
Expand Down Expand Up @@ -60,7 +66,11 @@ export class Preloader implements PreloaderContract {
/**
* Pass nested preloads
*/
preload.children.forEach(({ relationName, callback }) => query.preload(relationName, callback))
preload.children.forEach(({ relationName, callback }) => {
query.preload(relationName, callback)
})

query.sideload(this._sideloaded)

/**
* Invoke callback when defined
Expand Down Expand Up @@ -106,6 +116,14 @@ export class Preloader implements PreloaderContract {
}
}

/**
* Set sideloaded properties to be passed to the model instance
*/
public sideload (value: any) {
this._sideloaded = value
return this
}

/**
* Define relationship to be preloaded
*/
Expand Down
6 changes: 4 additions & 2 deletions src/Orm/QueryBuilder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { trait } from '@poppinss/traits'
import { Exception } from '@poppinss/utils'

import {
ModelObject,
ModelOptions,
ModelConstructorContract,
ModelQueryBuilderContract,
Expand All @@ -36,7 +37,7 @@ export class ModelQueryBuilder extends Chainable implements ModelQueryBuilderCon
/**
* Sideloaded attributes that will be passed to the model instances
*/
private _sideloaded = {}
private _sideloaded: ModelObject = {}

/**
* A copy of defined preloads on the model instance
Expand Down Expand Up @@ -76,14 +77,15 @@ export class ModelQueryBuilder extends Chainable implements ModelQueryBuilderCon
this.clientOptions,
)

this._preloader.sideload(this._sideloaded)
await this._preloader.processAllForMany(modelInstances, this.client)
return modelInstances
}

/**
* Set sideloaded properties to be passed to the model instance
*/
public sideload (value: any) {
public sideload (value: ModelObject) {
this._sideloaded = value
return this
}
Expand Down
230 changes: 229 additions & 1 deletion test/orm/base-model-options.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ test.group('Model options | Model.firstOrSave', (group) => {
})
})

test.group('Model options | Preloads', (group) => {
test.group('Model options | Query Builder Preloads', (group) => {
group.before(async () => {
db = getDb()
BaseModel = getBaseModel(ormAdapter(db))
Expand Down Expand Up @@ -658,4 +658,232 @@ test.group('Model options | Preloads', (group) => {
assert.equal(users[0].profile.$options!.connection, 'primary')
assert.deepEqual(users[0].profile.$options!.profiler, profiler)
})

test('pass sideloaded data to preloads', async (assert) => {
class Profile extends BaseModel {
@column({ primary: true })
public id: number

@column()
public userId: number

@column()
public displayName: string
}

class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@hasOne(() => Profile)
public profile: Profile
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ user_id: 1, display_name: 'Virk' })

const users = await User.query().sideload({ id: 1 }).preload('profile').exec()

assert.lengthOf(users, 1)

assert.equal(users[0].$options!.connection, 'primary')
assert.deepEqual(users[0].$sideloaded, { id: 1 })
assert.deepEqual(users[0].profile.$sideloaded, { id: 1 })
})

test('custom sideloaded data on preload query must win', async (assert) => {
class Profile extends BaseModel {
@column({ primary: true })
public id: number

@column()
public userId: number

@column()
public displayName: string
}

class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@hasOne(() => Profile)
public profile: Profile
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ user_id: 1, display_name: 'Virk' })

const users = await User.query().sideload({ id: 1 }).preload('profile', (builder) => {
builder.sideload({ id: 2 })
}).exec()

assert.lengthOf(users, 1)

assert.equal(users[0].$options!.connection, 'primary')
assert.deepEqual(users[0].$sideloaded, { id: 1 })
assert.deepEqual(users[0].profile.$sideloaded, { id: 2 })
})
})

test.group('Model options | Model Preloads', (group) => {
group.before(async () => {
db = getDb()
BaseModel = getBaseModel(ormAdapter(db))
await setup()
})

group.after(async () => {
await cleanup()
await db.manager.closeAll()
})

group.afterEach(async () => {
await resetTables()
})

test('pass query options to preloaded models', async (assert) => {
class Profile extends BaseModel {
@column({ primary: true })
public id: number

@column()
public userId: number

@column()
public displayName: string
}

class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@hasOne(() => Profile)
public profile: Profile
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ user_id: 1, display_name: 'Virk' })

const user = await User.query({ connection: 'secondary' }).firstOrFail()
assert.equal(user.$options!.connection, 'secondary')

await user.preload('profile')

assert.equal(user.profile.$options!.connection, 'secondary')
assert.instanceOf(user.profile.$options!.profiler, Profiler)
})

test('pass profiler to preload models', async (assert) => {
class Profile extends BaseModel {
@column({ primary: true })
public id: number

@column()
public userId: number

@column()
public displayName: string
}

class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@hasOne(() => Profile)
public profile: Profile
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ user_id: 1, display_name: 'Virk' })

const profiler = new Profiler({})
const user = await User.query({ profiler }).firstOrFail()

assert.equal(user.$options!.connection, 'primary')
assert.deepEqual(user.$options!.profiler, profiler)

await user.preload('profile')

assert.equal(user.profile.$options!.connection, 'primary')
assert.deepEqual(user.profile.$options!.profiler, profiler)
})

test('pass sideloaded data to preloads', async (assert) => {
class Profile extends BaseModel {
@column({ primary: true })
public id: number

@column()
public userId: number

@column()
public displayName: string
}

class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@hasOne(() => Profile)
public profile: Profile
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ user_id: 1, display_name: 'Virk' })

const user = await User.query().sideload({ id: 1 }).firstOrFail()
assert.deepEqual(user.$sideloaded, { id: 1 })

await user.preload('profile')
assert.deepEqual(user.profile.$sideloaded, { id: 1 })
})

test('custom sideloaded data on preload query must win', async (assert) => {
class Profile extends BaseModel {
@column({ primary: true })
public id: number

@column()
public userId: number

@column()
public displayName: string
}

class User extends BaseModel {
@column({ primary: true })
public id: number

@column()
public username: string

@hasOne(() => Profile)
public profile: Profile
}

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.insertQuery().table('profiles').insert({ user_id: 1, display_name: 'Virk' })

const user = await User.query().sideload({ id: 1 }).firstOrFail()
assert.deepEqual(user.$sideloaded, { id: 1 })

await user.preload('profile', (query) => query.sideload({ id: 2 }))
assert.deepEqual(user.profile.$sideloaded, { id: 2 })
})
})

0 comments on commit 92c10de

Please sign in to comment.