Start implementation of model relations
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
80
src/orm/model/relation/HasOneOrMany.ts
Normal file
80
src/orm/model/relation/HasOneOrMany.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import {Model} from '../Model'
|
||||
import {Relation, RelationValue} from './Relation'
|
||||
import {RelationBuilder} from './RelationBuilder'
|
||||
import {raw} from '../../dialect/SQLDialect'
|
||||
import {AbstractBuilder} from '../../builder/AbstractBuilder'
|
||||
import {ModelBuilder} from '../ModelBuilder'
|
||||
import {Collection, toString} from '../../../util'
|
||||
|
||||
/**
|
||||
* Base class for 1:1 and 1:M relations.
|
||||
*/
|
||||
export abstract class HasOneOrMany<T extends Model<T>, T2 extends Model<T2>, V extends RelationValue<T2>> extends Relation<T, T2, V> {
|
||||
protected constructor(
|
||||
parent: T,
|
||||
related: T2,
|
||||
|
||||
/** Override the foreign key property. */
|
||||
protected foreignKeyOverride?: keyof T & string,
|
||||
|
||||
/** Override the local key property. */
|
||||
protected localKeyOverride?: keyof T2 & string,
|
||||
) {
|
||||
super(parent, related)
|
||||
}
|
||||
|
||||
/** Get the name of the foreign key for this relation. */
|
||||
public get foreignKey(): string {
|
||||
return this.foreignKeyOverride || this.parent.keyName()
|
||||
}
|
||||
|
||||
/** Get the name of the local key for this relation. */
|
||||
public get localKey(): string {
|
||||
return this.localKeyOverride || this.foreignKey
|
||||
}
|
||||
|
||||
/** Get the fully-qualified name of the foreign key. */
|
||||
public get qualifiedForeignKey(): string {
|
||||
return this.related.qualify(this.foreignKey)
|
||||
}
|
||||
|
||||
/** Get the fully-qualified name of the local key. */
|
||||
public get qualifiedLocalKey(): string {
|
||||
return this.related.qualify(this.localKey)
|
||||
}
|
||||
|
||||
/** Get the value of the pivot for this relation from the parent model. */
|
||||
public get parentValue(): any {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return this.parent[this.localKey]
|
||||
}
|
||||
|
||||
/** Create a new query for this relation. */
|
||||
public query(): RelationBuilder<T2> {
|
||||
return this.builder().select(raw('*'))
|
||||
}
|
||||
|
||||
/** Apply the relation's constraints on a model query. */
|
||||
public applyScope(where: AbstractBuilder<T2>): void {
|
||||
where.where(subq => {
|
||||
subq.where(this.qualifiedForeignKey, '=', this.parentValue)
|
||||
.whereRaw(this.qualifiedForeignKey, 'IS NOT', 'NULL')
|
||||
})
|
||||
}
|
||||
|
||||
/** Create an eager-load query matching this relation's models. */
|
||||
public buildEagerQuery(parentQuery: ModelBuilder<T>, result: Collection<T>): ModelBuilder<T2> {
|
||||
const keys = result.pluck(this.localKey as keyof T)
|
||||
.map(toString)
|
||||
.all()
|
||||
|
||||
return this.related.query()
|
||||
.whereIn(this.foreignKey, keys)
|
||||
}
|
||||
|
||||
/** Given a collection of results, filter out those that are relevant to this relation. */
|
||||
public matchResults(possiblyRelated: Collection<T>): Collection<T> {
|
||||
return possiblyRelated.where(this.foreignKey as keyof T, '=', this.parentValue)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user