This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+16
View File
@@ -0,0 +1,16 @@
declare module '@ioc:Adonis/Core/Application' {
import * as Orm from '@ioc:Adonis/Lucid/Orm';
import Migrator from '@ioc:Adonis/Lucid/Migrator';
import { DatabaseContract } from '@ioc:Adonis/Lucid/Database';
import { FactoryManagerContract } from '@ioc:Adonis/Lucid/Factory';
import { SchemaConstructorContract } from '@ioc:Adonis/Lucid/Schema';
import { SeederConstructorContract } from '@ioc:Adonis/Lucid/Seeder';
interface ContainerBindings {
'Adonis/Lucid/Database': DatabaseContract;
'Adonis/Lucid/Factory': FactoryManagerContract;
'Adonis/Lucid/Orm': typeof Orm;
'Adonis/Lucid/Migrator': typeof Migrator;
'Adonis/Lucid/Schema': SchemaConstructorContract;
'Adonis/Lucid/Seeder': SeederConstructorContract;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+727
View File
@@ -0,0 +1,727 @@
/// <reference path="querybuilder.d.ts" />
/// <reference types="@adonisjs/events/build/adonis-typings" />
/// <reference types="@adonisjs/profiler/build/adonis-typings/profiler" />
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="@adonisjs/logger/build/adonis-typings/logger" />
declare module '@ioc:Adonis/Lucid/Database' {
import { Knex } from 'knex';
import { Pool } from 'tarn';
import { EventEmitter } from 'events';
import { ConnectionOptions } from 'tls';
import { EmitterContract } from '@ioc:Adonis/Core/Event';
import { MacroableConstructorContract } from 'macroable';
import { LoggerContract } from '@ioc:Adonis/Core/Logger';
import { HealthReportEntry } from '@ioc:Adonis/Core/HealthCheck';
import { LucidModel, ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm';
import { ProfilerRowContract, ProfilerContract } from '@ioc:Adonis/Core/Profiler';
/**
* Same as knex. Need to redefine, as knex doesn't export this
* type
*/
export type IsolationLevels = 'read uncommitted' | 'read committed' | 'snapshot' | 'repeatable read' | 'serializable';
/**
* Migration node returned by the migration source
* implementation
*/
export type FileNode<T> = {
absPath: string;
name: string;
getSource: () => T | Promise<T>;
};
/**
* Dialect specific methods
*/
export interface DialectContract {
readonly name: 'mssql' | 'mysql' | 'oracledb' | 'postgres' | 'redshift' | 'sqlite3' | 'better-sqlite3';
readonly dateTimeFormat: string;
readonly version?: string;
readonly supportsAdvisoryLocks: boolean;
readonly supportsViews: boolean;
readonly supportsTypes: boolean;
readonly supportsReturningStatement: boolean;
getAllTables(schemas?: string[]): Promise<string[]>;
dropAllTables(schemas?: string[]): Promise<void>;
getAllViews(schemas?: string[]): Promise<string[]>;
dropAllViews(schemas?: string[]): Promise<void>;
getAllTypes(schemas?: string[]): Promise<string[]>;
dropAllTypes(schemas?: string[]): Promise<void>;
truncate(table: string, cascade?: boolean): Promise<void>;
getAdvisoryLock(key: string | number, timeout?: number): Promise<boolean>;
releaseAdvisoryLock(key: string | number): Promise<boolean>;
}
/**
* Shape of the transaction function to create a new transaction
*/
export interface TransactionFn {
<T>(callback: (trx: TransactionClientContract) => Promise<T>, options?: {
isolationLevel?: IsolationLevels;
}): Promise<T>;
(options?: {
isolationLevel?: IsolationLevels;
}): Promise<TransactionClientContract>;
}
/**
* Shape of the query client, that is used to retrive instances
* of query builder
*/
export interface QueryClientContract {
emitter: EmitterContract;
/**
* Custom profiler to time queries
*/
profiler?: ProfilerRowContract | ProfilerContract;
/**
* Tells if client is a transaction client or not
*/
readonly isTransaction: boolean;
/**
* The database dialect in use
*/
readonly dialect: DialectContract;
/**
* The client mode in which it is execute queries
*/
readonly mode: 'dual' | 'write' | 'read';
/**
* The name of the connnection from which the client
* was originated
*/
readonly connectionName: string;
/**
* Is debug enabled on the connnection or not. Also opens up the API to
* disable debug for a given client
*/
debug: boolean;
/**
* Returns schema instance for the write client
*/
schema: Knex.SchemaBuilder;
/**
* Returns the read and write clients
*/
getReadClient(): Knex<any, any>;
getWriteClient(): Knex<any, any>;
/**
* Returns the query builder for a given model
*/
modelQuery<T extends LucidModel, Result = T>(model: T): ModelQueryBuilderContract<T, Result>;
/**
* Returns the knex query builder instance
*/
knexQuery(): Knex.QueryBuilder;
/**
* Returns the knex raw query builder instance
*/
knexRawQuery(sql: string, bindings?: RawQueryBindings): Knex.Raw;
/**
* Get new query builder instance for select, update and
* delete calls
*/
query<Result = any>(): DatabaseQueryBuilderContract<Result>;
/**
* Get new query builder instance inserts
*/
insertQuery<ReturnColumns = any>(): InsertQueryBuilderContract<ReturnColumns[]>;
/**
* Get raw query builder instance
*/
rawQuery<Result = any>(sql: string, bindings?: RawQueryBindings): RawQueryBuilderContract<Result>;
/**
* Returns instance of reference builder
*/
ref(reference: string): ReferenceBuilderContract;
/**
* Returns instance of raw builder
*/
raw(sql: string, bindings?: RawQueryBindings): RawBuilderContract;
/**
* Truncate a given table
*/
truncate(table: string, cascade?: boolean): Promise<void>;
/**
* Returns columns info for a given table
*/
columnsInfo(table: string): Promise<{
[column: string]: Knex.ColumnInfo;
}>;
columnsInfo(table: string, column: string): Promise<Knex.ColumnInfo>;
/**
* Get all tables of the database
*/
getAllTables(schemas?: string[]): Promise<string[]>;
/**
* Returns an array of all views names for one or many schemas
*/
getAllViews(schemas?: string[]): Promise<string[]>;
/**
* Returns an array of all types names
*/
getAllTypes(schemas?: string[]): Promise<string[]>;
/**
* Drop all tables inside database
*/
dropAllTables(schemas?: string[]): Promise<void>;
/**
* Drop all views inside the database
*/
dropAllViews(schemas?: string[]): Promise<void>;
/**
* Drop all types inside the database
*/
dropAllTypes(schemas?: string[]): Promise<void>;
/**
* Same as `query()`, but also selects the table for the query. The `from` method
* doesn't allow defining the return type and one must use `query` to define
* that.
*/
from: FromTable<DatabaseQueryBuilderContract<any>>;
/**
* Same as `insertQuery()`, but also selects the table for the query.
* The `table` method doesn't allow defining the return type and
* one must use `insertQuery` to define that.
*/
table: <ReturnColumns = any>(table: string) => InsertQueryBuilderContract<ReturnColumns[]>;
/**
* Get instance of transaction client
*/
transaction: TransactionFn;
/**
* Work with advisory locks
*/
getAdvisoryLock(key: string | number, timeout?: number): Promise<boolean>;
releaseAdvisoryLock(key: string | number): Promise<boolean>;
}
/**
* The shape of transaction client to run queries under a given
* transaction on a single connection
*/
export interface TransactionClientContract extends QueryClientContract, EventEmitter {
knexClient: Knex.Transaction;
/**
* Custom profiler to time queries
*/
profiler?: ProfilerRowContract;
/**
* Is transaction completed or not
*/
isCompleted: boolean;
/**
* Commit transaction
*/
commit(): Promise<void>;
/**
* Rollback transaction
*/
rollback(): Promise<void>;
/**
* Returns the read and write transaction clients
*/
getReadClient(): Knex.Transaction<any, any>;
getWriteClient(): Knex.Transaction<any, any>;
/**
* Transaction named events
*/
on(event: 'commit', handler: (client: this) => void): this;
on(event: 'rollback', handler: (client: this) => void): this;
once(event: 'commit', handler: (client: this) => void): this;
once(event: 'rollback', handler: (client: this) => void): this;
after(event: 'rollback' | 'commit', handler: () => void | Promise<void>): this;
}
/**
* Connection node used by majority of database
* clients
*/
type SharedConnectionNode = {
host?: string;
user?: string;
password?: string;
database?: string;
port?: number;
};
/**
* Shape of the report node for the database connection report
*/
export type ReportNode = {
connection: string;
message: string;
error: any;
};
/**
* Migrations config
*/
export type MigratorConfig = {
disableTransactions?: boolean;
paths?: string[];
tableName?: string;
disableRollbacksInProduction?: boolean;
naturalSort?: boolean;
};
/**
* Seeders config
*/
export type SeedersConfig = {
paths: string[];
};
/**
* Shared config options for all clients
*/
export type SharedConfigNode = {
useNullAsDefault?: boolean;
debug?: boolean;
asyncStackTraces?: boolean;
revision?: number;
healthCheck?: boolean;
migrations?: MigratorConfig;
seeders?: SeedersConfig;
wipe?: {
ignoreTables?: string[];
};
pool?: {
afterCreate?: (conn: any, done: any) => void;
min?: number;
max?: number;
acquireTimeoutMillis?: number;
createTimeoutMillis?: number;
idleTimeoutMillis?: number;
createRetryIntervalMillis?: number;
reapIntervalMillis?: number;
log?: (msg: string) => any;
validate?: (resource: any) => boolean;
propagateCreateError?: boolean;
};
};
/**
* The Sqlite specific config options are taken directly from the
* driver. https://github.com/mapbox/node-sqlite3/wiki/API#new-sqlite3databasefilename-mode-callback
*
* Knex forwards all config options to the driver directly. So feel
* free to define them (let us know, in case any options are missing)
*/
export type SqliteConfig = SharedConfigNode & {
client: 'sqlite' | 'sqlite3' | 'better-sqlite3';
connection: {
filename: string;
flags?: string[];
debug?: boolean;
mode?: any;
};
replicas?: never;
};
/**
* The MYSQL specific config options are taken directly from the
* driver. https://www.npmjs.com/package/mysql#connection-options
*
* Knex forwards all config options to the driver directly. So feel
* free to define them (let us know, in case any options are missing)
*/
type MysqlConnectionNode = {
socketPath?: string;
localAddress?: string;
charset?: string;
timezone?: string;
stringifyObjects?: boolean;
insecureAuth?: boolean;
typeCast?: boolean;
supportBigNumbers?: boolean;
bigNumberStrings?: boolean;
dateStrings?: boolean | string[];
flags?: string;
ssl?: any;
};
export type MysqlConfig = SharedConfigNode & {
client: 'mysql' | 'mysql2';
version?: string;
connection?: SharedConnectionNode & MysqlConnectionNode;
replicas?: {
write: {
connection: MysqlConfig['connection'];
pool?: MysqlConfig['pool'];
};
read: {
connection: MysqlConfig['connection'][];
pool?: MysqlConfig['pool'];
};
};
};
/**
* Config is picked from PostgreSQL driver, just refer their docs
* https://node-postgres.com/features/connecting#programmatic.
*
* - `returning` is added by knex and not driver.
* - `searchPath` is also added by Knex.
*
* Knex forwards all config options to the driver directly. So feel
* free to define them (let us know, in case any options are missing)
*/
type PostgresConnectionNode = {
ssl?: boolean | ConnectionOptions;
};
export type PostgreConfig = SharedConfigNode & {
client: 'pg' | 'postgres' | 'postgresql';
version?: string;
returning?: string;
connection?: string | (SharedConnectionNode & PostgresConnectionNode);
replicas?: {
write: {
connection: PostgreConfig['connection'];
pool?: PostgreConfig['pool'];
};
read: {
connection: PostgreConfig['connection'][];
pool?: PostgreConfig['pool'];
};
};
searchPath?: string[];
wrapIdentifier?: (value: string) => string;
};
/**
* Redshift uses `pg` driver. So config options are same as Postgres.
* https://node-postgres.com/features/connecting#programmatic.
*
* Knex forwards all config options to the driver directly. So feel
* free to define them (let us know, in case any options are missing)
*/
export type RedshiftConfig = PostgreConfig & {
client: 'redshift';
};
/**
* Please install `oracledb` driver and not the `oracle`. The later is
* deprecated. Config is only allowed for `oracledb`.
*
* Please refer to the driver configuration docs to learn more about the
* config values.
* https://oracle.github.io/node-oracledb/doc/api.html#oracledbproperties
*/
type OracleConnectionNode = {
autoCommit?: boolean;
connectionClass?: string;
edition?: string;
externalAuth?: boolean;
fetchArraySize?: number;
fetchAsBuffer?: any[];
lobPrefetchSize?: number;
maxRows?: number;
oracleClientVersion?: number;
connectString?: string;
};
export type OracleConfig = SharedConfigNode & {
client: 'oracledb';
connection?: SharedConnectionNode & OracleConnectionNode;
replicas?: {
write: {
connection: OracleConfig['connection'];
pool?: OracleConfig['pool'];
};
read: {
connection: OracleConfig['connection'][];
pool?: OracleConfig['pool'];
};
};
fetchAsString?: any[];
};
/**
* Config values are taken directly from the driver config.
* https://www.npmjs.com/package/mssql#config.
*
* Knex forwards all config options to the driver directly. So feel
* free to define them (let us know, in case any options are missing)
*/
type MssqlConnectionNode = {
server: string;
domain?: string;
connectionTimeout?: number;
requestTimeout?: number;
parseJSON?: boolean;
options?: {
encrypt?: boolean;
useUTC?: boolean;
tdsVersion?: string;
appName?: string;
abortTransactionOnError?: boolean;
trustedConnection?: boolean;
enableArithAbort?: boolean;
isolationLevel?: 'READ_UNCOMMITTED' | 'READ_COMMITTED' | 'REPEATABLE_READ' | 'SERIALIZABLE' | 'SNAPSHOT';
maxRetriesOnTransientErrors?: number;
multiSubnetFailover?: boolean;
packetSize?: number;
trustServerCertificate?: boolean;
};
};
export type MssqlConfig = SharedConfigNode & {
client: 'mssql';
version?: string;
connection?: SharedConnectionNode & MssqlConnectionNode;
replicas?: {
write: {
connection: MssqlConfig['connection'];
pool?: MssqlConfig['pool'];
};
read: {
connection: MssqlConfig['connection'][];
pool?: MssqlConfig['pool'];
};
};
};
/**
* Connection config must be the config from one of the
* available dialects
*/
export type ConnectionConfig = SqliteConfig | MysqlConfig | PostgreConfig | OracleConfig | RedshiftConfig | MssqlConfig;
/**
* Shape of config inside the database config file
*/
export type DatabaseConfig = {
connection: string;
connections: {
[key: string]: ConnectionConfig;
};
};
/**
* The shape of a connection within the connection manager
*/
export type ConnectionNode = {
name: string;
config: ConnectionConfig;
connection?: ConnectionContract;
state: 'registered' | 'migrating' | 'open' | 'closing' | 'closed';
};
/**
* Connection manager to manage one or more database
* connections.
*/
export interface ConnectionManagerContract {
/**
* List of registered connection. You must check the connection state
* to understand, if it is connected or not
*/
connections: Map<string, ConnectionNode>;
/**
* Add a new connection to the list of managed connection. You must call
* connect separately to instantiate a connection instance
*/
add(connectionName: string, config: ConnectionConfig): void;
/**
* Instantiate a connection. It is a noop, when connection for the given
* name is already instantiated
*/
connect(connectionName: string): void;
/**
* Get connection node
*/
get(connectionName: string): ConnectionNode | undefined;
/**
* Find if a connection name is managed by the manager or not
*/
has(connectionName: string): boolean;
/**
* Patch the existing connection config. This triggers the disconnect on the
* old connection
*/
patch(connectionName: string, config: ConnectionConfig): void;
/**
* Find if a managed connection is instantiated or not
*/
isConnected(connectionName: string): boolean;
/**
* Close a given connection. This is also kill the underlying knex connection
* pool
*/
close(connectionName: string, release?: boolean): Promise<void>;
/**
* Close all managed connections
*/
closeAll(release?: boolean): Promise<void>;
/**
* Release a given connection. Releasing a connection means, you will have to
* re-add it using the `add` method
*/
release(connectionName: string): Promise<void>;
/**
* Returns the health check report for registered connections
*/
report(): Promise<HealthReportEntry & {
meta: ReportNode[];
}>;
}
/**
* Connection represents a single knex instance with inbuilt
* pooling capabilities.
*/
export interface ConnectionContract extends EventEmitter {
client?: Knex;
readClient?: Knex;
readonly dialectName: 'mssql' | 'mysql' | 'mysql2' | 'oracledb' | 'postgres' | 'redshift' | 'sqlite3';
/**
* Property to find if explicit read/write is enabled
*/
readonly hasReadWriteReplicas: boolean;
/**
* Read/write connection pools
*/
pool: null | Pool<any>;
readPool: null | Pool<any>;
/**
* Name of the connection
*/
readonly name: string;
/**
* Find if connection is ready or not
*/
readonly ready: boolean;
/**
* Untouched config
*/
config: ConnectionConfig;
/**
* List of emitted events
*/
on(event: 'connect', callback: (connection: ConnectionContract) => void): this;
on(event: 'error', callback: (error: Error, connection: ConnectionContract) => void): this;
on(event: 'disconnect', callback: (connection: ConnectionContract) => void): this;
on(event: 'disconnect:error', callback: (error: Error, connection: ConnectionContract) => void): this;
/**
* Make knex connection
*/
connect(): void;
/**
* Disconnect knex
*/
disconnect(): Promise<void>;
/**
* Returns the connection report
*/
getReport(): Promise<ReportNode>;
}
/**
* Options when retrieving new query client from the database
* query builder
*/
export type DatabaseClientOptions = Partial<{
mode: 'read' | 'write';
profiler: ProfilerRowContract | ProfilerContract;
}>;
/**
* Shape of the data emitted by the `db:query event`
*/
export type DbQueryEventNode = {
connection: string;
model?: string;
ddl?: boolean;
duration?: [number, number];
method: string;
sql: string;
bindings?: any[];
inTransaction?: boolean;
};
/**
* Database contract serves as the main API to interact with multiple
* database connections
*/
export interface DatabaseContract {
Database: MacroableConstructorContract<DatabaseContract> & {
new (config: DatabaseConfig, logger: LoggerContract, profiler: ProfilerContract, emitter: EmitterContract): DatabaseContract;
};
DatabaseQueryBuilder: MacroableConstructorContract<DatabaseQueryBuilderContract>;
InsertQueryBuilder: MacroableConstructorContract<InsertQueryBuilderContract>;
ModelQueryBuilder: MacroableConstructorContract<ModelQueryBuilderContract<any, any>>;
SimplePaginator: {
namingStrategy: {
paginationMetaKeys(): SimplePaginatorMetaKeys;
};
new <Row>(total: number, perPage: number, currentPage: number, ...rows: Row[]): SimplePaginatorContract<Row>;
};
hasHealthChecksEnabled: boolean;
/**
* Pretty print query logs
*/
prettyPrint: (queryLog: DbQueryEventNode) => void;
/**
* Name of the primary connection defined inside `config/database.ts`
* file
*/
primaryConnectionName: string;
/**
* Reference to the connection manager
*/
manager: ConnectionManagerContract;
/**
* Returns the raw connection instance
*/
getRawConnection: ConnectionManagerContract['get'];
/**
* Get query client for a given connection. Optionally one can also define
* the mode of the connection and profiler row
*/
connection(connectionName?: string, options?: DatabaseClientOptions): QueryClientContract;
/**
* Returns the knex query builder instance
*/
knexQuery(): Knex.QueryBuilder;
/**
* Returns the knex raw query builder instance
*/
knexRawQuery(sql: string, bindings?: RawQueryBindings): Knex.Raw;
/**
* Returns the query builder for a given model
*/
modelQuery<T extends LucidModel, Result = T>(model: T, options?: DatabaseClientOptions): ModelQueryBuilderContract<T, Result>;
/**
* Get query builder instance for a given connection.
*/
query<Result = any>(options?: DatabaseClientOptions): DatabaseQueryBuilderContract<Result>;
/**
* Get insert query builder instance for a given connection.
*/
insertQuery<ReturnColumns = any>(options?: DatabaseClientOptions): InsertQueryBuilderContract<ReturnColumns[]>;
/**
* Get raw query builder instance
*/
rawQuery<Result = any>(sql: string, bindings?: RawQueryBindings, options?: DatabaseClientOptions): RawQueryBuilderContract<Result>;
/**
* Returns instance of reference builder
*/
ref(reference: string): ReferenceBuilderContract;
/**
* Returns instance of raw builder
*/
raw(sql: string, bindings?: RawQueryBindings): RawBuilderContract;
/**
* Selects a table on the default connection by instantiating a new query
* builder instance. This method provides no control over the client
* mode and one must use `query` for that
*/
from: QueryClientContract['from'];
/**
* Selects a table on the default connection by instantiating a new query
* builder instance. This method provides no control over the client
* mode and one must use `insertQuery` for that
*/
table: QueryClientContract['table'];
/**
* Start a new transaction
*/
transaction: TransactionFn;
/**
* Returns the health check report for registered connections
*/
report(): Promise<HealthReportEntry & {
meta: ReportNode[];
}>;
/**
* Begin a new global transaction. Multiple calls to this
* method is a noop
*/
beginGlobalTransaction(connectionName?: string, options?: Exclude<DatabaseClientOptions, 'mode'>): Promise<TransactionClientContract>;
/**
* Commit an existing global transaction
*/
commitGlobalTransaction(connectionName?: string): Promise<void>;
/**
* Rollback an existing global transaction
*/
rollbackGlobalTransaction(connectionName?: string): Promise<void>;
}
const Database: DatabaseContract;
export default Database;
}
+9
View File
@@ -0,0 +1,9 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// <reference path="./querybuilder.ts" />
+6
View File
@@ -0,0 +1,6 @@
declare module '@ioc:Adonis/Core/Event' {
import { DbQueryEventNode } from '@ioc:Adonis/Lucid/Database';
interface EventsList {
'db:query': DbQueryEventNode;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+299
View File
@@ -0,0 +1,299 @@
declare module '@ioc:Adonis/Lucid/Factory' {
import { faker } from '@faker-js/faker';
import { OneOrMany, QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
import { LucidRow, LucidModel, ModelAttributes, ModelAdapterOptions, RelationshipsContract, ExtractModelRelations, ModelObject } from '@ioc:Adonis/Lucid/Orm';
/**
* ------------------------------------------------------
* Helpers
* ------------------------------------------------------
*/
/**
* Extracts the attributes accepted by the lucid model set on a
* factory
*/
export type ExtractFactoryAttributes<T extends FactoryModelContract<LucidModel>> = Partial<ModelAttributes<InstanceType<T['model']>>>;
/**
* ------------------------------------------------------
* Callbacks
* ------------------------------------------------------
*/
/**
* Function to return the model attributes.
*/
export type DefineCallback<Model extends LucidModel> = (ctx: FactoryContextContract) => Promise<Partial<ModelAttributes<InstanceType<Model>>>> | Partial<ModelAttributes<InstanceType<Model>>>;
/**
* Function to generate custom stub ids
*/
export type StubIdCallback = (counter: number, model: LucidRow) => any;
/**
* Function to initiate a model instance. It will receive the
* attributes returned by the `define` method
*/
export type NewUpCallback<T extends FactoryModelContract<LucidModel>> = (attributes: ExtractFactoryAttributes<T>, ctx: FactoryContextContract, model: T['model'], builder: FactoryBuilderContract<T>) => InstanceType<T['model']>;
/**
* Function to merge attributes defined during runtime
*/
export type MergeCallback<T extends FactoryModelContract<LucidModel>> = (row: InstanceType<T['model']>, attributes: ExtractFactoryAttributes<T>, ctx: FactoryContextContract, builder: FactoryBuilderContract<T>) => void;
/**
* Callback to define a new model state
*/
export type StateCallback<Model extends LucidModel> = (row: InstanceType<Model>, ctx: FactoryContextContract, builder: FactoryBuilderContract<FactoryModelContract<Model>>) => any | Promise<any>;
/**
* ------------------------------------------------------
* Hooks
* ------------------------------------------------------
*/
/**
* List of events for which a factory will trigger hooks
*/
export type EventsList = 'makeStubbed' | 'create' | 'make';
/**
* Shape of hooks handler
*/
export type HooksHandler<Model extends FactoryModelContract<LucidModel>> = (builder: FactoryBuilderContract<Model>, row: InstanceType<Model['model']>, ctx: FactoryContextContract) => void | Promise<void>;
/**
* ------------------------------------------------------
* Runtime context
* ------------------------------------------------------
*/
/**
* The runtime context of the factory builder. A new state is constructed
* for each `create/make` operation and passed down to relationships
* as well.
*/
export interface FactoryContextContract {
faker: typeof faker;
isStubbed: boolean;
$trx: TransactionClientContract | undefined;
}
/**
* ------------------------------------------------------
* Relationships
* ------------------------------------------------------
*/
/**
* Callback accepted by the `with` method and relationships
* `create` and `make` methods
*/
export type RelationCallback = (builder: FactoryBuilderContract<FactoryModelContract<LucidModel>>) => void;
/**
* Shape of the factory relationships. To keep relationships slim, we will have
* a common interface for relationships vs fine tuning API for each type of
* relationship
*/
export interface FactoryRelationContract {
parent: LucidRow;
/**
* Reference to the Lucid model relationship
*/
relation: RelationshipsContract;
/**
* Merge attributes with the relationship and its children
*/
merge(attributes: any): this;
/**
* Define custom pivot attributes for many to many
* relationship
*/
pivotAttributes?(attributes: ModelObject | ModelObject[]): this;
/**
* Pass context to the relationship. Must be done everytime, so that
* relationships uses the same transaction as the parent model
*/
useCtx(ctx: FactoryContextContract): this;
/**
* Create and persist
*/
create(parent: LucidRow, callback?: RelationCallback, count?: number): Promise<void>;
/**
* Create and stub
*/
make(parent: LucidRow, callback?: RelationCallback, count?: number): Promise<void>;
}
/**
* ------------------------------------------------------
* Runtime builder
* ------------------------------------------------------
*/
/**
* Factory builder uses the factory model to create/make
* instances of lucid models
*/
export interface FactoryBuilderContract<FactoryModel extends FactoryModelContract<LucidModel>> {
/**
* Reference to the factory
*/
factory: FactoryModel;
/**
* Define custom database connection
*/
connection(connection: string): this;
/**
* Define custom query client
*/
client(client: QueryClientContract): this;
/**
* Apply pre-defined state
*/
apply<K extends keyof FactoryModel['states']>(...states: K[]): this;
/**
* Create/make relationships for explicitly defined related factories
*/
with<K extends keyof FactoryModel['relations']>(relation: K, count?: number, callback?: (
/**
* Receives the explicitly defined factory
*/
builder: FactoryModel['relations'][K] extends () => FactoryBuilderContract<any> ? ReturnType<FactoryModel['relations'][K]> & {
parent: InstanceType<FactoryModel['model']>;
} : never) => void): this;
/**
* Define pivot attributes when persisting a many to many
* relationship. Results in a noop, when not called
* for a many to many relationship
*/
pivotAttributes(attributes: ModelObject | ModelObject[]): this;
/**
* Merge custom set of attributes. They are passed to the merge method of
* the model factory
*
* For `createMany` and `makeMany`, you can pass an array of attributes mapped
* according to the array index.
*/
merge(attributes: OneOrMany<ExtractFactoryAttributes<FactoryModel>>): this;
/**
* Merge custom set of attributes with the correct factory builder
* model and all of its relationships as well
*/
mergeRecursive(attributes: any): this;
/**
* Define custom runtime context. This method is usually called by
* the relationships to ensure a single context is used by the
* parent and relationship factories.
*
* Do not define a custom context, unless you know what you are really
* doing.
*/
useCtx(ctx: FactoryContextContract): this;
/**
* Tap into the persistence layer of factory builder. Allows one
* to modify the model instance just before it is persisted
* to the database
*/
tap(callback: (row: InstanceType<FactoryModel['model']>, ctx: FactoryContextContract, builder: this) => void): this;
/**
* Make model instance without persitance. The make method
* doesn't process relationships
*/
make(): Promise<InstanceType<FactoryModel['model']>>;
/**
* Create model instance and stub out the persistance
* mechanism
*/
makeStubbed(): Promise<InstanceType<FactoryModel['model']>>;
/**
* Create and persist model instance
*/
create(): Promise<InstanceType<FactoryModel['model']>>;
/**
* Make model instance without persitance. The makeMany method
* doesn't process relationships
*/
makeMany(count: number): Promise<InstanceType<FactoryModel['model']>[]>;
/**
* Create one or more model instances and stub
* out the persistance mechanism.
*/
makeStubbedMany(count: number): Promise<InstanceType<FactoryModel['model']>[]>;
/**
* Create and persist more than one model instance
*/
createMany(count: number): Promise<InstanceType<FactoryModel['model']>[]>;
}
/**
* Query contract that initiates the factory builder. Since the factory builder
* API surface is small, we also proxy all of it's methods for a nicer DX
*/
export interface FactoryBuilderQueryContract<FactoryModel extends FactoryModelContract<LucidModel>> extends FactoryBuilderContract<FactoryModel> {
query(options?: ModelAdapterOptions, viaRelation?: FactoryRelationContract): FactoryBuilderContract<FactoryModel>;
}
/**
* ------------------------------------------------------
* Factory model
* ------------------------------------------------------
*/
/**
* Factory model exposes the API to defined a model factory with states
* and relationships
*/
export interface FactoryModelContract<Model extends LucidModel> {
/**
* Reference to the underlying lucid model used by the factory
* model
*/
model: Model;
/**
* Mainly for types support. Not used at runtime to derive any
* logic. Sorry, at times have to hack into typescript to
* get the desired output. :)
*/
states: unknown;
relations: unknown;
/**
* Optionally define a custom method to instantiate the model
* instance and manage merging attributes
*/
newUp(callback: NewUpCallback<this>): this;
merge(callback: MergeCallback<this>): this;
/**
* Define custom state for the factory. When executing the factory,
* you can apply the pre-defined states
*/
state<K extends string>(state: K, callback: StateCallback<Model>): this & {
states: {
[P in K]: StateCallback<Model>;
};
};
/**
* Define a relationship on another factory
*/
relation<K extends ExtractModelRelations<InstanceType<Model>>, Relation>(relation: K, callback: Relation): this & {
relations: {
[P in K]: Relation;
};
};
/**
* Define before hooks. Only `create` event is invoked
* during the before lifecycle
*/
before(event: Exclude<EventsList, 'make'>, handler: HooksHandler<this>): this;
/**
* Define after hooks.
*/
after(event: EventsList, handler: HooksHandler<this>): this;
/**
* Build model factory. This method returns the factory builder, which can be used to
* execute model queries
*/
build(): FactoryBuilderQueryContract<this>;
}
/**
* ------------------------------------------------------
* Manager to register new factories
* ------------------------------------------------------
*/
/**
* Factory manager to define new factories
*/
export interface FactoryManagerContract {
/**
* Define a custom factory
*/
define<Model extends LucidModel>(model: Model, callback: DefineCallback<Model>): FactoryModelContract<Model>;
/**
* Define a custom callback to generate stub ids
*/
stubId(callback: StubIdCallback): void;
}
const Factory: FactoryManagerContract;
export default Factory;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+13
View File
@@ -0,0 +1,13 @@
/// <reference path="database.d.ts" />
/// <reference path="events.d.ts" />
/// <reference path="querybuilder.d.ts" />
/// <reference path="model.d.ts" />
/// <reference path="orm.d.ts" />
/// <reference path="schema.d.ts" />
/// <reference path="migrator.d.ts" />
/// <reference path="relations.d.ts" />
/// <reference path="factory.d.ts" />
/// <reference path="validator.d.ts" />
/// <reference path="seeder.d.ts" />
/// <reference path="container.d.ts" />
/// <reference path="test-utils.d.ts" />
+21
View File
@@ -0,0 +1,21 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// <reference path="./database.ts" />
/// <reference path="./events.ts" />
/// <reference path="./querybuilder.ts" />
/// <reference path="./model.ts" />
/// <reference path="./orm.ts" />
/// <reference path="./schema.ts" />
/// <reference path="./migrator.ts" />
/// <reference path="./relations.ts" />
/// <reference path="./factory.ts" />
/// <reference path="./validator.ts" />
/// <reference path="./seeder.ts" />
/// <reference path="./container.ts" />
/// <reference path="./test-utils.ts" />
+77
View File
@@ -0,0 +1,77 @@
/// <reference types="node" />
/// <reference types="@adonisjs/application/build/adonis-typings" />
declare module '@ioc:Adonis/Lucid/Migrator' {
import { EventEmitter } from 'events';
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { FileNode, DatabaseContract } from '@ioc:Adonis/Lucid/Database';
/**
* Options accepted by migrator constructor
*/
export type MigratorOptions = {
direction: 'up';
connectionName?: string;
dryRun?: boolean;
disableLocks?: boolean;
} | {
direction: 'down';
batch?: number;
connectionName?: string;
dryRun?: boolean;
disableLocks?: boolean;
};
/**
* Shape of migrated file within migrator
*/
export type MigratedFileNode = {
status: 'completed' | 'error' | 'pending';
queries: string[];
file: FileNode<unknown>;
batch: number;
};
/**
* Shape of migrated file within migrator
*/
export type MigrationListNode = {
name: string;
status: 'pending' | 'migrated' | 'corrupt';
batch?: number;
migrationTime?: Date;
};
/**
* Shape of the migrator
*/
export interface MigratorContract extends EventEmitter {
dryRun: boolean;
disableLocks: boolean;
version: number;
direction: 'up' | 'down';
status: 'completed' | 'skipped' | 'pending' | 'error';
error: null | Error;
migratedFiles: {
[file: string]: MigratedFileNode;
};
run(): Promise<void>;
getList(): Promise<MigrationListNode[]>;
close(): Promise<void>;
on(event: 'start', callback: () => void): this;
on(event: 'end', callback: () => void): this;
on(event: 'acquire:lock', callback: () => void): this;
on(event: 'release:lock', callback: () => void): this;
on(event: 'create:schema:table', callback: () => void): this;
on(event: 'create:schema_versions:table', callback: () => void): this;
on(event: 'upgrade:version', callback: (payload: {
from: number;
to: number;
}) => void): this;
on(event: 'migration:start', callback: (file: MigratedFileNode) => void): this;
on(event: 'migration:completed', callback: (file: MigratedFileNode) => void): this;
on(event: 'migration:error', callback: (file: MigratedFileNode) => void): this;
}
/**
* Migrator class constructor
*/
const Migrator: {
new (db: DatabaseContract, app: ApplicationContract, options: MigratorOptions): MigratorContract;
};
export default Migrator;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+801
View File
@@ -0,0 +1,801 @@
/// <reference types="@adonisjs/profiler/build/adonis-typings/profiler" />
declare module '@ioc:Adonis/Lucid/Orm' {
import { DateTime } from 'luxon';
import { Hooks } from '@poppinss/hooks';
import { ProfilerContract, ProfilerRowContract } from '@ioc:Adonis/Core/Profiler';
import { Update, Counter, OneOrMany, Aggregate, Returning, DialectContract, ChainableContract, QueryClientContract, SimplePaginatorMetaKeys, SimplePaginatorContract, TransactionClientContract, ExcutableQueryBuilderContract } from '@ioc:Adonis/Lucid/Database';
/**
* ------------------------------------------------------
* Helpers
* ------------------------------------------------------
*/
/**
* Same as [[Parameters]] but omits the first parameter
*/
type OmitFirst<T extends (...args: any) => any> = T extends (x: any, ...args: infer P) => any ? P : never;
/**
* Same as [[Pick]] but picks by value and not the key
*/
type PickProperties<T, P> = Pick<T, {
[K in keyof T]: T[K] extends P ? K : never;
}[keyof T]>;
/**
* Decorator function
*/
type DecoratorFn = (target: any, property: any) => void;
/**
* Typed decorator
*/
type TypedDecorator<PropType> = <TKey extends string, TTarget extends {
[K in TKey]: PropType;
}>(target: TTarget, property: TKey) => void;
/**
* Typed decorator that also represents an optional property
*/
type OptionalTypedDecorator<PropType> = <TKey extends string, TTarget extends {
[K in TKey]?: PropType;
}>(target: TTarget, property: TKey) => void;
/**
* A complex type that filters out functions and relationships from the
* model attributes and consider all other properties as database
* columns. Alternatively, the user can self define a `$columns`
* property.
*/
type ModelAttributes<Model extends LucidRow> = Model['$columns'] extends undefined ? {
[Filtered in {
[P in keyof Model]: P extends keyof LucidRow | 'serializeExtras' ? never : Model[P] extends Function | ModelRelationTypes ? never : P;
}[keyof Model]]: Model[Filtered];
} : Model['$columns'];
/**
* Extract the query scopes of a model
*/
type ExtractScopes<Model> = {
[Scope in keyof PickProperties<Model, QueryScope<QueryScopeCallback>>]: (...args: Model[Scope] extends QueryScopeCallback ? OmitFirst<Model[Scope]> : never) => ExtractScopes<Model>;
};
/**
* Reusable interface to define an object.
*/
interface ModelObject {
[key: string]: any;
}
/**
* Shape of cache node to keep getters optimized
*/
type CacheNode = {
original: any;
resolved: any;
getter: (value: any) => any;
};
/**
* Shape for cherry picking fields
*/
type CherryPickFields = string[] | {
pick?: string[];
omit?: string[];
};
/**
* Shape for cherry picking fields on nested relationships
*/
type CherryPick = {
fields?: CherryPickFields;
relations?: {
[relation: string]: CherryPick;
};
};
/**
* List of events for which a model will trigger hooks
*/
type EventsList = 'save' | 'create' | 'update' | 'delete' | 'fetch' | 'find' | 'paginate';
type HooksHandler<Data, Event extends EventsList> = ((data: Data, event: Event) => Promise<void> | void) | string;
/**
* ------------------------------------------------------
* Query Scope
* ------------------------------------------------------
*/
/**
* Generic query scope callback
*/
type QueryScopeCallback<Model extends LucidModel = LucidModel> = (query: ModelQueryBuilderContract<Model>, ...args: any[]) => void;
/**
* Query scope
*/
type QueryScope<Scope extends QueryScopeCallback> = Scope & {
readonly isQueryScope: true;
};
/**
* A function to mark a method as query scope
*/
type ScopeFn = <Model extends LucidModel, Scope extends QueryScopeCallback = QueryScopeCallback<Model>>(callback: Scope) => QueryScope<Scope>;
/**
* ------------------------------------------------------
* Decorators and Options
* ------------------------------------------------------
*/
/**
* Options for defining a column
*/
type ColumnOptions = {
columnName: string;
serializeAs: string | null;
isPrimary: boolean;
meta?: any;
/**
* Invoked before serializing process happens
*/
serialize?: (value: any, attribute: string, model: LucidRow) => any;
/**
* Invoked before create or update happens
*/
prepare?: (value: any, attribute: string, model: LucidRow) => any;
/**
* Invoked when row is fetched from the database
*/
consume?: (value: any, attribute: string, model: LucidRow) => any;
};
/**
* Shape of column options after they have set on the model
*/
type ModelColumnOptions = ColumnOptions & {
hasGetter: boolean;
hasSetter: boolean;
};
/**
* Represents a computed property on the model
*/
type ComputedOptions = {
serializeAs: string | null;
meta?: any;
};
/**
* Options accepted by the Model.$addRelation method
*/
type ModelRelationOptions = RelationOptions<ModelRelations> | ManyToManyRelationOptions<ModelRelations> | ThroughRelationOptions<ModelRelations>;
/**
* Signature for column decorator function
*/
type ColumnDecorator = (options?: Partial<ColumnOptions>) => DecoratorFn;
/**
* Signature for computed decorator function
*/
type ComputedDecorator = (options?: Partial<ComputedOptions>) => DecoratorFn;
/**
* Decorator for defining date columns
*/
type DateColumnDecorator = (options?: Partial<ColumnOptions & {
autoCreate: boolean;
autoUpdate: boolean;
}>) => OptionalTypedDecorator<DateTime | null>;
/**
* Decorator for defining date time columns. It is same as
* date column as of now
*/
type DateTimeColumnDecorator = DateColumnDecorator;
/**
* Decorator for defining hooks. The generics enforces that
* decorator is used on static properties only
*/
type HooksDecorator = () => <Model extends LucidModel>(target: Model, property: string) => void;
/**
* ------------------------------------------------------
* Model Options
* ------------------------------------------------------
*/
/**
* Model options to be used when making queries
*/
type ModelOptions = {
connection?: string;
profiler?: ProfilerContract | ProfilerRowContract;
};
/**
* Adapter also accepts a client directly
*/
type ModelAdapterOptions = ModelOptions & {
client?: QueryClientContract;
};
/**
* Options used by the method that internally invokes
* the merge method.
] */
type ModelAssignOptions = ModelAdapterOptions & {
allowExtraProperties?: boolean;
};
/**
* Preload function on a model instance
*/
interface LucidRowPreload<Model extends LucidRow> extends Preload<Model, Promise<void>> {
(callback: (preloader: PreloaderContract<Model>) => void): Promise<void>;
}
interface LucidRowAggregate<Model extends LucidRow> extends Preload<Model, Promise<void>> {
(callback: (preloader: PreloaderContract<Model>) => void): Promise<void>;
}
/**
* An extension of the simple paginator with support for serializing models
*/
interface ModelPaginatorContract<Result extends LucidRow> extends Omit<SimplePaginatorContract<Result>, 'toJSON'> {
serialize(cherryPick?: CherryPick): {
meta: any;
data: ModelObject[];
};
toJSON(): {
meta: any;
data: ModelObject[];
};
}
/**
* Lazy load aggregates for a given model instance
*/
interface LazyLoadAggregatesContract<Model extends LucidRow> extends Promise<void> {
loadAggregate: WithAggregate<Model, this>;
loadCount: WithCount<Model, this>;
exec(): Promise<void>;
}
/**
* ------------------------------------------------------
* Model Query Builder
* ------------------------------------------------------
*/
/**
* Model query builder will have extras methods on top of the Database query builder
*/
interface ModelQueryBuilderContract<Model extends LucidModel, Result = InstanceType<Model>> extends ChainableContract, ExcutableQueryBuilderContract<Result[]> {
model: Model;
returning: Returning<this>;
/**
* Define a callback to transform a row
*/
rowTransformer(callback: (row: LucidRow) => void): this;
/**
* Define a custom preloader for the current query
*/
usePreloader(preloader: PreloaderContract<LucidRow>): this;
/**
* Whether or not the query is a child query generated for `.where`
* callbacks
*/
isChildQuery: boolean;
/**
* Alias for the @withScopes method
*/
apply<Scopes extends ExtractScopes<Model>>(callback: (scopes: Scopes) => void): this;
/**
* Apply model query scopes on the query bulder
*/
withScopes<Scopes extends ExtractScopes<Model>>(callback: (scopes: Scopes) => void): this;
/**
* A copy of client options.
*/
readonly clientOptions: ModelAdapterOptions;
/**
* Reference to query client used for making queries
*/
client: QueryClientContract;
/**
* Clone query builder instance
*/
clone<ClonedResult = Result>(): ModelQueryBuilderContract<Model, ClonedResult>;
/**
* A custom set of sideloaded properties defined on the query
* builder, this will be passed to the model instance created
* by the query builder
*/
sideload(value: ModelObject): this;
/**
* Execute and get first result
*/
first(): Promise<Result | null>;
/**
* Return the first matching row or fail
*/
firstOrFail(): Promise<Result>;
/**
* Perform delete operation
*/
del(returning?: OneOrMany<string>): ModelQueryBuilderContract<Model, any>;
delete(returning?: OneOrMany<string>): ModelQueryBuilderContract<Model, any>;
/**
* A shorthand to define limit and offset based upon the
* current page
*/
forPage(page: number, perPage?: number): this;
/**
* Execute query with pagination
*/
paginate(page: number, perPage?: number): Promise<Result extends LucidRow ? ModelPaginatorContract<Result> : SimplePaginatorContract<Result>>;
/**
* Mutations (update and increment can be one query aswell)
*/
update: Update<ModelQueryBuilderContract<Model, any>>;
increment: Counter<ModelQueryBuilderContract<Model, any>>;
decrement: Counter<ModelQueryBuilderContract<Model, any>>;
/**
* Fetch relationship count
*/
withCount: WithCount<InstanceType<Model>, this>;
/**
* Fetch aggregate value for a given relationship
*/
withAggregate: WithAggregate<InstanceType<Model>, this>;
/**
* Add where constraint using the relationship
*/
has: Has<InstanceType<Model>, this>;
orHas: Has<InstanceType<Model>, this>;
andHas: Has<InstanceType<Model>, this>;
doesntHave: Has<InstanceType<Model>, this>;
orDoesntHave: Has<InstanceType<Model>, this>;
andDoesntHave: Has<InstanceType<Model>, this>;
/**
* Add where constraint using the relationship with a custom callback
*/
whereHas: WhereHas<InstanceType<Model>, this>;
orWhereHas: WhereHas<InstanceType<Model>, this>;
andWhereHas: WhereHas<InstanceType<Model>, this>;
whereDoesntHave: WhereHas<InstanceType<Model>, this>;
orWhereDoesntHave: WhereHas<InstanceType<Model>, this>;
andWhereDoesntHave: WhereHas<InstanceType<Model>, this>;
/**
* Define relationships to be preloaded
*/
preload: Preload<InstanceType<Model>, this>;
/**
* Aggregates
*/
count: Aggregate<this>;
countDistinct: Aggregate<this>;
min: Aggregate<this>;
max: Aggregate<this>;
sum: Aggregate<this>;
sumDistinct: Aggregate<this>;
avg: Aggregate<this>;
avgDistinct: Aggregate<this>;
/**
* Executes the callback when dialect matches one of the mentioned
* dialects
*/
ifDialect(dialect: DialectContract['name'] | DialectContract['name'][], matchCallback: (query: this) => any, noMatchCallback?: (query: this) => any): this;
/**
* Executes the callback when dialect matches doesn't all the mentioned
* dialects
*/
unlessDialect(dialect: DialectContract['name'] | DialectContract['name'][], matchCallback: (query: this) => any, noMatchCallback?: (query: this) => any): this;
/**
* Get rows back as a plain javascript object and not an array
* of model instances
*/
pojo<T>(): ModelQueryBuilderContract<Model, T>;
}
/**
* Shape of model keys
*/
interface ModelKeysContract {
add(key: string, value: string): void;
get(key: string, defaultValue: string): string;
get(key: string, defaultValue?: string): string | undefined;
resolve(key: string): string;
all(): ModelObject;
}
/**
* ------------------------------------------------------
* Shape of Model instance
* ------------------------------------------------------
*/
/**
* Shape of the model instance. We prefix the properties with a `$` to
* differentiate between special properties provided by the base
* model but with exception to `save`, `delete`, `fill`, `merge`
* and `toJSON`.
*
* @note: Since the interface name appears next to the inherited model
* methods, we have to choose a succinct name
*/
interface LucidRow {
$attributes: ModelObject;
$extras: ModelObject;
$original: ModelObject;
$preloaded: {
[relation: string]: LucidRow | LucidRow[];
};
/**
* Columns is a property to get type information for model
* attributes. This must be declared by the end user
*/
$columns: undefined;
$sideloaded: ModelObject;
$primaryKeyValue?: number | string;
$isPersisted: boolean;
$isNew: boolean;
$isLocal: boolean;
$dirty: ModelObject;
$isDirty: boolean;
$isDeleted: boolean;
$options?: ModelOptions;
$trx?: TransactionClientContract;
$setOptionsAndTrx(options?: ModelAdapterOptions): void;
useTransaction(trx: TransactionClientContract): this;
useConnection(connection: string): this;
/**
* Gives an option to the end user to define constraints for update, insert
* and delete queries. Since the query builder for these queries aren't
* exposed to the end user, this method opens up the API to build
* custom queries.
*/
$getQueryFor(action: 'insert', client: QueryClientContract): ReturnType<QueryClientContract['insertQuery']>;
$getQueryFor(action: 'update' | 'delete' | 'refresh', client: QueryClientContract): ModelQueryBuilderContract<LucidModel>;
/**
* Read/write attributes. Following methods are intentionally loosely typed,
* so that one can bypass the public facing API and type checking for
* advanced use cases
*/
$setAttribute(key: string, value: any): void;
$getAttribute(key: string): any;
$getAttributeFromCache(key: string, callback: CacheNode['getter']): any;
/**
* Read/write realtionships. Following methods are intentionally loosely typed,
* so that one can bypass the public facing API and type checking for
* advanced use cases
*/
$hasRelated(key: string): boolean;
$setRelated(key: string, result: OneOrMany<LucidRow> | null): void;
$pushRelated(key: string, result: OneOrMany<LucidRow> | null): void;
$getRelated(key: string, defaultValue?: any): OneOrMany<LucidRow> | undefined | null;
/**
* Consume the adapter result and hydrate the model
*/
$consumeAdapterResult(adapterResult: ModelObject, sideloadAttributes?: ModelObject): void;
$hydrateOriginals(): void;
fill(value: Partial<ModelAttributes<this>>, allowExtraProperties?: boolean): this;
merge(value: Partial<ModelAttributes<this>>, allowExtraProperties?: boolean): this;
/**
* Enable force update even when no attributes
* are dirty
*/
enableForceUpdate(): this;
/**
* Actions to perform on the instance
*/
save(): Promise<this>;
delete(): Promise<void>;
refresh(): Promise<this>;
/**
* Load relationships onto the instance
*/
load: LucidRowPreload<this>;
/**
* Alias for "load"
* @deprecated
*/
preload: LucidRowPreload<this>;
/**
* Load aggregates
*/
loadAggregate: <Self extends this, Name extends ExtractModelRelations<Self>, RelatedBuilder = Self[Name] extends ModelRelations ? Self[Name]['subQuery'] : never>(name: Name, callback: (builder: RelatedBuilder) => void) => LazyLoadAggregatesContract<Self>;
/**
* Load count
*/
loadCount: <Self extends this, Name extends ExtractModelRelations<Self>, RelatedBuilder = Self[Name] extends ModelRelations ? Self[Name]['subQuery'] : never>(name: Name, callback?: (builder: RelatedBuilder) => void) => LazyLoadAggregatesContract<Self>;
/**
* Serialize attributes to a plain object
*/
serializeAttributes(fields?: CherryPickFields, raw?: boolean): ModelObject;
/**
* Serialize computed properties to a plain object
*/
serializeComputed(fields?: CherryPickFields): ModelObject;
/**
* Serialize relationships to key-value pair of model instances and
* their serializeAs keys
*/
serializeRelations(fields: undefined, raw: true): {
[key: string]: LucidRow | LucidRow[];
};
/**
* Serialize relationships to key-value pair of plain nested objects
*/
serializeRelations(cherryPick: CherryPick['relations'] | undefined, raw: false | undefined): ModelObject;
serializeRelations(cherryPick?: CherryPick['relations'], raw?: boolean): ModelObject;
/**
* Serialize model to a plain object
*/
serialize(cherryPick?: CherryPick): ModelObject;
/**
* Converts model to an object. It just returns the properties
* of the model, along with preloaded relationships
*/
toObject(): ModelObject;
/**
* Serialize everything
*/
toJSON(): ModelObject;
/**
* Returns related model for a given relationship
*/
related<Name extends ExtractModelRelations<this>>(relation: Name): this[Name] extends ModelRelations ? this[Name]['client'] : never;
}
/**
* ------------------------------------------------------
* Shape of Model constructor
* ------------------------------------------------------
*/
/**
* Shape of the model static properties. The `$` prefix is to denote
* special properties from the base model.
*
* @note: Since the interface name appears next to the inherited model
* methods, we have to choose a succinct name
*/
interface LucidModel {
/**
* Whether or not model has been booted. After this model configurations
* are ignored
*/
readonly booted: boolean;
/**
* A map of defined columns
*/
$columnsDefinitions: Map<string, ModelColumnOptions>;
/**
* A map of defined relationships
*/
$relationsDefinitions: Map<string, RelationshipsContract>;
/**
* A map of computed properties
*/
$computedDefinitions: Map<string, ComputedOptions>;
/**
* The primary key for finding unique referencing to a
* model
*/
primaryKey: string;
/**
* Custom database connection to use
*/
connection?: string;
/**
* Naming strategy to use
*/
namingStrategy: NamingStrategyContract;
/**
* Database table to use
*/
table: string;
/**
* Self assign the primary instead of relying on the database to
* return it back
*/
selfAssignPrimaryKey: boolean;
/**
* Adapter to work as a bridge between query builder and the model
*/
$adapter: AdapterContract;
/**
* Reference to hooks
*/
$hooks: Hooks;
/**
* A copy of internal keys mapping. One should be able to resolve between
* all key versions
*/
$keys: {
attributesToColumns: ModelKeysContract;
attributesToSerialized: ModelKeysContract;
columnsToAttributes: ModelKeysContract;
columnsToSerialized: ModelKeysContract;
serializedToColumns: ModelKeysContract;
serializedToAttributes: ModelKeysContract;
};
/**
* Creating model from adapter results
*/
$createFromAdapterResult<T extends LucidModel>(this: T, result?: ModelObject, sideloadAttributes?: ModelObject, options?: ModelAdapterOptions): null | InstanceType<T>;
/**
* Creating multiple model instances from an array of adapter
* result
*/
$createMultipleFromAdapterResult<T extends LucidModel>(this: T, results: ModelObject[], sideloadAttributes?: ModelObject, options?: ModelAdapterOptions): InstanceType<T>[];
/**
* Managing columns
*/
$addColumn(name: string, options: Partial<ColumnOptions>): ColumnOptions;
$hasColumn(name: string): boolean;
$getColumn(name: string): ModelColumnOptions | undefined;
/**
* Managing computed columns
*/
$addComputed(name: string, options: Partial<ComputedOptions>): ComputedOptions;
$hasComputed(name: string): boolean;
$getComputed(name: string): ComputedOptions | undefined;
/**
* Managing relationships
*/
$addRelation(name: string, type: ModelRelationTypes['__opaque_type'], relatedModel: () => LucidModel, options: ModelRelationOptions): void;
/**
* Find if a relationship exists
*/
$hasRelation(name: string): boolean;
/**
* Get relationship declaration
*/
$getRelation<Model extends LucidModel, Name extends ExtractModelRelations<InstanceType<Model>>>(this: Model, name: Name): InstanceType<Model>[Name] extends ModelRelations ? InstanceType<Model>[Name]['client']['relation'] : RelationshipsContract;
$getRelation<Model extends LucidModel>(this: Model, name: string): RelationshipsContract;
/**
* Define a static property on the model using the inherit or
* define strategy.
*
* Inherit strategy will clone the property from the parent model
* and will set it on the current model
*/
$defineProperty<Model extends LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: 'inherit' | 'define' | ((value: Model[Prop]) => Model[Prop])): void;
/**
* Boot model
*/
boot(): void;
/**
* Register a before hook
*/
before<Model extends LucidModel, Event extends 'find' | 'fetch'>(this: Model, event: Event, handler: HooksHandler<ModelQueryBuilderContract<Model>, Event>): void;
before<Model extends LucidModel>(this: Model, event: 'paginate', handler: HooksHandler<[
ModelQueryBuilderContract<Model>,
ModelQueryBuilderContract<Model>
], 'paginate'>): void;
before<Model extends LucidModel, Event extends EventsList>(this: Model, event: Event, handler: HooksHandler<InstanceType<Model>, Event>): void;
/**
* Register an after hook
*/
after<Model extends LucidModel>(this: Model, event: 'fetch', handler: HooksHandler<InstanceType<Model>[], 'fetch'>): void;
after<Model extends LucidModel>(this: Model, event: 'paginate', handler: HooksHandler<ModelPaginatorContract<InstanceType<Model>>, 'paginate'>): void;
after<Model extends LucidModel, Event extends EventsList>(this: Model, event: Event, handler: HooksHandler<InstanceType<Model>, Event>): void;
/**
* Create model and return its instance back
*/
create<T extends LucidModel>(this: T, values: Partial<ModelAttributes<InstanceType<T>>>, options?: ModelAssignOptions): Promise<InstanceType<T>>;
/**
* Create many of model instances
*/
createMany<T extends LucidModel>(this: T, values: Partial<ModelAttributes<InstanceType<T>>>[], options?: ModelAssignOptions): Promise<InstanceType<T>[]>;
/**
* Find one using the primary key
*/
find<T extends LucidModel>(this: T, value: any, options?: ModelAdapterOptions): Promise<null | InstanceType<T>>;
/**
* Find one using the primary key or fail
*/
findOrFail<T extends LucidModel>(this: T, value: any, options?: ModelAdapterOptions): Promise<InstanceType<T>>;
/**
* Find one using a key-value pair
*/
findBy<T extends LucidModel>(this: T, key: string, value: any, options?: ModelAdapterOptions): Promise<null | InstanceType<T>>;
/**
* Find one using a key-value pair or fail
*/
findByOrFail<T extends LucidModel>(this: T, key: string, value: any, options?: ModelAdapterOptions): Promise<InstanceType<T>>;
/**
* Same as `query().first()`
*/
first<T extends LucidModel>(this: T, options?: ModelAdapterOptions): Promise<null | InstanceType<T>>;
/**
* Same as `query().firstOrFail()`
*/
firstOrFail<T extends LucidModel>(this: T, options?: ModelAdapterOptions): Promise<InstanceType<T>>;
/**
* Find many using an array of primary keys
*/
findMany<T extends LucidModel>(this: T, value: any[], options?: ModelAdapterOptions): Promise<InstanceType<T>[]>;
/**
* Returns the first row or create a new instance of model without
* persisting it
*/
firstOrNew<T extends LucidModel>(this: T, searchPayload: Partial<ModelAttributes<InstanceType<T>>>, savePayload?: Partial<ModelAttributes<InstanceType<T>>>, options?: ModelAssignOptions): Promise<InstanceType<T>>;
/**
* Returns the first row or save it to the database
*/
firstOrCreate<T extends LucidModel>(this: T, searchPayload: Partial<ModelAttributes<InstanceType<T>>>, savePayload?: Partial<ModelAttributes<InstanceType<T>>>, options?: ModelAssignOptions): Promise<InstanceType<T>>;
/**
* Returns the first row or save it to the database
*/
updateOrCreate<T extends LucidModel>(this: T, searchPayload: Partial<ModelAttributes<InstanceType<T>>>, updatePayload: Partial<ModelAttributes<InstanceType<T>>>, options?: ModelAssignOptions): Promise<InstanceType<T>>;
/**
* Find rows or create in-memory instances of the missing
* one's.
*/
fetchOrNewUpMany<T extends LucidModel>(this: T, predicate: keyof ModelAttributes<InstanceType<T>> | (keyof ModelAttributes<InstanceType<T>>)[], payload: Partial<ModelAttributes<InstanceType<T>>>[], options?: ModelAssignOptions): Promise<InstanceType<T>[]>;
/**
* Find rows or create many when missing. One db call is invoked
* for each create
*/
fetchOrCreateMany<T extends LucidModel>(this: T, predicate: keyof ModelAttributes<InstanceType<T>> | (keyof ModelAttributes<InstanceType<T>>)[], payload: Partial<ModelAttributes<InstanceType<T>>>[], options?: ModelAssignOptions): Promise<InstanceType<T>[]>;
/**
* Update existing rows or create new one's.
*/
updateOrCreateMany<T extends LucidModel>(this: T, predicate: keyof ModelAttributes<InstanceType<T>> | (keyof ModelAttributes<InstanceType<T>>)[], payload: Partial<ModelAttributes<InstanceType<T>>>[], options?: ModelAssignOptions): Promise<InstanceType<T>[]>;
/**
* Fetch all rows
*/
all<T extends LucidModel>(this: T, options?: ModelAdapterOptions): Promise<InstanceType<T>[]>;
/**
* Returns the query for fetching a model instance
*/
query<Model extends LucidModel, Result = InstanceType<Model>>(this: Model, options?: ModelAdapterOptions): ModelQueryBuilderContract<Model, Result>;
/**
* Truncate model table
*/
truncate(cascade?: boolean): Promise<void>;
new (): LucidRow;
}
/**
* ------------------------------------------------------
* Database Adapter
* ------------------------------------------------------
*/
/**
* Every adapter must adhere to the Adapter contract
*/
interface AdapterContract {
/**
* Returns query client for a model instance by inspecting it's options
*/
modelClient(instance: LucidRow): QueryClientContract;
/**
* Returns query client for a model constructor
*/
modelConstructorClient(modelConstructor: LucidModel, options?: ModelAdapterOptions): QueryClientContract;
/**
* Delete model instance
*/
delete(instance: LucidRow): Promise<void>;
/**
* Refresh model instance to reflect new values
* from the database
*/
refresh(instance: LucidRow): Promise<void>;
/**
* Perform insert
*/
insert(instance: LucidRow, attributes: ModelObject): Promise<void>;
/**
* Perform update
*/
update(instance: LucidRow, attributes: ModelObject): Promise<void>;
/**
* Must return the query builder for the model
*/
query(modelConstructor: LucidModel, options?: ModelAdapterOptions): ModelQueryBuilderContract<LucidModel, LucidRow>;
}
/**
* Naming strategy for model
*/
interface NamingStrategyContract {
/**
* The default table name for the given model
*/
tableName(model: LucidModel): string;
/**
* The database column name for a given model attribute
*/
columnName(model: LucidModel, attributeName: string): string;
/**
* The post serialization name for a given model attribute
*/
serializedName(model: LucidModel, attributeName: string): string;
/**
* The local key for a given model relationship
*/
relationLocalKey(relation: ModelRelations['__opaque_type'], model: LucidModel, relatedModel: LucidModel, relationName: string): string;
/**
* The foreign key for a given model relationship
*/
relationForeignKey(relation: ModelRelations['__opaque_type'], model: LucidModel, relatedModel: LucidModel, relationName: string): string;
/**
* Pivot table name for many to many relationship
*/
relationPivotTable(relation: 'manyToMany', model: LucidModel, relatedModel: LucidModel, relationName: string): string;
/**
* Pivot foreign key for many to many relationship
*/
relationPivotForeignKey(relation: 'manyToMany', model: LucidModel, relatedModel: LucidModel, relationName: string): string;
/**
* Keys for the pagination meta
*/
paginationMetaKeys(): SimplePaginatorMetaKeys;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+47
View File
@@ -0,0 +1,47 @@
declare module '@ioc:Adonis/Lucid/Orm' {
import { SimplePaginatorMetaKeys } from '@ioc:Adonis/Lucid/Database';
const SnakeCaseNamingStrategy: {
new (): NamingStrategyContract;
};
const scope: ScopeFn;
const BaseModel: LucidModel;
/**
* Relationships
*/
const hasOne: HasOneDecorator;
const belongsTo: BelongsToDecorator;
const hasMany: HasManyDecorator;
const manyToMany: ManyToManyDecorator;
const hasManyThrough: HasManyThroughDecorator;
/**
* Hooks
*/
const beforeSave: HooksDecorator;
const afterSave: HooksDecorator;
const beforeCreate: HooksDecorator;
const afterCreate: HooksDecorator;
const beforeUpdate: HooksDecorator;
const afterUpdate: HooksDecorator;
const beforeDelete: HooksDecorator;
const afterDelete: HooksDecorator;
const beforeFind: HooksDecorator;
const afterFind: HooksDecorator;
const beforeFetch: HooksDecorator;
const afterFetch: HooksDecorator;
const beforePaginate: HooksDecorator;
const afterPaginate: HooksDecorator;
const ModelPaginator: {
namingStrategy: {
paginationMetaKeys(): SimplePaginatorMetaKeys;
};
new <Row extends LucidRow>(total: number, perPage: number, currentPage: number, ...rows: Row[]): ModelPaginatorContract<Row>;
};
/**
* Columns and computed
*/
const column: ColumnDecorator & {
date: DateColumnDecorator;
dateTime: DateTimeColumnDecorator;
};
const computed: ComputedDecorator;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+701
View File
@@ -0,0 +1,701 @@
/// <reference types="node" />
declare module '@ioc:Adonis/Lucid/Database' {
import { Knex } from 'knex';
import { DialectContract, QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
/**
* Extracted from ts-essentials
*/
type Dictionary<T, K extends string | number = string> = {
[key in K]: T;
};
/**
* Get one or many of a generic
*/
type OneOrMany<T> = T | T[];
/**
* Allowing a generic value along with raw query instance or a subquery
* instance
*/
type ValueWithSubQueries<T> = T | ChainableContract | RawQuery;
/**
* Acceptable raw queries
*/
type RawQuery = RawBuilderContract | RawQueryBuilderContract | Knex.Raw | Knex.RawQueryBuilder;
/**
* A known set of values allowed when defining values for different
* clauses
*/
type StrictValues = string | number | boolean | Date | Array<string> | Array<number> | Array<Date> | Array<boolean> | Buffer | RawQuery | ReferenceBuilderContract;
/**
* Strict set of allowed values except the raw queries
*/
type StrictValuesWithoutRaw = Exclude<StrictValues, RawQuery>;
/**
* Shape of raw query bindings
*/
type RawQueryBindings = {
[key: string]: StrictValues;
} | StrictValues[];
/**
* A builder method to allow raw queries. However, the return type is the
* instance of current query builder. This is used for `.{verb}Raw` methods.
*/
interface RawQueryFn<Builder extends ChainableContract> {
(sql: string | RawQuery): Builder;
(sql: string, bindings: RawQueryBindings): Builder;
}
/**
* Query callback is used to write wrapped queries. We get rid of `this` from
* knex, since it makes everything confusing.
*/
type QueryCallback<Builder> = (builder: Builder) => void;
/**
* Shape of the function accepted by the chainable query builder to
* pass lucid query builder to wrapped callbacks like
* `.where(function () {})`.
*
* - This method will accept the wrapped callback
* - Return a new method, that is accepted by Knex.
* - When knex calls that method, this method will invoke the user wrapped
* callback, but instead of passing the knex query builder, it will
* pass the appropriate lucid query builder.
*/
type DBQueryCallback = (userFn: QueryCallback<ChainableContract>, keysResolver?: (columnName: string) => string) => (builder: Knex.QueryBuilder) => void;
/**
* Possible signatures for a select method on database query builder.
*/
interface DatabaseQueryBuilderSelect<Builder extends ChainableContract> {
/**
* Selecting columns as a dictionary with key as the alias and value is
* the original column.
*/
(columns: Dictionary<string, string>): Builder;
/**
* An array of values with subqueries
*/
(columns: ValueWithSubQueries<string | number>[]): Builder;
/**
* A spread of array arguments
*/
(...columns: ValueWithSubQueries<string | number>[]): Builder;
/**
* Wildcard selector.
*/
(column: '*'): Builder;
}
/**
* Possible signatures for adding a where clause
*/
interface Where<Builder extends ChainableContract> {
/**
* Callback for wrapped clauses
*/
(callback: QueryCallback<Builder>): Builder;
/**
* Passing an object of named key-value pair
*/
(clause: Dictionary<any, string>): Builder;
/**
* Key-value pair. The value can also be a subquery
*/
(key: string | RawQuery, value: StrictValues | ChainableContract): Builder;
(key: string | RawQuery, operator: string, value: StrictValues | ChainableContract): Builder;
}
/**
* Possible signatures for adding a whereLike clause
*/
interface WhereLike<Builder extends ChainableContract> {
/**
* Key-value pair. The value can also be a subquery
*/
(key: string, value: StrictValues | ChainableContract): Builder;
}
/**
* Possible signatures for adding a whereLike clause
*/
interface WhereJson<Builder extends ChainableContract> {
/**
* Key-value pair. The value can also be a subquery
*/
(column: string, value: Record<string, any> | ChainableContract | QueryCallback<Builder>): Builder;
}
interface WhereJsonPath<Builder extends ChainableContract> {
(column: string, jsonPath: string, value: string | number | boolean | string[] | number[] | boolean[] | Record<string, any> | ChainableContract | QueryCallback<Builder>): Builder;
(column: string, jsonPath: string, operator: string, value: string | number | boolean | string[] | number[] | boolean[] | Record<string, any> | ChainableContract | QueryCallback<Builder>): Builder;
}
/**
* Possible signatures for adding a where column clause
*/
interface WhereColumn<Builder extends ChainableContract> {
/**
* Key-value pair.
*/
(column: string | RawQuery, comparisonColumn: string): Builder;
(column: string | RawQuery, operator: string, comparisonColumn: string): Builder;
}
/**
* Possible signatures for adding where in clause.
*/
interface WhereIn<Builder extends ChainableContract> {
/**
* Column name and array of values
*/
(K: string | RawQuery, value: StrictValues[]): Builder;
/**
* Column names and array of values as an 2d array
*/
(K: string[], value: StrictValues[][]): Builder;
/**
* Column name with a subquery for a callback that yields an array of
* results
*/
(k: string | RawQuery, subquery: ChainableContract | QueryCallback<Builder> | RawBuilderContract | RawQuery): Builder;
/**
* Column names along with a subquery that yields an array
*/
(k: string[], subquery: ChainableContract | RawBuilderContract | RawQuery): Builder;
}
/**
* Possible signatures for adding whereNull clause.
*/
interface WhereNull<Builder extends ChainableContract> {
(key: string | RawQuery): Builder;
}
/**
* Possibles signatures for adding a where exists clause
*/
interface WhereExists<Builder extends ChainableContract> {
(callback: QueryCallback<Builder> | ChainableContract | RawBuilderContract | RawQuery): Builder;
}
/**
* Possibles signatures for adding a where between clause
*/
interface WhereBetween<Builder extends ChainableContract> {
/**
* Accept any string as a key for supporting prefix columns
*/
(key: string | RawQuery, value: [StrictValues | ChainableContract, StrictValues | ChainableContract]): Builder;
}
/**
* Possible signatures for join query
*/
interface Join<Builder extends ChainableContract> {
/**
* Defining the join table with primary and secondary columns
* to match
*/
(table: string, primaryColumn: string, secondaryColumn: string): Builder;
/**
* Defining the join table with primary and secondary columns
* to match, where secondary column is output of a raw query
*/
(table: string, primaryColumn: string, raw: RawQuery): Builder;
/**
* Defining the join table with primary and secondary columns
* to match with a custom operator
*/
(table: string, primaryColumn: string, operator: string, secondaryColumn: string): Builder;
/**
* Join with a callback. The callback receives an array of join class from
* knex directly.
*/
(table: string, callback: Knex.JoinCallback): Builder;
}
/**
* Possible signatures for a distinct clause
*/
interface Distinct<Builder extends ChainableContract> {
(columns: string[]): Builder;
(...columns: string[]): Builder;
(column: '*'): Builder;
}
/**
* The signatures are same as the `distinct` method. For subqueries and
* raw queries, one must use `groupByRaw`.
*/
interface GroupBy<Builder extends ChainableContract> extends Distinct<Builder> {
}
/**
* Possible signatures for aggregate functions. Aggregates will push to the
* result set. Unlike knex, we force defining aliases for each aggregate.
*/
interface Aggregate<Builder extends ChainableContract> {
/**
* Accepting column with the alias for the count.
*/
(column: OneOrMany<ValueWithSubQueries<string>>, alias?: string): Builder;
/**
* Accepting an object for multiple counts in a single query.
*/
(columns: Dictionary<OneOrMany<ValueWithSubQueries<string>>, string>): Builder;
}
/**
* Possible signatures for orderBy method.
*/
interface OrderBy<Builder extends ChainableContract> {
/**
* Order by a column and optional direction
*/
(column: string | ChainableContract | RawBuilderContract | RawQuery, direction?: 'asc' | 'desc'): Builder;
/**
* Order by multiple columns in default direction
*/
(columns: string[]): Builder;
/**
* Order by multiple columns and custom direction for each of them
*/
(columns: {
column: string | ChainableContract | RawBuilderContract | RawQuery;
order?: 'asc' | 'desc';
}[]): Builder;
}
/**
* Possible signatures for a union clause
*/
interface Union<Builder extends ChainableContract> {
(callback: OneOrMany<QueryCallback<Builder>>, wrap?: boolean): Builder;
(subquery: OneOrMany<ChainableContract | RawQuery>, wrap?: boolean): Builder;
}
/**
* Same signature as union
*/
interface UnionAll<Builder extends ChainableContract> extends Union<Builder> {
}
/**
* Same signature as union
*/
interface Intersect<Builder extends ChainableContract> extends Union<Builder> {
}
/**
* Possible signatures for having clause
*/
interface Having<Builder extends ChainableContract> {
/**
* A subquery callback
*/
(callback: QueryCallback<Builder> | RawBuilderContract | RawQuery): Builder;
/**
* Key operator and value. Value can be a subquery as well
*/
(key: string | RawQuery, operator: string, value: StrictValues | ChainableContract | RawBuilderContract | RawQuery): Builder;
}
/**
* Possible signatures for `having in` clause.
*/
interface HavingIn<Builder extends ChainableContract> {
/**
* Key and an array of literal values, raw queries or
* subqueries.
*/
(key: string | RawQuery, value: (StrictValues | ChainableContract | RawBuilderContract | RawQuery)[]): Builder;
/**
* Key, along with a query callback
*/
(key: string | RawQuery, callback: QueryCallback<Builder>): Builder;
}
/**
* Possible signatures for `having null` clause
*/
interface HavingNull<Builder extends ChainableContract> extends WhereNull<Builder> {
}
/**
* Possible signatures for `having exists` clause
*/
interface HavingExists<Builder extends ChainableContract> {
/**
* A query callback or a sub query
*/
(callback: QueryCallback<Builder> | ChainableContract): Builder;
}
/**
* Possible signatures for having between
*/
interface HavingBetween<Builder extends ChainableContract> extends WhereBetween<Builder> {
}
/**
* Possible signatures of `with` CTE
*/
interface With<Builder extends ChainableContract> {
(alias: string, query: RawQuery | ChainableContract | QueryCallback<Builder>, columns?: string[]): Builder;
}
/**
* Possible signatures for defining table for a select query.
*/
interface FromTable<Builder extends ChainableContract> {
(table: string | Dictionary<string, string> | QueryCallback<Builder> | ChainableContract): Builder;
}
/**
* Possible signatures for the `returning` method.
*/
interface Returning<Builder> {
(column: OneOrMany<string>): Builder;
}
/**
* Possible signatures for performing an update
*/
interface Update<Builder extends ChainableContract> {
/**
* Accepts an array of object of named key/value pair and returns an array
* of Generic return columns.
*/
(values: Dictionary<any, string>, returning?: OneOrMany<string>): Builder;
/**
* Accepts a key-value pair to update.
*/
(column: string, value: any, returning?: OneOrMany<string>): Builder;
}
/**
* Possible signatures for incrementing/decrementing
* values
*/
interface Counter<Builder extends ChainableContract> {
(column: string, counter?: number): Builder;
(values: Dictionary<number, string>): Builder;
}
/**
* Possible signatures for an insert query
*/
interface Insert<Builder extends InsertQueryBuilderContract> {
(values: Dictionary<any, string>): Builder;
}
/**
* Possible signatures for doing multiple inserts in a single query
*/
interface MultiInsert<Builder extends InsertQueryBuilderContract> {
(values: Dictionary<any, string>[]): Builder;
}
/**
* The chainable contract has all the methods that can be chained
* to build a query. This interface will never have any
* methods to execute a query.
*/
interface ChainableContract {
knexQuery: Knex.QueryBuilder;
columns: (string | Knex.QueryBuilder | Knex.RawQueryBuilder)[];
subQueryAlias?: string;
hasAggregates: boolean;
hasGroupBy: boolean;
hasUnion: boolean;
keysResolver?: (columnName: string) => string;
from: FromTable<this>;
select: DatabaseQueryBuilderSelect<this>;
wrapExisting(): this;
where: Where<this>;
orWhere: Where<this>;
andWhere: Where<this>;
whereNot: Where<this>;
orWhereNot: Where<this>;
andWhereNot: Where<this>;
whereColumn: WhereColumn<this>;
orWhereColumn: WhereColumn<this>;
andWhereColumn: WhereColumn<this>;
whereNotColumn: WhereColumn<this>;
orWhereNotColumn: WhereColumn<this>;
andWhereNotColumn: WhereColumn<this>;
whereIn: WhereIn<this>;
orWhereIn: WhereIn<this>;
andWhereIn: WhereIn<this>;
whereNotIn: WhereIn<this>;
orWhereNotIn: WhereIn<this>;
andWhereNotIn: WhereIn<this>;
whereNull: WhereNull<this>;
orWhereNull: WhereNull<this>;
andWhereNull: WhereNull<this>;
whereNotNull: WhereNull<this>;
orWhereNotNull: WhereNull<this>;
andWhereNotNull: WhereNull<this>;
whereExists: WhereExists<this>;
orWhereExists: WhereExists<this>;
andWhereExists: WhereExists<this>;
whereNotExists: WhereExists<this>;
orWhereNotExists: WhereExists<this>;
andWhereNotExists: WhereExists<this>;
whereBetween: WhereBetween<this>;
orWhereBetween: WhereBetween<this>;
andWhereBetween: WhereBetween<this>;
whereNotBetween: WhereBetween<this>;
orWhereNotBetween: WhereBetween<this>;
andWhereNotBetween: WhereBetween<this>;
whereRaw: RawQueryFn<this>;
orWhereRaw: RawQueryFn<this>;
andWhereRaw: RawQueryFn<this>;
whereLike: WhereLike<this>;
orWhereLike: WhereLike<this>;
andWhereLike: WhereLike<this>;
whereILike: WhereLike<this>;
orWhereILike: WhereLike<this>;
andWhereILike: WhereLike<this>;
whereJson: WhereJson<this>;
orWhereJson: WhereJson<this>;
andWhereJson: WhereJson<this>;
whereNotJson: WhereJson<this>;
orWhereNotJson: WhereJson<this>;
andWhereNotJson: WhereJson<this>;
whereJsonSuperset: WhereJson<this>;
orWhereJsonSuperset: WhereJson<this>;
andWhereJsonSuperset: WhereJson<this>;
whereNotJsonSuperset: WhereJson<this>;
orWhereNotJsonSuperset: WhereJson<this>;
andWhereNotJsonSuperset: WhereJson<this>;
whereJsonSubset: WhereJson<this>;
orWhereJsonSubset: WhereJson<this>;
andWhereJsonSubset: WhereJson<this>;
whereNotJsonSubset: WhereJson<this>;
orWhereNotJsonSubset: WhereJson<this>;
andWhereNotJsonSubset: WhereJson<this>;
whereJsonPath: WhereJsonPath<this>;
orWhereJsonPath: WhereJsonPath<this>;
andWhereJsonPath: WhereJsonPath<this>;
join: Join<this>;
innerJoin: Join<this>;
leftJoin: Join<this>;
leftOuterJoin: Join<this>;
rightJoin: Join<this>;
rightOuterJoin: Join<this>;
fullOuterJoin: Join<this>;
crossJoin: Join<this>;
joinRaw: RawQueryFn<this>;
having: Having<this>;
orHaving: Having<this>;
andHaving: Having<this>;
havingIn: HavingIn<this>;
orHavingIn: HavingIn<this>;
andHavingIn: HavingIn<this>;
havingNotIn: HavingIn<this>;
orHavingNotIn: HavingIn<this>;
andHavingNotIn: HavingIn<this>;
havingNull: HavingNull<this>;
orHavingNull: HavingNull<this>;
andHavingNull: HavingNull<this>;
havingNotNull: HavingNull<this>;
orHavingNotNull: HavingNull<this>;
andHavingNotNull: HavingNull<this>;
havingExists: HavingExists<this>;
orHavingExists: HavingExists<this>;
andHavingExists: HavingExists<this>;
havingNotExists: HavingExists<this>;
orHavingNotExists: HavingExists<this>;
andHavingNotExists: HavingExists<this>;
havingBetween: HavingBetween<this>;
orHavingBetween: HavingBetween<this>;
andHavingBetween: HavingBetween<this>;
havingNotBetween: HavingBetween<this>;
orHavingNotBetween: HavingBetween<this>;
andHavingNotBetween: HavingBetween<this>;
havingRaw: RawQueryFn<this>;
orHavingRaw: RawQueryFn<this>;
andHavingRaw: RawQueryFn<this>;
distinct: Distinct<this>;
distinctOn: Distinct<this>;
groupBy: GroupBy<this>;
groupByRaw: RawQueryFn<this>;
orderBy: OrderBy<this>;
orderByRaw: RawQueryFn<this>;
union: Union<this>;
unionAll: UnionAll<this>;
intersect: Intersect<this>;
with: With<this>;
withRecursive: With<this>;
withMaterialized: With<this>;
withNotMaterialized: With<this>;
withSchema(schema: string): this;
as(name: string): this;
offset(offset: number): this;
limit(limit: number): this;
clearSelect(): this;
clearWhere(): this;
clearOrder(): this;
clearHaving(): this;
clearLimit(): this;
clearOffset(): this;
forUpdate(...tableNames: string[]): this;
forShare(...tableNames: string[]): this;
skipLocked(): this;
noWait(): this;
/**
* Executes the callback when condition is truthy
*/
if(condition: any, matchCallback: (query: this) => any, noMatchCallback?: (query: this) => any): this;
/**
* Executes the callback when condition is falsy
*/
unless(condition: any, matchCallback: (query: this) => any, noMatchCallback?: (query: this) => any): this;
/**
* Write blocks to match from
*/
match(...blocks: ([condition: any, callback: (query: this) => any] | ((query: this) => any))[]): this;
}
/**
* Shape of the raw query that can also be passed as a value to
* other queries
*/
interface RawQueryBuilderContract<Result = any> extends ExcutableQueryBuilderContract<Result> {
knexQuery: Knex.Raw;
client: QueryClientContract;
wrap(before: string, after: string): this;
}
/**
* Reference builder
*/
interface ReferenceBuilderContract {
withSchema(name: string): this;
as(name: string): this;
toKnex(client: Knex.Client): Knex.Ref<string, any>;
}
/**
* Static raw builder
*/
interface RawBuilderContract {
wrap(before: string, after: string): this;
toKnex(client: Knex.Client): Knex.Raw;
}
/**
* The keys for the simple paginator meta
* data
*/
type SimplePaginatorMetaKeys = {
total: string;
perPage: string;
currentPage: string;
lastPage: string;
firstPage: string;
firstPageUrl: string;
lastPageUrl: string;
nextPageUrl: string;
previousPageUrl: string;
};
/**
* Shape of the simple paginator that works with offset and limit
*/
interface SimplePaginatorContract<Result> extends Array<Result> {
all(): Result[];
readonly firstPage: number;
readonly perPage: number;
readonly currentPage: number;
readonly lastPage: number;
readonly hasPages: boolean;
readonly hasMorePages: boolean;
readonly isEmpty: boolean;
readonly total: number;
readonly hasTotal: boolean;
namingStrategy: {
paginationMetaKeys(): SimplePaginatorMetaKeys;
};
baseUrl(url: string): this;
queryString(values: {
[key: string]: any;
}): this;
getUrl(page: number): string;
getMeta(): any;
getNextPageUrl(): string | null;
getPreviousPageUrl(): string | null;
getUrlsForRange(start: number, end: number): {
url: string;
page: number;
isActive: boolean;
}[];
toJSON(): {
meta: any;
data: Result[];
};
}
/**
* Database query builder exposes the API to construct SQL query using fluent
* chainable API
*/
interface DatabaseQueryBuilderContract<Result = Dictionary<any, string>> extends ChainableContract, ExcutableQueryBuilderContract<Result[]> {
client: QueryClientContract;
returning: Returning<this>;
/**
* Clone current query
*/
clone<ClonedResult = Result>(): DatabaseQueryBuilderContract<ClonedResult>;
/**
* Execute and get first result
*/
first(): Promise<Result | null>;
/**
* Execute and get first result or fail
*/
firstOrFail(): Promise<Result>;
/**
* Perform delete operation
*/
del(returning?: OneOrMany<string>): this;
delete(returning?: OneOrMany<string>): this;
/**
* A shorthand to define limit and offset based upon the
* current page
*/
forPage(page: number, perPage?: number): this;
/**
* Execute query with pagination
*/
paginate(page: number, perPage?: number): Promise<SimplePaginatorContract<Result>>;
/**
* Mutations (update and increment can be one query aswell)
*/
update: Update<this>;
increment: Counter<this>;
decrement: Counter<this>;
/**
* Aggregates
*/
count: Aggregate<this>;
countDistinct: Aggregate<this>;
min: Aggregate<this>;
max: Aggregate<this>;
sum: Aggregate<this>;
sumDistinct: Aggregate<this>;
avg: Aggregate<this>;
avgDistinct: Aggregate<this>;
/**
* Executes the callback when dialect matches one of the mentioned
* dialects
*/
ifDialect(dialect: DialectContract['name'] | DialectContract['name'][], matchCallback: (query: this) => any, noMatchCallback?: (query: this) => any): this;
/**
* Executes the callback when dialect matches doesn't all the mentioned
* dialects
*/
unlessDialect(dialect: DialectContract['name'] | DialectContract['name'][], matchCallback: (query: this) => any, noMatchCallback?: (query: this) => any): this;
}
/**
* Insert query builder to perform database inserts.
*/
interface InsertQueryBuilderContract<Result = any> extends ExcutableQueryBuilderContract<Result> {
knexQuery: Knex.QueryBuilder;
client: QueryClientContract;
/**
* Table for the insert query
*/
table(table: string): this;
withSchema(schema: string): this;
/**
* Define returning columns
*/
returning: Returning<this>;
/**
* Inserting a single record.
*/
insert: Insert<this>;
/**
* Inserting multiple columns at once
*/
multiInsert: MultiInsert<this>;
}
/**
* A executable query builder will always have these methods on it.
*/
interface ExcutableQueryBuilderContract<Result> extends Promise<Result> {
debug(debug: boolean): this;
timeout(time: number, options?: {
cancel: boolean;
}): this;
useTransaction(trx: TransactionClientContract): this;
reporterData(data: any): this;
toQuery(): string;
exec(): Promise<Result>;
toSQL(): Knex.Sql;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+665
View File
@@ -0,0 +1,665 @@
declare module '@ioc:Adonis/Lucid/Orm' {
import { RawQuery, OneOrMany, StrictValues, QueryCallback, ChainableContract, RawBuilderContract, QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
/**
* ------------------------------------------------------
* Helpers
* ------------------------------------------------------
*/
/**
* Extracts relationship attributes from the model
*/
type ExtractModelRelations<Model extends LucidRow> = {
[Key in keyof Model]: Model[Key] extends ModelRelations ? Key : never;
}[keyof Model];
/**
* Returns relationship model instance or array of instances based
* upon the relationship type
*/
type GetRelationModelInstance<Relation extends ModelRelations> = Relation['__opaque_type'] extends 'hasOne' | 'belongsTo' ? Relation['instance'] : Relation['instance'][];
/**
* ------------------------------------------------------
* Options
* ------------------------------------------------------
*/
/**
* Options accepted when defining a new relationship. Certain
* relationships like `manyToMany` have their own options
*/
type RelationOptions<Related extends ModelRelations> = {
localKey?: string;
foreignKey?: string;
serializeAs?: string | null;
onQuery?(query: Related['builder'] | Related['subQuery']): void;
};
/**
* Options accepted by many to many relationship
*/
type ManyToManyRelationOptions<Related extends ModelRelations> = {
pivotTable?: string;
localKey?: string;
pivotForeignKey?: string;
relatedKey?: string;
pivotRelatedForeignKey?: string;
pivotColumns?: string[];
pivotTimestamps?: boolean | {
createdAt: string | boolean;
updatedAt: string | boolean;
};
serializeAs?: string | null;
onQuery?(query: Related['builder'] | Related['subQuery']): void;
};
/**
* Options accepted by through relationships
*/
type ThroughRelationOptions<Related extends ModelRelations> = RelationOptions<Related> & {
throughLocalKey?: string;
throughForeignKey?: string;
throughModel: () => LucidModel;
};
/**
* ------------------------------------------------------
* Decorators
* ------------------------------------------------------
*/
/**
* Decorator signature to define has one relationship
*/
type HasOneDecorator = <RelatedModel extends LucidModel>(model: () => RelatedModel, options?: RelationOptions<HasOne<RelatedModel>>) => TypedDecorator<HasOne<RelatedModel> | null>;
/**
* Decorator signature to define has many relationship
*/
type HasManyDecorator = <RelatedModel extends LucidModel>(model: () => RelatedModel, options?: RelationOptions<HasOne<RelatedModel>>) => TypedDecorator<HasMany<RelatedModel>>;
/**
* Decorator signature to define belongs to relationship
*/
type BelongsToDecorator = <RelatedModel extends LucidModel>(model: () => RelatedModel, options?: RelationOptions<HasOne<RelatedModel>>) => TypedDecorator<BelongsTo<RelatedModel> | null>;
/**
* Decorator signature to define many to many relationship
*/
type ManyToManyDecorator = <RelatedModel extends LucidModel>(model: () => RelatedModel, column?: ManyToManyRelationOptions<ManyToMany<RelatedModel>>) => TypedDecorator<ManyToMany<RelatedModel>>;
/**
* Decorator signature to define has many through relationship
*/
type HasManyThroughDecorator = <RelatedModel extends LucidModel>(model: [() => RelatedModel, () => LucidModel], column?: Omit<ThroughRelationOptions<HasManyThrough<RelatedModel>>, 'throughModel'>) => TypedDecorator<HasManyThrough<RelatedModel>>;
/**
* ------------------------------------------------------
* Opaque typed relationships
* ------------------------------------------------------
*
* They have no runtime relevance, just a way to distinguish
* between standard model properties and relationships
*
*/
type ModelRelationTypes = {
readonly __opaque_type: 'hasOne' | 'hasMany' | 'belongsTo' | 'manyToMany' | 'hasManyThrough';
};
/**
* Opaque type for has one relationship
*/
type HasOne<RelatedModel extends LucidModel, ParentModel extends LucidModel = LucidModel> = InstanceType<RelatedModel> & {
readonly __opaque_type: 'hasOne';
model: RelatedModel;
instance: InstanceType<RelatedModel>;
client: HasOneClientContract<HasOneRelationContract<ParentModel, RelatedModel>, RelatedModel>;
builder: RelationQueryBuilderContract<RelatedModel, any>;
subQuery: RelationSubQueryBuilderContract<RelatedModel>;
};
/**
* Opaque type for has many relationship
*/
type HasMany<RelatedModel extends LucidModel, ParentModel extends LucidModel = LucidModel> = InstanceType<RelatedModel>[] & {
readonly __opaque_type: 'hasMany';
model: RelatedModel;
instance: InstanceType<RelatedModel>;
client: HasManyClientContract<HasManyRelationContract<ParentModel, RelatedModel>, RelatedModel>;
builder: HasManyQueryBuilderContract<RelatedModel, any>;
subQuery: RelationSubQueryBuilderContract<RelatedModel>;
};
/**
* Opaque type for has belongs to relationship
*/
type BelongsTo<RelatedModel extends LucidModel, ParentModel extends LucidModel = LucidModel> = InstanceType<RelatedModel> & {
readonly __opaque_type: 'belongsTo';
model: RelatedModel;
instance: InstanceType<RelatedModel>;
client: BelongsToClientContract<BelongsToRelationContract<ParentModel, RelatedModel>, RelatedModel>;
builder: RelationQueryBuilderContract<RelatedModel, any>;
subQuery: RelationSubQueryBuilderContract<RelatedModel>;
};
/**
* Opaque type for many to many relationship
*/
type ManyToMany<RelatedModel extends LucidModel, ParentModel extends LucidModel = LucidModel> = InstanceType<RelatedModel>[] & {
readonly __opaque_type: 'manyToMany';
model: RelatedModel;
instance: InstanceType<RelatedModel>;
client: ManyToManyClientContract<ManyToManyRelationContract<ParentModel, RelatedModel>, RelatedModel>;
builder: ManyToManyQueryBuilderContract<RelatedModel, any>;
subQuery: ManyToManySubQueryBuilderContract<RelatedModel>;
};
/**
* Opaque type for many to many relationship
*/
type HasManyThrough<RelatedModel extends LucidModel, ParentModel extends LucidModel = LucidModel> = InstanceType<RelatedModel>[] & {
readonly __opaque_type: 'hasManyThrough';
model: RelatedModel;
instance: InstanceType<RelatedModel>;
client: HasManyThroughClientContract<HasManyThroughRelationContract<ParentModel, RelatedModel>, RelatedModel>;
builder: HasManyThroughQueryBuilderContract<RelatedModel, any>;
subQuery: RelationSubQueryBuilderContract<RelatedModel>;
};
/**
* These exists on the models directly as a relationship. The idea
* is to distinguish relationship properties from other model
* properties.
*/
type ModelRelations = HasOne<LucidModel, LucidModel> | HasMany<LucidModel, LucidModel> | BelongsTo<LucidModel, LucidModel> | ManyToMany<LucidModel, LucidModel> | HasManyThrough<LucidModel, LucidModel>;
/**
* ------------------------------------------------------
* Relationships
* ------------------------------------------------------
*/
/**
* Interface to be implemented by all relationship types
*/
interface BaseRelationContract<ParentModel extends LucidModel, RelatedModel extends LucidModel> {
readonly type: ModelRelationTypes['__opaque_type'];
readonly relationName: string;
readonly serializeAs: string | null;
readonly booted: boolean;
readonly model: ParentModel;
relatedModel(): RelatedModel;
boot(): void;
clone(parent: LucidModel): this;
/**
* Get client
*/
client(parent: InstanceType<ParentModel>, client: QueryClientContract): unknown;
/**
* Get eager query for the relationship
*/
eagerQuery(parent: OneOrMany<InstanceType<ParentModel>>, client: QueryClientContract): RelationQueryBuilderContract<RelatedModel, InstanceType<RelatedModel>>;
subQuery(client: QueryClientContract): RelationSubQueryBuilderContract<RelatedModel>;
}
/**
* Has one relationship interface
*/
interface HasOneRelationContract<ParentModel extends LucidModel, RelatedModel extends LucidModel> extends BaseRelationContract<ParentModel, RelatedModel> {
readonly type: 'hasOne';
readonly localKey: string;
readonly foreignKey: string;
/**
* Set related model as a relationship on the parent model.
*/
setRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel> | null): void;
/**
* Push related model as a relationship on the parent model
*/
pushRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel> | null): void;
/**
* Set multiple related instances on the multiple parent models.
* This method is generally invoked during eager load.
*
* Fetch 10 users and then all profiles for all 10 users and then
* call this method to set related instances
*/
setRelatedForMany(parent: InstanceType<ParentModel>[], related: InstanceType<RelatedModel>[]): void;
/**
* Returns the query client for one or many model instances. The query
* client then be used to fetch and persist relationships.
*/
client(parent: InstanceType<ParentModel>, client: QueryClientContract): HasOneClientContract<this, RelatedModel>;
/**
* Hydrates related model attributes for persistance
*/
hydrateForPersistance(parent: LucidRow, values: ModelObject | LucidRow): void;
}
/**
* Has many relationship interface
*/
interface HasManyRelationContract<ParentModel extends LucidModel, RelatedModel extends LucidModel> extends BaseRelationContract<ParentModel, RelatedModel> {
readonly type: 'hasMany';
readonly localKey: string;
readonly foreignKey: string;
/**
* Set related models as a relationship on the parent model
*/
setRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel>[]): void;
/**
* Push related model(s) as a relationship on the parent model
*/
pushRelated(parent: InstanceType<ParentModel>, related: OneOrMany<InstanceType<RelatedModel>>): void;
/**
* Set multiple related instances on the multiple parent models.
* This method is generally invoked during eager load.
*
* Fetch 10 users and then all posts for all 10 users and then
* call this method to set related instances
*/
setRelatedForMany(parent: InstanceType<ParentModel>[], related: InstanceType<RelatedModel>[]): void;
/**
* Returns the query client for one or many model instances. The query
* client then be used to fetch and persist relationships.
*/
client(parent: InstanceType<ParentModel>, client: QueryClientContract): HasManyClientContract<this, RelatedModel>;
/**
* Hydrates related model attributes for persistance
*/
hydrateForPersistance(parent: LucidRow, values: ModelObject | LucidRow): void;
}
/**
* Belongs to relationship interface
*/
interface BelongsToRelationContract<ParentModel extends LucidModel, RelatedModel extends LucidModel> extends BaseRelationContract<ParentModel, RelatedModel> {
readonly type: 'belongsTo';
readonly localKey: string;
readonly foreignKey: string;
/**
* Set related model as a relationship on the parent model
*/
setRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel> | null): void;
/**
* Push related model as a relationship on the parent model
*/
pushRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel> | null): void;
/**
* Set multiple related instances on the multiple parent models.
* This method is generally invoked during eager load.
*
* Fetch 10 profiles and then users for all 10 profiles and then
* call this method to set related instances
*/
setRelatedForMany(parent: InstanceType<ParentModel>[], related: InstanceType<RelatedModel>[]): void;
/**
* Returns the query client for a model instance
*/
client(parent: InstanceType<ParentModel>, client: QueryClientContract): BelongsToClientContract<this, RelatedModel>;
/**
* Hydrates parent model attributes for persistance
*/
hydrateForPersistance(parent: LucidRow, values: ModelObject | LucidRow): void;
}
/**
* Many to many relationship interface
*/
interface ManyToManyRelationContract<ParentModel extends LucidModel, RelatedModel extends LucidModel> extends BaseRelationContract<ParentModel, RelatedModel> {
type: 'manyToMany';
readonly localKey: string;
readonly relatedKey: string;
readonly pivotForeignKey: string;
readonly pivotRelatedForeignKey: string;
readonly pivotTable: string;
pivotColumns: string[];
/**
* Set related models as a relationship on the parent model
*/
setRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel>[]): void;
/**
* Push related model(s) as a relationship on the parent model
*/
pushRelated(parent: InstanceType<ParentModel>, related: OneOrMany<InstanceType<RelatedModel>>): void;
/**
* Set multiple related instances on the multiple parent models.
* This method is generally invoked during eager load.
*/
setRelatedForMany(parent: InstanceType<ParentModel>[], related: InstanceType<RelatedModel>[]): void;
/**
* Returns the query client for one model instance
*/
client(parent: InstanceType<ParentModel>, client: QueryClientContract): ManyToManyClientContract<this, RelatedModel>;
/**
* Get eager query for the relationship
*/
eagerQuery(parent: OneOrMany<InstanceType<ParentModel>>, client: QueryClientContract): ManyToManyQueryBuilderContract<RelatedModel, InstanceType<RelatedModel>>;
/**
* Get subquery for the relationships
*/
subQuery(client: QueryClientContract): ManyToManySubQueryBuilderContract<RelatedModel>;
/**
* Returns key-value pair for the pivot table in relation to the parent model
*/
getPivotPair(parent: LucidRow): [string, number | string];
/**
* Returns key-value pair for the pivot table in relation to the related model
*/
getPivotRelatedPair(related: LucidRow): [string, number | string];
}
/**
* Has many through relationship interface
*/
interface HasManyThroughRelationContract<ParentModel extends LucidModel, RelatedModel extends LucidModel> extends BaseRelationContract<ParentModel, RelatedModel> {
type: 'hasManyThrough';
readonly localKey: string;
readonly foreignKey: string;
readonly throughLocalKey: string;
readonly throughForeignKey: string;
/**
* Set related models as a relationship on the parent model
*/
setRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel>[]): void;
/**
* Push related model(s) as a relationship on the parent model
*/
pushRelated(parent: InstanceType<ParentModel>, related: InstanceType<RelatedModel> | InstanceType<RelatedModel>[]): void;
/**
* Set multiple related instances on the multiple parent models.
* This method is generally invoked during eager load.
*/
setRelatedForMany(parent: InstanceType<ParentModel>[], related: InstanceType<RelatedModel>[]): void;
/**
* Returns the query client for a model instance
*/
client(model: InstanceType<ParentModel>, client: QueryClientContract): RelationQueryClientContract<this, RelatedModel>;
}
/**
* A union of relationships
*/
type RelationshipsContract = HasOneRelationContract<LucidModel, LucidModel> | HasManyRelationContract<LucidModel, LucidModel> | BelongsToRelationContract<LucidModel, LucidModel> | ManyToManyRelationContract<LucidModel, LucidModel> | HasManyThroughRelationContract<LucidModel, LucidModel>;
/**
* ------------------------------------------------------
* Relationships query client
* ------------------------------------------------------
*/
interface RelationQueryClientContract<Relation extends RelationshipsContract, RelatedModel extends LucidModel> {
relation: Relation;
/**
* Return a query builder instance of the relationship
*/
query<Result = InstanceType<RelatedModel>>(): RelationQueryBuilderContract<RelatedModel, Result>;
}
/**
* Query client for has one relationship
*/
interface HasOneClientContract<Relation extends RelationshipsContract, RelatedModel extends LucidModel> extends RelationQueryClientContract<Relation, RelatedModel> {
/**
* Save related instance. Sets up the FK automatically
*/
save(related: InstanceType<RelatedModel>): Promise<void>;
/**
* Create related instance. Sets up the FK automatically
*/
create(values: Partial<ModelAttributes<InstanceType<RelatedModel>>>, options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>>;
/**
* Return first or create related instance
*/
firstOrCreate(search: Partial<ModelAttributes<InstanceType<RelatedModel>>>, savePayload?: Partial<ModelAttributes<InstanceType<RelatedModel>>>, options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>>;
/**
* Update or create related instance
*/
updateOrCreate(search: Partial<ModelAttributes<InstanceType<RelatedModel>>>, updatePayload: Partial<ModelAttributes<InstanceType<RelatedModel>>>, options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>>;
}
/**
* Query client for has many relationship. Extends hasOne and
* adds support for saving many relations
*/
interface HasManyClientContract<Relation extends RelationshipsContract, RelatedModel extends LucidModel> extends HasOneClientContract<Relation, RelatedModel> {
/**
* Save many of related instances. Sets up FK automatically
*/
saveMany(related: InstanceType<RelatedModel>[]): Promise<void>;
/**
* Create many of related instances. Sets up FK automatically
*/
createMany(values: Partial<ModelAttributes<InstanceType<RelatedModel>>>[], options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>[]>;
/**
* Fetch or create rows. Providers a great API to sync rows
*/
fetchOrCreateMany(payload: Partial<ModelAttributes<InstanceType<RelatedModel>>>[], predicate?: keyof ModelAttributes<InstanceType<RelatedModel>> | (keyof ModelAttributes<InstanceType<RelatedModel>>)[], options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>[]>;
/**
* Update or create rows. Providers a great API to sync rows
*/
updateOrCreateMany(payload: Partial<ModelAttributes<InstanceType<RelatedModel>>>[], predicate?: keyof ModelAttributes<InstanceType<RelatedModel>> | (keyof ModelAttributes<InstanceType<RelatedModel>>)[], options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>[]>;
/**
* Return a query builder instance of the relationship
*/
query<Result = InstanceType<RelatedModel>>(): HasManyQueryBuilderContract<RelatedModel, Result>;
}
/**
* Query client for belongs to relationship. Uses `associate` and
* `dissociate` over save.
*/
interface BelongsToClientContract<Relation extends RelationshipsContract, RelatedModel extends LucidModel> extends RelationQueryClientContract<Relation, RelatedModel> {
/**
* Associate related instance
*/
associate(related: InstanceType<RelatedModel>): Promise<void>;
/**
* Dissociate related instance
*/
dissociate(): Promise<void>;
}
/**
* Query client for many to many relationship.
*/
interface ManyToManyClientContract<Relation extends RelationshipsContract, RelatedModel extends LucidModel> extends RelationQueryClientContract<Relation, RelatedModel> {
/**
* Returns related model query builder instance
*/
query<Result = InstanceType<RelatedModel>>(): ManyToManyQueryBuilderContract<RelatedModel, Result>;
/**
* Pivot query just targets the pivot table without any joins
*/
pivotQuery<Result = any>(): ManyToManyQueryBuilderContract<RelatedModel, Result>;
/**
* Save related model instance. Sets up FK automatically
*/
save(related: InstanceType<RelatedModel>, performSync?: boolean, // defaults to true
pivotAttributes?: ModelObject): Promise<void>;
/**
* Save many of related model instance. Sets up FK automatically
*/
saveMany(related: InstanceType<RelatedModel>[], performSync?: boolean, // defaults to true
pivotAttributes?: (ModelObject | undefined)[]): Promise<void>;
/**
* Create related model instance. Sets up FK automatically
*/
create(values: Partial<ModelAttributes<InstanceType<RelatedModel>>>, pivotAttributes?: ModelObject, options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>>;
/**
* Create many of related model instances. Sets up FK automatically
*/
createMany(values: Partial<ModelAttributes<InstanceType<RelatedModel>>>[], pivotAttributes?: (ModelObject | undefined)[], options?: ModelAssignOptions): Promise<InstanceType<RelatedModel>[]>;
/**
* Attach new pivot rows
*/
attach(ids: (string | number)[] | Record<string, ModelObject>, trx?: TransactionClientContract): Promise<void>;
/**
* Detach existing pivot rows
*/
detach(ids?: (string | number)[], trx?: TransactionClientContract): Promise<void>;
/**
* Sync pivot rows.
*/
sync(ids: (string | number)[] | Record<string, ModelObject>, detach?: boolean, trx?: TransactionClientContract): Promise<void>;
}
/**
* HasMany through client contract. HasMany through doesn't
* allow persisting relationships. Use the direct relation
* for that.
*/
interface HasManyThroughClientContract<Relation extends RelationshipsContract, RelatedModel extends LucidModel> extends RelationQueryClientContract<Relation, RelatedModel> {
/**
* Return a query builder instance of the relationship
*/
query<Result = InstanceType<RelatedModel>>(): HasManyThroughQueryBuilderContract<RelatedModel, Result>;
}
/**
* ------------------------------------------------------
* Relationships query builders
* ------------------------------------------------------
*/
/**
* Interface with query builder options for the many to many pivot
* table
*/
interface PivotQueryBuilderContract {
pivotColumns(columns: string[]): this;
wherePivot: WherePivot<this>;
orWherePivot: WherePivot<this>;
andWherePivot: WherePivot<this>;
whereNotPivot: WherePivot<this>;
orWhereNotPivot: WherePivot<this>;
andWhereNotPivot: WherePivot<this>;
whereInPivot: WhereInPivot<this>;
orWhereInPivot: WhereInPivot<this>;
andWhereInPivot: WhereInPivot<this>;
whereNotInPivot: WhereInPivot<this>;
orWhereNotInPivot: WhereInPivot<this>;
andWhereNotInPivot: WhereInPivot<this>;
whereNullPivot: WhereNullPivot<this>;
orWhereNullPivot: WhereNullPivot<this>;
andWhereNullPivot: WhereNullPivot<this>;
whereNotNullPivot: WhereNullPivot<this>;
orWhereNotNullPivot: WhereNullPivot<this>;
andWhereNotNullPivot: WhereNullPivot<this>;
}
/**
* Base query builder for all relations
*/
interface RelationQueryBuilderContract<Related extends LucidModel, Result> extends ModelQueryBuilderContract<Related, Result> {
/**
* Is query a relationship query obtained using `related('relation').query()`
*/
isRelatedQuery: true;
/**
* Is query a relationship query obtained using `related('relation').subQuery()`
*/
isRelatedSubQuery: false;
/**
* Is query a relationship query obtained using one of the preload methods.
*/
isRelatedPreloadQuery: boolean;
selectRelationKeys(): this;
}
/**
* Has many query builder contract
*/
interface HasManyQueryBuilderContract<Related extends LucidModel, Result> extends RelationQueryBuilderContract<Related, Result> {
groupLimit(limit: number): this;
groupOrderBy(column: string, direction?: 'asc' | 'desc'): this;
}
/**
* Has many query through builder contract
*/
interface HasManyThroughQueryBuilderContract<Related extends LucidModel, Result> extends RelationQueryBuilderContract<Related, Result> {
groupLimit(limit: number): this;
groupOrderBy(column: string, direction?: 'asc' | 'desc'): this;
}
/**
* Possible signatures for adding a where clause
*/
interface WherePivot<Builder> {
(key: string, value: StrictValues | ChainableContract): Builder;
(key: string, operator: string, value: StrictValues | ChainableContract): Builder;
}
/**
* Possible signatures for adding whereNull clause.
*/
interface WhereNullPivot<Builder> {
(key: string): Builder;
}
/**
* Possible signatures for adding where in clause.
*/
interface WhereInPivot<Builder> {
(K: string, value: StrictValues[]): Builder;
(K: string[], value: StrictValues[][]): Builder;
(k: string, subquery: ChainableContract | QueryCallback<Builder> | RawBuilderContract | RawQuery): Builder;
(k: string[], subquery: ChainableContract | RawBuilderContract | RawQuery): Builder;
}
/**
* Shape of many to many query builder. It has few methods over the standard
* model query builder
*/
interface ManyToManyQueryBuilderContract<Related extends LucidModel, Result> extends RelationQueryBuilderContract<Related, Result>, PivotQueryBuilderContract {
isPivotOnlyQuery: boolean;
groupLimit(limit: number): this;
groupOrderBy(column: string, direction?: 'asc' | 'desc'): this;
}
/**
* ------------------------------------------------------
* Sub Queries
* ------------------------------------------------------
*/
/**
* Not in use right now. Since after omitting these types from the
* model query builder losses "this" scope. Need to re-think
*/
type UnSupportedSubQueryMethods = 'preload' | 'decrement' | 'increment' | 'update' | 'paginate' | 'delete' | 'del' | 'firstOrFail' | 'first' | 'exec' | 'withCount';
/**
* SubQuery builder allows creating sub queries targeting a relationship. Sub queries
* cannot be executed directly, but can be used as a reference in the parent query
* builder. Use cases are:
*
* - withCount
* - whereHas
*/
interface RelationSubQueryBuilderContract<Related extends LucidModel> extends ModelQueryBuilderContract<Related, any> {
/**
* Is query a relationship query obtained using `related('relation').query()`
*/
isRelatedQuery: false;
/**
* Is query a relationship query obtained using `related('relation').subQuery()`
*/
isRelatedSubQuery: true;
/**
* Is query a relationship query obtained using one of the preload methods.
*/
isRelatedPreloadQuery: false;
selfJoinCounter: number;
readonly selfJoinAlias: string;
selectRelationKeys(): this;
prepare(): this;
}
/**
* SubQuery builder for many to many relationship
*/
interface ManyToManySubQueryBuilderContract<Related extends LucidModel> extends RelationSubQueryBuilderContract<Related>, PivotQueryBuilderContract {
}
/**
* The withCount function
*/
interface WithCount<Model extends LucidRow, Builder> {
<Name extends ExtractModelRelations<Model>, RelatedBuilder = Model[Name] extends ModelRelations ? Model[Name]['subQuery'] : never>(relation: Name, callback?: (builder: RelatedBuilder) => void): Builder;
}
/**
* The with aggregate function
*/
interface WithAggregate<Model extends LucidRow, Builder> {
<Name extends ExtractModelRelations<Model>, RelatedBuilder = Model[Name] extends ModelRelations ? Model[Name]['subQuery'] : never>(relation: Name, callback: (builder: RelatedBuilder) => void): Builder;
}
/**
* The has function
*/
interface Has<Model extends LucidRow, Builder> {
<Name extends ExtractModelRelations<Model>>(relation: Name, operator?: string, value?: StrictValues | ChainableContract): Builder;
}
/**
* The whereHas function
*/
interface WhereHas<Model extends LucidRow, Builder> {
<Name extends ExtractModelRelations<Model>, RelatedBuilder = Model[Name] extends ModelRelations ? Model[Name]['subQuery'] : never>(relation: Name, callback: (builder: RelatedBuilder) => void, operator?: string, value?: StrictValues | ChainableContract): Builder;
}
/**
* ------------------------------------------------------
* Preloader
* ------------------------------------------------------
*/
/**
* The preload function
*/
interface Preload<Model extends LucidRow, Builder> {
<Name extends ExtractModelRelations<Model>, RelatedBuilder = Model[Name] extends ModelRelations ? Model[Name]['builder'] : never>(relation: Name, callback?: (builder: RelatedBuilder) => void): Builder;
}
/**
* Shape of the preloader to preload relationships
*/
interface PreloaderContract<Model extends LucidRow> {
processAllForOne(parent: Model, client: QueryClientContract): Promise<void>;
processAllForMany(parent: Model[], client: QueryClientContract): Promise<void>;
load: Preload<Model, this>;
preload: Preload<Model, this>;
debug(debug: boolean): this;
sideload(values: ModelObject): this;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+35
View File
@@ -0,0 +1,35 @@
declare module '@ioc:Adonis/Lucid/Schema' {
import { Knex } from 'knex';
import { QueryClientContract, RawQueryBindings } from '@ioc:Adonis/Lucid/Database';
/**
* Shape of callback to defer database calls
*/
export type DeferCallback = (client: QueryClientContract) => void | Promise<void>;
/**
* Shape of schema class constructor
*/
export interface SchemaConstructorContract {
disableTransactions: boolean;
new (db: QueryClientContract, file: string, dryRun: boolean): SchemaContract;
}
/**
* Shape of schema class
*/
export interface SchemaContract {
readonly file: string;
dryRun: boolean;
debug: boolean;
db: QueryClientContract;
schema: Knex.SchemaBuilder;
now(precision?: number): Knex.Raw;
knex(): Knex.QueryBuilder;
raw(sql: string, bindings?: RawQueryBindings): Knex.Raw;
defer: (cb: DeferCallback) => void;
up(): Promise<void> | void;
down(): Promise<void> | void;
execUp(): Promise<string[] | boolean>;
execDown(): Promise<string[] | boolean>;
}
const Schema: SchemaConstructorContract;
export default Schema;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+27
View File
@@ -0,0 +1,27 @@
declare module '@ioc:Adonis/Lucid/Seeder' {
import { QueryClientContract, FileNode } from '@ioc:Adonis/Lucid/Database';
/**
* Shape of seeder class
*/
export type SeederConstructorContract = {
/**
* @deprecated
*/
developmentOnly: boolean;
environment: string[];
new (client: QueryClientContract): {
client: QueryClientContract;
run(): Promise<void>;
};
};
/**
* Shape of file node returned by the run method
*/
export type SeederFileNode = {
status: 'pending' | 'completed' | 'failed' | 'ignored';
error?: any;
file: FileNode<unknown>;
};
const BaseSeeder: SeederConstructorContract;
export default BaseSeeder;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+11
View File
@@ -0,0 +1,11 @@
declare module '@ioc:Adonis/Core/TestUtils' {
type HookCleanupHandler = () => Promise<void>;
type HookCallback = () => Promise<HookCleanupHandler> | Promise<void>;
interface TestUtilsContract {
db(connectionName?: string): {
seed: HookCallback;
migrate: HookCallback;
truncate: HookCallback;
};
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+24
View File
@@ -0,0 +1,24 @@
/// <reference types="@adonisjs/validator" />
declare module '@ioc:Adonis/Core/Validator' {
import { Rule } from '@ioc:Adonis/Core/Validator';
type DbRowCheckOptions = {
table: string;
column: string;
dateFormat?: string;
connection?: string;
caseInsensitive?: boolean;
constraints?: {
[key: string]: any;
};
where?: {
[key: string]: any;
};
whereNot?: {
[key: string]: any;
};
};
interface Rules {
exists(options: DbRowCheckOptions): Rule;
unique(options: DbRowCheckOptions): Rule;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/