@athenna/database
Advanced tools
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { HasManyThroughOptions } from '#src/types/relations/HasManyThroughOptions'; | ||
| /** | ||
| * Create has many through relation for model class. | ||
| */ | ||
| export declare function HasManyThrough<T extends BaseModel = any, R extends BaseModel = any, H extends BaseModel = any>(model: (() => new () => R) | string, through: (() => new () => H) | string, options?: Omit<HasManyThroughOptions<T, R, H>, 'type' | 'model' | 'through' | 'property'>): (target: T, key: any) => void; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| import { Is, Options } from '@athenna/common'; | ||
| /** | ||
| * Create has many through relation for model class. | ||
| */ | ||
| export function HasManyThrough(model, through, options = {}) { | ||
| return (target, key) => { | ||
| const Target = target.constructor; | ||
| options = Options.create(options, { | ||
| isIncluded: false, | ||
| inverse: false | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.type = 'hasManyThrough'; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.model = Is.String(model) | ||
| ? () => ioc.safeUse(`App/Models/${model}`).constructor | ||
| : model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.through = Is.String(through) | ||
| ? () => ioc.safeUse(`App/Models/${through}`).constructor | ||
| : through; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| debug('registering hasManyThrough metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineHasManyThroughMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { HasOneThroughOptions } from '#src/types/relations/HasOneThroughOptions'; | ||
| /** | ||
| * Create has one through relation for model class. | ||
| */ | ||
| export declare function HasOneThrough<T extends BaseModel = any, R extends BaseModel = any, H extends BaseModel = any>(model: (() => new () => R) | string, through: (() => new () => H) | string, options?: Omit<HasOneThroughOptions<T, R, H>, 'type' | 'model' | 'through' | 'property'>): (target: T, key: any) => void; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| import { Is, Options } from '@athenna/common'; | ||
| /** | ||
| * Create has one through relation for model class. | ||
| */ | ||
| export function HasOneThrough(model, through, options = {}) { | ||
| return (target, key) => { | ||
| const Target = target.constructor; | ||
| options = Options.create(options, { | ||
| isIncluded: false, | ||
| inverse: false | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.type = 'hasOneThrough'; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.model = Is.String(model) | ||
| ? () => ioc.safeUse(`App/Models/${model}`).constructor | ||
| : model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.through = Is.String(through) | ||
| ? () => ioc.safeUse(`App/Models/${through}`).constructor | ||
| : through; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| debug('registering hasOneThrough metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineHasOneThroughMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { HasManyThroughOptions } from '#src/types'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export declare class HasManyThroughRelation { | ||
| /** | ||
| * Get the options with defined default values. | ||
| */ | ||
| static options(Parent: typeof BaseModel, relation: HasManyThroughOptions): HasManyThroughOptions; | ||
| /** | ||
| * Load a has many through relation. | ||
| */ | ||
| static load(model: BaseModel, relation: HasManyThroughOptions): Promise<any>; | ||
| /** | ||
| * Load all models that has many through relation. | ||
| */ | ||
| static loadAll(models: BaseModel[], relation: HasManyThroughOptions): Promise<any[]>; | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has many through relations. | ||
| */ | ||
| static whereHas(Model: typeof BaseModel, query: Driver, relation: HasManyThroughOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { String } from '@athenna/common'; | ||
| export class HasManyThroughRelation { | ||
| /** | ||
| * Get the options with defined default values. | ||
| */ | ||
| static options(Parent, relation) { | ||
| const Through = relation.through(); | ||
| const Final = relation.model(); | ||
| relation.localKey = | ||
| relation.localKey || Parent.schema().getMainPrimaryKeyProperty(); | ||
| relation.firstKey = | ||
| relation.firstKey || `${String.toCamelCase(Parent.name)}Id`; | ||
| if (relation.inverse) { | ||
| relation.secondLocalKey = | ||
| relation.secondLocalKey || `${String.toCamelCase(Final.name)}Id`; | ||
| relation.secondKey = | ||
| relation.secondKey || Final.schema().getMainPrimaryKeyProperty(); | ||
| } | ||
| else { | ||
| relation.secondLocalKey = | ||
| relation.secondLocalKey || Through.schema().getMainPrimaryKeyProperty(); | ||
| relation.secondKey = | ||
| relation.secondKey || `${String.toCamelCase(Through.name)}Id`; | ||
| } | ||
| return relation; | ||
| } | ||
| /** | ||
| * Load a has many through relation. | ||
| */ | ||
| static async load(model, relation) { | ||
| this.options(model.constructor, relation); | ||
| const throughRows = await relation | ||
| .through() | ||
| .query() | ||
| .where(relation.firstKey, model[relation.localKey]) | ||
| .findMany(); | ||
| const linkValues = throughRows | ||
| .map(r => r[relation.secondLocalKey]) | ||
| .filter(v => v !== undefined && v !== null); | ||
| if (!linkValues.length) { | ||
| model[relation.property] = []; | ||
| return model; | ||
| } | ||
| model[relation.property] = await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.secondKey, linkValues) | ||
| .when(relation.withClosure, relation.withClosure) | ||
| .findMany(); | ||
| return model; | ||
| } | ||
| /** | ||
| * Load all models that has many through relation. | ||
| */ | ||
| static async loadAll(models, relation) { | ||
| if (!models.length) { | ||
| return models; | ||
| } | ||
| this.options(models[0].constructor, relation); | ||
| const Final = relation.model(); | ||
| const finalPK = Final.schema().getMainPrimaryKeyProperty(); | ||
| const parentValues = models.map(m => m[relation.localKey]); | ||
| const throughRows = await relation | ||
| .through() | ||
| .query() | ||
| .whereIn(relation.firstKey, parentValues) | ||
| .findMany(); | ||
| const parentToLinks = new Map(); | ||
| const allLinks = []; | ||
| for (const t of throughRows) { | ||
| const link = t[relation.secondLocalKey]; | ||
| if (link === undefined || link === null) { | ||
| continue; | ||
| } | ||
| allLinks.push(link); | ||
| const arr = parentToLinks.get(t[relation.firstKey]) || []; | ||
| arr.push(link); | ||
| parentToLinks.set(t[relation.firstKey], arr); | ||
| } | ||
| const finals = allLinks.length | ||
| ? await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.secondKey, allLinks) | ||
| .when(relation.withClosure, relation.withClosure) | ||
| .findMany() | ||
| : []; | ||
| const linkToFinals = new Map(); | ||
| for (const f of finals) { | ||
| const arr = linkToFinals.get(f[relation.secondKey]) || []; | ||
| arr.push(f); | ||
| linkToFinals.set(f[relation.secondKey], arr); | ||
| } | ||
| return models.map(m => { | ||
| const links = parentToLinks.get(m[relation.localKey]) || []; | ||
| const collected = []; | ||
| const seen = new Set(); | ||
| for (const link of links) { | ||
| const matches = linkToFinals.get(link) || []; | ||
| for (const f of matches) { | ||
| const pk = f[finalPK]; | ||
| if (seen.has(pk)) { | ||
| continue; | ||
| } | ||
| seen.add(pk); | ||
| collected.push(f); | ||
| } | ||
| } | ||
| m[relation.property] = collected; | ||
| return m; | ||
| }); | ||
| } | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has many through relations. | ||
| */ | ||
| static whereHas(Model, query, relation) { | ||
| this.options(Model, relation); | ||
| const Through = relation.through(); | ||
| const Final = relation.model(); | ||
| const modelTable = Model.table(); | ||
| const throughTable = Through.table(); | ||
| const finalTable = Final.table(); | ||
| const modelLocal = Model.schema().getColumnNameByProperty(relation.localKey) || | ||
| Model.schema().getMainPrimaryKeyName(); | ||
| const throughFK = Through.schema().getColumnNameByProperty(relation.firstKey) || | ||
| Through.schema().getColumnNameByProperty(`${String.toCamelCase(Model.name)}Id`); | ||
| const throughLink = Through.schema().getColumnNameByProperty(relation.secondLocalKey); | ||
| const finalLink = Final.schema().getColumnNameByProperty(relation.secondKey); | ||
| let outerWhereRaw = `${throughTable}.${throughFK} = ${modelTable}.${modelLocal}`; | ||
| switch (Through.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| outerWhereRaw = `"${throughTable}"."${throughFK}" = "${modelTable}"."${modelLocal}"`; | ||
| } | ||
| Through.query() | ||
| .setDriver(query, throughTable) | ||
| .whereRaw(outerWhereRaw) | ||
| .whereExists(innerQuery => { | ||
| let innerWhereRaw = `${finalTable}.${finalLink} = ${throughTable}.${throughLink}`; | ||
| switch (Final.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| innerWhereRaw = `"${finalTable}"."${finalLink}" = "${throughTable}"."${throughLink}"`; | ||
| } | ||
| Final.query() | ||
| .setDriver(innerQuery, finalTable) | ||
| .whereRaw(innerWhereRaw) | ||
| .when(relation.closure, relation.closure); | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { HasOneThroughOptions } from '#src/types'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export declare class HasOneThroughRelation { | ||
| /** | ||
| * Load a has one through relation. | ||
| */ | ||
| static load(model: BaseModel, relation: HasOneThroughOptions): Promise<any>; | ||
| /** | ||
| * Load all models that has one through relation. | ||
| */ | ||
| static loadAll(models: BaseModel[], relation: HasOneThroughOptions): Promise<any[]>; | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has one through relation. | ||
| */ | ||
| static whereHas(Model: typeof BaseModel, query: Driver, relation: HasOneThroughOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { HasManyThroughRelation } from '#src/models/relations/HasManyThrough/HasManyThroughRelation'; | ||
| export class HasOneThroughRelation { | ||
| /** | ||
| * Load a has one through relation. | ||
| */ | ||
| static async load(model, relation) { | ||
| await HasManyThroughRelation.load(model, relation); | ||
| const arr = model[relation.property] || []; | ||
| model[relation.property] = arr[0] ?? null; | ||
| return model; | ||
| } | ||
| /** | ||
| * Load all models that has one through relation. | ||
| */ | ||
| static async loadAll(models, relation) { | ||
| const result = await HasManyThroughRelation.loadAll(models, relation); | ||
| return result.map(m => { | ||
| const arr = m[relation.property] || []; | ||
| m[relation.property] = arr[0] ?? null; | ||
| return m; | ||
| }); | ||
| } | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has one through relation. | ||
| */ | ||
| static whereHas(Model, query, relation) { | ||
| return HasManyThroughRelation.whereHas(Model, query, relation); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ModelColumns } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export type HasManyThroughOptions<T extends BaseModel = any, R extends BaseModel = any, H extends BaseModel = any> = { | ||
| /** | ||
| * The relation option type. | ||
| * | ||
| * @readonly | ||
| * @default 'hasManyThrough' | ||
| */ | ||
| type?: 'hasManyThrough'; | ||
| /** | ||
| * The closure that should be executed while | ||
| * querying the relation data from database. | ||
| * | ||
| * Used by `whereHas()` for the WHERE EXISTS subquery. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| closure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The closure provided to `with()` for eager loading. | ||
| * Kept separate from {@link closure} so that a `whereHas()` call | ||
| * on the same relation never overwrites the eager-load filter. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| withClosure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The property name in class of the relation. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: string; | ||
| /** | ||
| * The final relation model that is being referenced | ||
| * through the intermediate model. | ||
| * | ||
| * @readonly | ||
| */ | ||
| model?: () => typeof BaseModel; | ||
| /** | ||
| * The intermediate model used to traverse from the | ||
| * parent model to the final relation model. | ||
| * | ||
| * @readonly | ||
| */ | ||
| through?: () => typeof BaseModel; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `with()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIncluded?: boolean; | ||
| /** | ||
| * Internal flag when `whereHas()` applies a constraint on this relation. | ||
| * Does not eager-load; use {@link isIncluded} / `with()` to load related rows. | ||
| * | ||
| * @default false | ||
| */ | ||
| isWhereHasIncluded?: boolean; | ||
| /** | ||
| * The column on the parent model that links to the | ||
| * intermediate model via {@link firstKey}. | ||
| * | ||
| * @default Model.schema().getMainPrimaryKeyProperty() | ||
| */ | ||
| localKey?: ModelColumns<T>; | ||
| /** | ||
| * The column on the intermediate model that points | ||
| * back at the parent model. | ||
| * | ||
| * @default `${String.toCamelCase(Model.name)}Id` | ||
| */ | ||
| firstKey?: ModelColumns<H>; | ||
| /** | ||
| * The column on the intermediate model that participates | ||
| * in the link to the final model. | ||
| * | ||
| * - Shape A (default): `Through.schema().getMainPrimaryKeyProperty()` | ||
| * - Shape B (`inverse: true`): `${String.toCamelCase(Final.name)}Id` | ||
| */ | ||
| secondLocalKey?: ModelColumns<H>; | ||
| /** | ||
| * The column on the final model that participates | ||
| * in the link to the intermediate model. | ||
| * | ||
| * - Shape A (default): `${String.toCamelCase(Through.name)}Id` | ||
| * - Shape B (`inverse: true`): `Final.schema().getMainPrimaryKeyProperty()` | ||
| */ | ||
| secondKey?: ModelColumns<R>; | ||
| /** | ||
| * Flip the defaults so the foreign key linking the | ||
| * intermediate model to the final model lives on the | ||
| * intermediate model (shape B). | ||
| * | ||
| * @default false | ||
| */ | ||
| inverse?: boolean; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ModelColumns } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export type HasOneThroughOptions<T extends BaseModel = any, R extends BaseModel = any, H extends BaseModel = any> = { | ||
| /** | ||
| * The relation option type. | ||
| * | ||
| * @readonly | ||
| * @default 'hasOneThrough' | ||
| */ | ||
| type?: 'hasOneThrough'; | ||
| /** | ||
| * The closure that should be executed while | ||
| * querying the relation data from database. | ||
| * | ||
| * Used by `whereHas()` for the WHERE EXISTS subquery. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| closure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The closure provided to `with()` for eager loading. | ||
| * Kept separate from {@link closure} so that a `whereHas()` call | ||
| * on the same relation never overwrites the eager-load filter. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| withClosure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The property name in class of the relation. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: string; | ||
| /** | ||
| * The final relation model that is being referenced | ||
| * through the intermediate model. | ||
| * | ||
| * @readonly | ||
| */ | ||
| model?: () => typeof BaseModel; | ||
| /** | ||
| * The intermediate model used to traverse from the | ||
| * parent model to the final relation model. | ||
| * | ||
| * @readonly | ||
| */ | ||
| through?: () => typeof BaseModel; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `with()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIncluded?: boolean; | ||
| /** | ||
| * Internal flag when `whereHas()` applies a constraint on this relation. | ||
| * Does not eager-load; use {@link isIncluded} / `with()` to load related rows. | ||
| * | ||
| * @default false | ||
| */ | ||
| isWhereHasIncluded?: boolean; | ||
| /** | ||
| * The column on the parent model that links to the | ||
| * intermediate model via {@link firstKey}. | ||
| * | ||
| * @default Model.schema().getMainPrimaryKeyProperty() | ||
| */ | ||
| localKey?: ModelColumns<T>; | ||
| /** | ||
| * The column on the intermediate model that points | ||
| * back at the parent model. | ||
| * | ||
| * @default `${String.toCamelCase(Model.name)}Id` | ||
| */ | ||
| firstKey?: ModelColumns<H>; | ||
| /** | ||
| * The column on the intermediate model that participates | ||
| * in the link to the final model. | ||
| * | ||
| * - Shape A (default): `Through.schema().getMainPrimaryKeyProperty()` | ||
| * - Shape B (`inverse: true`): `${String.toCamelCase(Final.name)}Id` | ||
| */ | ||
| secondLocalKey?: ModelColumns<H>; | ||
| /** | ||
| * The column on the final model that participates | ||
| * in the link to the intermediate model. | ||
| * | ||
| * - Shape A (default): `${String.toCamelCase(Through.name)}Id` | ||
| * - Shape B (`inverse: true`): `Final.schema().getMainPrimaryKeyProperty()` | ||
| */ | ||
| secondKey?: ModelColumns<R>; | ||
| /** | ||
| * Flip the defaults so the foreign key linking the | ||
| * intermediate model to the final model lives on the | ||
| * intermediate model (shape B). | ||
| * | ||
| * @default false | ||
| */ | ||
| inverse?: boolean; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
+1
-1
| { | ||
| "name": "@athenna/database", | ||
| "version": "5.54.0", | ||
| "version": "5.55.0", | ||
| "description": "The Athenna database handler for SQL/NoSQL.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -12,3 +12,5 @@ /** | ||
| export declare const HAS_MANY_KEY = "database:hasMany:options"; | ||
| export declare const HAS_ONE_THROUGH_KEY = "database:hasOneThrough:options"; | ||
| export declare const HAS_MANY_THROUGH_KEY = "database:hasManyThrough:options"; | ||
| export declare const BELONGS_TO_KEY = "database:belongsTo:options"; | ||
| export declare const BELONGS_TO_MANY_KEY = "database:belongsToMany:options"; |
@@ -12,3 +12,5 @@ /** | ||
| export const HAS_MANY_KEY = 'database:hasMany:options'; | ||
| export const HAS_ONE_THROUGH_KEY = 'database:hasOneThrough:options'; | ||
| export const HAS_MANY_THROUGH_KEY = 'database:hasManyThrough:options'; | ||
| export const BELONGS_TO_KEY = 'database:belongsTo:options'; | ||
| export const BELONGS_TO_MANY_KEY = 'database:belongsToMany:options'; |
@@ -9,3 +9,3 @@ /** | ||
| */ | ||
| import type { RelationOptions, ColumnOptions, HasOneOptions, HasManyOptions, BelongsToOptions, BelongsToManyOptions } from '#src/types'; | ||
| import type { RelationOptions, ColumnOptions, HasOneOptions, HasManyOptions, HasOneThroughOptions, HasManyThroughOptions, BelongsToOptions, BelongsToManyOptions } from '#src/types'; | ||
| export declare class Annotation { | ||
@@ -19,2 +19,6 @@ static getColumnsMeta(target: any): ColumnOptions[]; | ||
| static defineHasManyMeta(target: any, options: HasManyOptions): void; | ||
| static getHasOneThroughMeta(target: any): HasOneThroughOptions[]; | ||
| static defineHasOneThroughMeta(target: any, options: HasOneThroughOptions): void; | ||
| static getHasManyThroughMeta(target: any): HasManyThroughOptions[]; | ||
| static defineHasManyThroughMeta(target: any, options: HasManyThroughOptions): void; | ||
| static getBelongsToMeta(target: any): BelongsToOptions[]; | ||
@@ -21,0 +25,0 @@ static defineBelongsToMeta(target: any, options: BelongsToOptions): void; |
@@ -9,3 +9,3 @@ /** | ||
| */ | ||
| import { COLUMNS_KEY, HAS_ONE_KEY, HAS_MANY_KEY, BELONGS_TO_KEY, BELONGS_TO_MANY_KEY } from '#src/constants/MetadataKeys'; | ||
| import { COLUMNS_KEY, HAS_ONE_KEY, HAS_MANY_KEY, HAS_ONE_THROUGH_KEY, HAS_MANY_THROUGH_KEY, BELONGS_TO_KEY, BELONGS_TO_MANY_KEY } from '#src/constants/MetadataKeys'; | ||
| export class Annotation { | ||
@@ -24,2 +24,4 @@ static getColumnsMeta(target) { | ||
| ...this.getHasManyMeta(target), | ||
| ...this.getHasOneThroughMeta(target), | ||
| ...this.getHasManyThroughMeta(target), | ||
| ...this.getBelongsToMeta(target), | ||
@@ -45,2 +47,18 @@ ...this.getBelongsToManyMeta(target) | ||
| } | ||
| static getHasOneThroughMeta(target) { | ||
| return Reflect.getMetadata(HAS_ONE_THROUGH_KEY, target) || []; | ||
| } | ||
| static defineHasOneThroughMeta(target, options) { | ||
| const hasOneThrough = Reflect.getMetadata(HAS_ONE_THROUGH_KEY, target) || []; | ||
| hasOneThrough.push(options); | ||
| Reflect.defineMetadata(HAS_ONE_THROUGH_KEY, hasOneThrough, target); | ||
| } | ||
| static getHasManyThroughMeta(target) { | ||
| return Reflect.getMetadata(HAS_MANY_THROUGH_KEY, target) || []; | ||
| } | ||
| static defineHasManyThroughMeta(target, options) { | ||
| const hasManyThrough = Reflect.getMetadata(HAS_MANY_THROUGH_KEY, target) || []; | ||
| hasManyThrough.push(options); | ||
| Reflect.defineMetadata(HAS_MANY_THROUGH_KEY, hasManyThrough, target); | ||
| } | ||
| static getBelongsToMeta(target) { | ||
@@ -47,0 +65,0 @@ return Reflect.getMetadata(BELONGS_TO_KEY, target) || []; |
+2
-0
@@ -16,2 +16,4 @@ /** | ||
| export * from '#src/models/annotations/HasMany'; | ||
| export * from '#src/models/annotations/HasOneThrough'; | ||
| export * from '#src/models/annotations/HasManyThrough'; | ||
| export * from '#src/models/annotations/BelongsTo'; | ||
@@ -18,0 +20,0 @@ export * from '#src/models/annotations/BelongsToMany'; |
+2
-0
@@ -16,2 +16,4 @@ /** | ||
| export * from '#src/models/annotations/HasMany'; | ||
| export * from '#src/models/annotations/HasOneThrough'; | ||
| export * from '#src/models/annotations/HasManyThrough'; | ||
| export * from '#src/models/annotations/BelongsTo'; | ||
@@ -18,0 +20,0 @@ export * from '#src/models/annotations/BelongsToMany'; |
@@ -19,2 +19,4 @@ /** | ||
| import { BelongsToManyRelation } from '#src/models/relations/BelongsToMany/BelongsToManyRelation'; | ||
| import { HasOneThroughRelation } from '#src/models/relations/HasOneThrough/HasOneThroughRelation'; | ||
| import { HasManyThroughRelation } from '#src/models/relations/HasManyThrough/HasManyThroughRelation'; | ||
| export class ModelQueryBuilder extends QueryBuilder { | ||
@@ -408,2 +410,6 @@ constructor(model, driver) { | ||
| return HasManyRelation.whereHas(this.Model, query, snapshot); | ||
| case 'hasOneThrough': | ||
| return HasOneThroughRelation.whereHas(this.Model, query, snapshot); | ||
| case 'hasManyThrough': | ||
| return HasManyThroughRelation.whereHas(this.Model, query, snapshot); | ||
| case 'belongsTo': | ||
@@ -441,2 +447,6 @@ return BelongsToRelation.whereHas(this.Model, query, snapshot); | ||
| return HasManyRelation.whereHas(this.Model, query, snapshot); | ||
| case 'hasOneThrough': | ||
| return HasOneThroughRelation.whereHas(this.Model, query, snapshot); | ||
| case 'hasManyThrough': | ||
| return HasManyThroughRelation.whereHas(this.Model, query, snapshot); | ||
| case 'belongsTo': | ||
@@ -443,0 +453,0 @@ return BelongsToRelation.whereHas(this.Model, query, snapshot); |
@@ -14,2 +14,4 @@ /** | ||
| import { HasManyRelation } from '#src/models/relations/HasMany/HasManyRelation'; | ||
| import { HasOneThroughRelation } from '#src/models/relations/HasOneThrough/HasOneThroughRelation'; | ||
| import { HasManyThroughRelation } from '#src/models/relations/HasManyThrough/HasManyThroughRelation'; | ||
| import { BelongsToRelation } from '#src/models/relations/BelongsTo/BelongsToRelation'; | ||
@@ -77,2 +79,6 @@ import { BelongsToManyRelation } from '#src/models/relations/BelongsToMany/BelongsToManyRelation'; | ||
| return HasManyRelation.load(model, relation); | ||
| case 'hasOneThrough': | ||
| return HasOneThroughRelation.load(model, relation); | ||
| case 'hasManyThrough': | ||
| return HasManyThroughRelation.load(model, relation); | ||
| case 'belongsTo': | ||
@@ -111,2 +117,6 @@ return BelongsToRelation.load(model, relation); | ||
| return HasManyRelation.loadAll(models, relation); | ||
| case 'hasOneThrough': | ||
| return HasOneThroughRelation.loadAll(models, relation); | ||
| case 'hasManyThrough': | ||
| return HasManyThroughRelation.loadAll(models, relation); | ||
| case 'belongsTo': | ||
@@ -113,0 +123,0 @@ return BelongsToRelation.loadAll(models, relation); |
@@ -19,2 +19,4 @@ /** | ||
| export * from '#src/types/relations/HasManyOptions'; | ||
| export * from '#src/types/relations/HasOneThroughOptions'; | ||
| export * from '#src/types/relations/HasManyThroughOptions'; | ||
| export * from '#src/types/relations/BelongsToOptions'; | ||
@@ -21,0 +23,0 @@ export * from '#src/types/relations/BelongsToManyOptions'; |
@@ -19,2 +19,4 @@ /** | ||
| export * from '#src/types/relations/HasManyOptions'; | ||
| export * from '#src/types/relations/HasOneThroughOptions'; | ||
| export * from '#src/types/relations/HasManyThroughOptions'; | ||
| export * from '#src/types/relations/BelongsToOptions'; | ||
@@ -21,0 +23,0 @@ export * from '#src/types/relations/BelongsToManyOptions'; |
@@ -11,4 +11,6 @@ /** | ||
| import type { HasManyOptions } from '#src/types/relations/HasManyOptions'; | ||
| import type { HasOneThroughOptions } from '#src/types/relations/HasOneThroughOptions'; | ||
| import type { HasManyThroughOptions } from '#src/types/relations/HasManyThroughOptions'; | ||
| import type { BelongsToOptions } from '#src/types/relations/BelongsToOptions'; | ||
| import type { BelongsToManyOptions } from '#src/types/relations/BelongsToManyOptions'; | ||
| export type RelationOptions = HasOneOptions | HasManyOptions | BelongsToOptions | BelongsToManyOptions; | ||
| export type RelationOptions = HasOneOptions | HasManyOptions | HasOneThroughOptions | HasManyThroughOptions | BelongsToOptions | BelongsToManyOptions; |
552787
4.73%190
6.74%16336
4.26%