Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/orm/relations/has_many/query_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { type LucidRow, type LucidModel } from '../../../types/model.js'
import { type HasManyQueryBuilderContract } from '../../../types/relations.js'

import { type HasMany } from './index.js'
import { getValue, unique } from '../../../utils/index.js'
import { getNullableValue, unique } from '../../../utils/index.js'
import { BaseQueryBuilder } from '../base/query_builder.js'

/**
Expand Down Expand Up @@ -101,9 +101,11 @@ export class HasManyQueryBuilder
this.wrapExisting().whereIn(
this.relation.foreignKey,
unique(
this.parent.map((model) => {
return getValue(model, this.relation.localKey, this.relation, queryAction)
})
this.parent
.map((model) => {
return getNullableValue(model, this.relation.localKey, this.relation, queryAction)
})
.filter((value) => value !== null)
)
)
return
Expand All @@ -112,7 +114,12 @@ export class HasManyQueryBuilder
/**
* Query constraints
*/
const value = getValue(this.parent, this.relation.localKey, this.relation, queryAction)
const value = getNullableValue(this.parent, this.relation.localKey, this.relation, queryAction)
if (value === null) {
this.wrapExisting().whereIn(this.relation.foreignKey, [])
return
}

this.wrapExisting().where(this.relation.foreignKey, value)
}

Expand Down
17 changes: 12 additions & 5 deletions src/orm/relations/has_many_through/query_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { type LucidRow, type LucidModel } from '../../../types/model.js'
import { type HasManyThroughQueryBuilderContract } from '../../../types/relations.js'

import { type HasManyThrough } from './index.js'
import { getValue, unique } from '../../../utils/index.js'
import { getNullableValue, unique } from '../../../utils/index.js'
import { BaseQueryBuilder } from '../base/query_builder.js'

/**
Expand Down Expand Up @@ -81,9 +81,11 @@ export class HasManyThroughQueryBuilder
builder.whereIn(
this.prefixThroughTable(this.relation.foreignKeyColumnName),
unique(
this.parent.map((model) => {
return getValue(model, this.relation.localKey, this.relation, queryAction)
})
this.parent
.map((model) => {
return getNullableValue(model, this.relation.localKey, this.relation, queryAction)
})
.filter((value) => value !== null)
)
)
return
Expand All @@ -92,7 +94,12 @@ export class HasManyThroughQueryBuilder
/**
* Query constraints
*/
const value = getValue(this.parent, this.relation.localKey, this.relation, queryAction)
const value = getNullableValue(this.parent, this.relation.localKey, this.relation, queryAction)
if (value === null) {
builder.whereIn(this.prefixThroughTable(this.relation.foreignKeyColumnName), [])
return
}

builder.where(this.prefixThroughTable(this.relation.foreignKeyColumnName), value)
}

Expand Down
18 changes: 12 additions & 6 deletions src/orm/relations/has_one/query_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { type LucidRow } from '../../../types/model.js'
import { type QueryClientContract } from '../../../types/database.js'

import { type HasOne } from './index.js'
import { getValue, unique } from '../../../utils/index.js'
import { getNullableValue, unique } from '../../../utils/index.js'
import { BaseQueryBuilder } from '../base/query_builder.js'

/**
Expand Down Expand Up @@ -96,9 +96,11 @@ export class HasOneQueryBuilder extends BaseQueryBuilder {
this.wrapExisting().whereIn(
this.relation.foreignKey,
unique(
this.parent.map((model) => {
return getValue(model, this.relation.localKey, this.relation, queryAction)
})
this.parent
.map((model) => {
return getNullableValue(model, this.relation.localKey, this.relation, queryAction)
})
.filter((value) => value !== null)
)
)
return
Expand All @@ -107,8 +109,12 @@ export class HasOneQueryBuilder extends BaseQueryBuilder {
/**
* Query constraints
*/
const value = getValue(this.parent, this.relation.localKey, this.relation, queryAction)
this.wrapExisting().where(this.relation.foreignKey, value)
const value = getNullableValue(this.parent, this.relation.localKey, this.relation, queryAction)
if (value === null) {
this.wrapExisting().whereIn(this.relation.foreignKey, [])
} else {
this.wrapExisting().where(this.relation.foreignKey, value)
}

/**
* Do not add limit when updating or deleting
Expand Down
17 changes: 12 additions & 5 deletions src/orm/relations/many_to_many/query_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { type ManyToManyQueryBuilderContract } from '../../../types/relations.js

import { type ManyToMany } from './index.js'
import { PivotHelpers } from './pivot_helpers.js'
import { getValue, unique } from '../../../utils/index.js'
import { getNullableValue, unique } from '../../../utils/index.js'
import { BaseQueryBuilder } from '../base/query_builder.js'

/**
Expand Down Expand Up @@ -115,9 +115,11 @@ export class ManyToManyQueryBuilder
this.wrapExisting().whereInPivot(
this.relation.pivotForeignKey,
unique(
this.parent.map((model) => {
return getValue(model, this.relation.localKey, this.relation, queryAction)
})
this.parent
.map((model) => {
return getNullableValue(model, this.relation.localKey, this.relation, queryAction)
})
.filter((value) => value !== null)
)
)
return
Expand All @@ -126,7 +128,12 @@ export class ManyToManyQueryBuilder
/**
* Query constraints
*/
const value = getValue(this.parent, this.relation.localKey, this.relation, queryAction)
const value = getNullableValue(this.parent, this.relation.localKey, this.relation, queryAction)
if (value === null) {
this.wrapExisting().whereInPivot(this.relation.pivotForeignKey, [])
return
}

this.wrapExisting().wherePivot(this.relation.pivotForeignKey, value)
}

Expand Down
23 changes: 23 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,29 @@ export function getValue(
})
}

/**
* Same as "getValue", but returns null instead of raising when the key
* value is null.
*
* A null key is a legitimate value: the row simply has no related rows.
* Only undefined is a programmer error, where the column was never
* selected. This mirrors how belongsTo already treats a nullable foreign
* key.
*/
export function getNullableValue(
model: LucidRow | ModelObject,
key: string,
relation: RelationshipsContract,
action = 'preload'
) {
const value = (model as ModelObject)[key]
if (value === undefined) {
return getValue(model, key, relation, action)
}

return value
}

/**
* Helper to find if value is a valid Object or
* not
Expand Down
Loading