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
TypeScript
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