UNPKG

adonis-odm

Version:

A comprehensive MongoDB ODM for AdonisJS with Lucid-style API, type-safe relationships, embedded documents, and transaction support

202 lines 6.95 kB
import type { BaseModel } from '../base_model/base_model.js'; import type { ModelQueryBuilder } from '../query_builder/model_query_builder.js'; import type { Document } from 'mongodb'; /** * SEAMLESS TYPE SAFETY - LIKE ADONISJS LUCID! * * This module implements advanced TypeScript patterns to achieve seamless type safety * for relationship loading, exactly like AdonisJS Lucid, without requiring any type * assertions or extra steps from developers. * * Key Features: * - Automatic relationship key inference from model definitions * - Type-safe load callbacks with proper IntelliSense * - Seamless direct property access: user.profile.firstName * - Array access for HasMany: user.posts[0].title * - Compile-time error checking for invalid relationship names * - Zero developer overhead - works exactly like AdonisJS Lucid */ /** * HasOne relationship type - represents a one-to-one relationship * Supports seamless direct property access to the related model */ export type HasOne<T extends typeof BaseModel> = { /** * The related model instance (when loaded) */ related?: InstanceType<T> | null; /** * Load the relationship */ load(): Promise<InstanceType<T> | null>; /** * Create a new related model */ create(attributes: Partial<InstanceType<T>>): Promise<InstanceType<T>>; /** * Save a related model */ save(model: InstanceType<T>): Promise<InstanceType<T>>; /** * Query the relationship */ query(): any; /** * Check if the relationship is loaded */ isLoaded: boolean; } & Partial<InstanceType<T>>; /** * HasMany relationship type - represents a one-to-many relationship * Supports array-like access and seamless property access on array elements */ export type HasMany<T extends typeof BaseModel> = { /** * The related model instances (when loaded) */ related?: InstanceType<T>[]; /** * Load the relationship */ load(): Promise<InstanceType<T>[]>; /** * Create a new related model */ create(attributes: Partial<InstanceType<T>>): Promise<InstanceType<T>>; /** * Create multiple related models */ createMany(attributes: Partial<InstanceType<T>>[]): Promise<InstanceType<T>[]>; /** * Save a single related model */ save(model: InstanceType<T>): Promise<InstanceType<T>>; /** * Save multiple related models */ saveMany(models: InstanceType<T>[]): Promise<InstanceType<T>[]>; /** * Query the relationship */ query(): any; /** * Check if the relationship is loaded */ isLoaded: boolean; /** * Array length */ readonly length: number; /** * Array iteration methods */ forEach(callback: (item: InstanceType<T>, index: number) => void): void; map<U>(callback: (item: InstanceType<T>, index: number) => U): U[]; filter(callback: (item: InstanceType<T>, index: number) => boolean): InstanceType<T>[]; /** * Array access by index */ [index: number]: InstanceType<T>; } & InstanceType<T>[]; /** * BelongsTo relationship type - represents an inverse one-to-one/many relationship * Supports seamless direct property access to the related model */ export type BelongsTo<T extends typeof BaseModel> = { /** * The related model instance (when loaded) */ related?: InstanceType<T> | null; /** * Load the relationship */ load(): Promise<InstanceType<T> | null>; /** * Associate with a related model */ associate(model: InstanceType<T>): Promise<InstanceType<T>>; /** * Dissociate from the related model */ dissociate(): Promise<void>; /** * Query the relationship */ query(): any; /** * Check if the relationship is loaded */ isLoaded: boolean; } & Partial<InstanceType<T>>; /** * ADVANCED TYPE INFERENCE - LIKE ADONISJS LUCID! * * These utility types automatically extract relationship information from model * definitions, enabling seamless type-safe load callbacks without any manual work. */ /** * Extract all relationship property names from a model * This automatically finds all HasOne, HasMany, and BelongsTo properties */ export type RelationshipKeys<TModel extends BaseModel> = { [K in keyof TModel]: TModel[K] extends HasOne<any> ? K : TModel[K] extends HasMany<any> ? K : TModel[K] extends BelongsTo<any> ? K : never; }[keyof TModel]; /** * Extract the related model type from a relationship property * This provides the exact model type for load callback parameters */ export type RelatedModelType<TModel extends BaseModel, TRelation extends keyof TModel> = TModel[TRelation] extends HasOne<infer R> ? R : TModel[TRelation] extends HasMany<infer R> ? R : TModel[TRelation] extends BelongsTo<infer R> ? R : never; /** * Extract the instance type of a related model * This provides the exact instance type for seamless property access */ export type RelatedModelInstance<TModel extends BaseModel, TRelation extends keyof TModel> = TModel[TRelation] extends HasOne<infer R> ? InstanceType<R> : TModel[TRelation] extends HasMany<infer R> ? InstanceType<R> : TModel[TRelation] extends BelongsTo<infer R> ? InstanceType<R> : never; /** * RELATIONSHIP DECORATORS * * These decorators are used to define relationships on model classes * and provide the metadata needed for automatic type inference. */ /** * HasOne relationship decorator */ export declare function hasOne<T extends typeof BaseModel>(relatedModel: () => T, options?: { foreignKey?: string; localKey?: string; }): (target: any, propertyKey: string) => void; /** * HasMany relationship decorator */ export declare function hasMany<T extends typeof BaseModel>(relatedModel: () => T, options?: { foreignKey?: string; localKey?: string; }): (target: any, propertyKey: string) => void; /** * BelongsTo relationship decorator */ export declare function belongsTo<T extends typeof BaseModel>(relatedModel: () => T, options?: { foreignKey?: string; localKey?: string; }): (target: any, propertyKey: string) => void; /** * RELATIONSHIP METADATA INTERFACE * * This interface defines the structure of relationship metadata * stored on model classes for runtime relationship handling. */ export interface RelationshipMetadata { type: 'hasOne' | 'hasMany' | 'belongsTo'; relatedModel: () => typeof BaseModel; options: { foreignKey?: string; localKey?: string; }; } /** * SEAMLESS TYPE SAFETY * * Type-safe load callback for seamless relationship loading. * Use declaration merging to augment ModelQueryBuilder with specific relationship types. */ export type TypeSafeLoadCallback<T extends Document = Document> = (query: ModelQueryBuilder<T>) => void | Promise<void> | ModelQueryBuilder<T> | Promise<ModelQueryBuilder<T>>; //# sourceMappingURL=relationships.d.ts.map