API @deepkit/sql
npm install @deepkit/sql
user.address[0].street => [user, address[0].street]
address[0].street => [address, [0].street] Only direct properties of an entity will be serialized in some special way.
Deeper types get the normal JSON serialization.Classes
export class Sql {
constructor(public sql: string = , public params: any[] = []);
appendSql(sql: Sql);
append(sql: string, params?: any[]);
}
export class SqlBuilder {
rootConverter?: ConvertDataToDict;
constructor(protected adapter: PreparedAdapter, public params: string[] = []);
convertRows(schema: ReflectionClass<any>, model: SQLQueryModel<any>, rows: any[]): any[];
build<T extends OrmEntity>(schema: ReflectionClass<any>, model: SQLQueryModel<T>, head: string): Sql;
update<T extends OrmEntity>(schema: ReflectionClass<any>, model: SQLQueryModel<T>, set: string[]): Sql;
select(schema: ReflectionClass<any>, model: SQLQueryModel<any>, options: {
select?: string[];
} = {}): Sql;
}
export class SqlReference {
constructor(public readonly field: string);
}
export class SQLQueryModel<T extends OrmEntity> extends DatabaseQueryModel<T, FilterQuery<T>, DEEP_SORT<T>> {
where?: SqlQuery;
sqlSelect?: SqlQuery;
clone(): this;
isPartial(): boolean;
}
export abstract class SQLStatement {
abstract get(params?: any[]): Promise<any>;
abstract all(params?: any[]): Promise<any[]>;
abstract release(): void;
}
export abstract class SQLConnection {
released: boolean;
constructor(protected connectionPool: SQLConnectionPool, public logger: Logger, public transaction?: DatabaseTransaction, public stopwatch?: Stopwatch);
release();
abstract prepare(sql: string): Promise<SQLStatement>;
/**
* Runs a single SQL query.
*/
abstract run(sql: string, params?: any[]): Promise<any>;
abstract getChanges(): Promise<number>;
async execAndReturnSingle(sql: string, params?: any[]): Promise<any>;
async execAndReturnAll(sql: string, params?: any[]): Promise<any>;
}
export abstract class SQLConnectionPool {
constructor(protected logger: Logger);
setLogger(logger: Logger);
/**
* Reserves an existing or new connection. It's important to call `.release()` on it when
* done. When release is not called a resource leak occurs and server crashes.
*/
abstract getConnection(transaction?: DatabaseTransaction): Promise<SQLConnection>;
getActiveConnections();
release(connection: SQLConnection);
}
export class SQLQueryResolver<T extends OrmEntity> extends GenericQueryResolver<T> {
constructor(protected connectionPool: SQLConnectionPool, protected platform: DefaultPlatform, classSchema: ReflectionClass<T>, protected adapter: SQLDatabaseAdapter, session: DatabaseSession<DatabaseAdapter>);
/**
* If possible, this method should handle specific SQL errors and convert
* them to more specific error classes with more information, e.g. unique constraint.
*/
handleSpecificError(error: Error): Error;
async count(model: SQLQueryModel<T>): Promise<number>;
async delete(model: SQLQueryModel<T>, deleteResult: DeleteResult<T>): Promise<void>;
async find(model: SQLQueryModel<T>): Promise<T[]>;
async findOneOrUndefined(model: SQLQueryModel<T>): Promise<T | undefined>;
async has(model: SQLQueryModel<T>): Promise<boolean>;
async patch(model: SQLQueryModel<T>, changes: Changes<T>, patchResult: PatchResult<T>): Promise<void>;
}
export class SqlQueryParameter {
constructor(public value: any);
}
export class SQLQueryIdentifier {
constructor(public id: any);
}
export class SqlQuery {
constructor(public parts: ReadonlyArray<QueryPart>);
clone(): SqlQuery;
convertToSQL(platform: DefaultPlatform, placeholderStrategy: SqlPlaceholderStrategy, tableName?: string): SqlStatement;
}
export class SQLDatabaseQuery<T extends OrmEntity> extends Query<T> {
model: SQLQueryModel<T>;
constructor(classSchema: ReflectionClass<T>, protected databaseSession: DatabaseSession<DatabaseAdapter>, public resolver: SQLQueryResolver<T>);
/**
* Adds raw SQL to the where clause of the query.
* If there is a `filter()` set as well, the where is added after the filter using AND.
*
* ```
* database.query(User).where(`id > ${id}`).find();
* ```
*
* Use `${identifier('name')} = ${'Peter'}` for column names that need to be quoted.
*/
where(sql: SqlQuery): this;
/**
* Adds additional selects to the query.
* Automatically converts the query to a partial (no class instances).
*/
sqlSelect(sql: SqlQuery): Replace<this, Pick<Resolve<this>, any>>;
}
export class SQLDatabaseQueryFactory extends DatabaseAdapterQueryFactory {
constructor(protected connectionPool: SQLConnectionPool, protected platform: DefaultPlatform, protected databaseSession: DatabaseSession<any>);
createQuery<T extends OrmEntity>(classType: ReceiveType<T> | ClassType<T> | AbstractClassType<T> | ReflectionClass<T>): SQLDatabaseQuery<T>;
}
@entity.name()
export class MigrationStateEntity {
created: Date;
constructor(public version: number & PrimaryKey);
}
export class SqlMigrationHandler {
constructor(protected database: Database<SQLDatabaseAdapter>);
async setLatestMigrationVersion(version: number): Promise<void>;
async removeMigrationVersion(version: number): Promise<void>;
async getLatestMigrationVersion(): Promise<number>;
}
export class RawQuery<T> implements FindQuery<T> {
constructor(protected session: DatabaseSession<SQLDatabaseAdapter>, protected connectionPool: SQLConnectionPool, protected platform: DefaultPlatform, protected sql: SqlQuery, protected type: Type);
/**
* Executes the raw query and returns nothing.
*/
async execute(): Promise<void>;
/**
* Returns the SQL statement with placeholders replaced with the actual values.
*/
getSql(): SqlStatement;
/**
* Returns the raw result of a single row.
*
* Note that this does not resolve/map joins. Use the regular database.query() for that.
*/
async findOneOrUndefined(): Promise<T>;
/**
* Note that this does not resolve/map joins. Use the regular database.query() for that.
*/
async findOne(): Promise<T>;
/**
* Returns the full result of a raw query.
*
* Note that this does not resolve/map joins. Use the regular database.query() for that.
*/
async find(): Promise<T[]>;
}
export class SqlRawFactory implements RawFactory<[
SqlQuery
]> {
constructor(protected session: DatabaseSession<SQLDatabaseAdapter>, protected connectionPool: SQLConnectionPool, protected platform: DefaultPlatform);
create<T = unknown>(sql: SqlQuery, type?: ReceiveType<T>): RawQuery<T>;
}
export abstract class SQLDatabaseAdapter extends DatabaseAdapter {
abstract platform: DefaultPlatform;
abstract connectionPool: SQLConnectionPool;
preparedEntities;
abstract queryFactory(databaseSession: DatabaseSession<this>): SQLDatabaseQueryFactory;
abstract createPersistence(databaseSession: DatabaseSession<this>): SQLPersistence;
abstract getSchemaName(): string;
rawFactory(session: DatabaseSession<this>): SqlRawFactory;
async getInsertBatchSize(schema: ReflectionClass<any>): Promise<number>;
async getUpdateBatchSize(schema: ReflectionClass<any>): Promise<number>;
isNativeForeignKeyConstraintSupported();
createSelectSql(query: Query<any>): Sql;
/**
* Creates (and re-creates already existing) tables in the database.
* This is only for testing purposes useful.
*
* WARNING: THIS DELETES ALL AFFECTED TABLES AND ITS CONTENT.
*/
async createTables(entityRegistry: DatabaseEntityRegistry): Promise<void>;
async getMigrations(options: MigrateOptions, entityRegistry: DatabaseEntityRegistry): Promise<{
[name: string]: {
sql: string[];
diff: string;
};
}>;
async migrate(options: MigrateOptions, entityRegistry: DatabaseEntityRegistry): Promise<void>;
}
export class SQLPersistence extends DatabasePersistence {
constructor(protected platform: DefaultPlatform, public connectionPool: SQLConnectionPool, protected session: DatabaseSession<SQLDatabaseAdapter>);
/**
* If possible, this method should handle specific SQL errors and convert
* them to more specific error classes with more information, e.g. unique constraint.
*/
handleSpecificError(error: Error): Error;
async getConnection(): Promise<ReturnType<this[][]>>;
release();
async insert<T extends OrmEntity>(classSchema: ReflectionClass<T>, items: T[]): Promise<void>;
async update<T extends OrmEntity>(classSchema: ReflectionClass<T>, changeSets: DatabasePersistenceChangeSet<T>[]): Promise<void>;
async batchUpdate<T extends OrmEntity>(entity: PreparedEntity, changeSets: DatabasePersistenceChangeSet<T>[]): Promise<void>;
async remove<T extends OrmEntity>(classSchema: ReflectionClass<T>, items: T[]): Promise<void>;
}
export class SQLFilterBuilder {
params: any[];
constructor(protected adapter: PreparedAdapter, protected schema: ReflectionClass<any>, protected tableName: string, protected serializer: Serializer, public placeholderStrategy: SqlPlaceholderStrategy);
isNull();
regexpComparator(lvalue: string, value: RegExp): string;
isNotNull();
convert(filter: Filter): string;
requiresJson(type: Type): boolean;
}
export class MigrationProvider {
constructor(public databases: DatabaseRegistry);
getMigrationDir(): string;
setMigrationDir(dir: string);
async getMigrationsPerDatabase(limitDatabase?: string);
async getMigrations(migrationDir: string): Promise<Migration[]>;
}
export class DatabaseModel {
schemaName: string;
schemaMap;
constructor(public tables: Table[] = [], public adapterName: string = );
getTableForClass(schema: ReflectionClass<any>): Table;
removeUnknownTables(other: DatabaseModel);
removeTable(name: string, schemaName?: string);
addTable(name: string);
getTable(name: string, schemaName?: string): Table;
getTableNames(): string[];
getTableForFull(fullName: string, schemaDelimiter: string): Table;
hasTable(name: string, schemaName?: string): boolean;
}
export class Table {
schemaName: string;
alias: string;
columnForProperty: Map<ReflectionProperty, Column>;
columns: Column[];
indices: IndexModel[];
foreignKeys: ForeignKey[];
constructor(public name: string);
isName(name: string, schemaName?: string): boolean;
getName(): string;
getFullName(schemaDelimiter: string): string;
addColumn(name: string, property?: ReflectionProperty): Column;
addIndex(name: string, unique = false): IndexModel;
addForeignKey(name: string, foreignTable: Table): ForeignKey;
hasColumn(name: string): boolean;
getColumn(name: string): Column;
getColumnForProperty(property: ReflectionProperty): Column;
getPrimaryKeys(): Column[];
getAutoIncrements(): Column[];
getIndices();
getIndex(name: string);
getUnices();
hasPrimaryKey();
hasCompositePrimaryKey();
getForeignKeyOfLocalColumn(column: Column): ForeignKey | undefined;
hasIndexByName(name: string): boolean;
hasIndex(columns: Column[], unique = false): boolean;
}
export class Column {
description: string;
type?: string;
size?: number;
scale?: number;
unsigned: boolean;
defaultValue?: any;
defaultExpression?: string;
isNotNull;
isPrimaryKey;
isAutoIncrement;
constructor(public table: Table, public name: string);
getName(): string;
getFullName(): string;
getSizeDefinition();
}
export class IndexModel {
columns: Column[];
spatial: boolean;
partial: boolean;
size: number;
constructor(public table: Table, public name: string, public isUnique = false);
getName(): string;
hasColumn(columnName: string);
addColumn(columnName: string);
valueOf(): string;
}
export class ForeignKey {
localColumns: Column[];
foreignColumns: Column[];
onUpdate: ForeignKeyAction;
onDelete: ForeignKeyAction;
constructor(public table: Table, public name: string, public foreign: Table);
getName(): string;
addReference(localColumnName: string, foreignColumnName: string);
getColumnMapping(): [
from: Column,
to: Column
][];
valueOf();
}
export class ColumnPropertyDiff {
constructor(public readonly from: any, public readonly to: any);
}
export class ColumnDiff {
constructor(public from: Column, public to: Column, public changedProperties = new Map<keyof Column, ColumnPropertyDiff>());
valueOf();
}
export class ColumnComparator {
static computeDiff(from: Column, to: Column);
static compareColumns(from: Column, to: Column);
}
export class IndexComparator {
static computeDiff(from: IndexModel, to: IndexModel);
}
export class ForeignKeyComparator {
static computeDiff(from: ForeignKey, to: ForeignKey);
}
export class TableDiff {
addedColumns: Column[];
removedColumns: Column[];
modifiedColumns: ColumnDiff[];
renamedColumns: [
from: Column,
to: Column
][];
addedPKColumns: Column[];
removedPKColumns: Column[];
renamedPKColumns: [
from: Column,
to: Column
][];
addedIndices: IndexModel[];
removedIndices: IndexModel[];
modifiedIndices: [
from: IndexModel,
to: IndexModel
][];
addedFKs: ForeignKey[];
modifiedFKs: [
from: ForeignKey,
to: ForeignKey
][];
removedFKs: ForeignKey[];
constructor(public from: Table, public to: Table);
hasModifiedPk(): boolean;
toString();
}
export class TableComparator {
readonly diff: TableDiff;
constructor(public from: Table, public to: Table);
static computeDiff(from: Table, to: Table): TableDiff | undefined;
}
export class DatabaseDiff {
addedTables: Table[];
removedTables: Table[];
modifiedTables: TableDiff[];
renamedTables: [
from: Table,
to: Table
][];
constructor(public from: DatabaseModel, public to: DatabaseModel);
removeTable(name: string, schema?: string);
forTable(table: Table);
getDiff(table: Table): TableDiff | undefined;
}
export class DatabaseComparator {
readonly diff: DatabaseDiff;
withRemoveTable: boolean;
withRenaming: boolean;
constructor(public from: DatabaseModel, public to: DatabaseModel);
static computeDiff(from: DatabaseModel, to: DatabaseModel);
}
export abstract class SchemaParser {
constructor(protected connection: SQLConnection, protected platform: DefaultPlatform);
abstract parse(database: DatabaseModel, limitTableNames?: string[]): Promise<void>;
}
export class DefaultNamingStrategy implements NamingStrategy {
getColumnName(property: ReflectionProperty, databaseAdapterAnnotationId: string): string;
getTableName(reflectionClass: ReflectionClass<any>): string;
}
export class SqlPlaceholderStrategy {
constructor(public offset: number = );
getPlaceholder(): string;
}
export abstract class DefaultPlatform {
/**
* The ID used in annotation to get database related type information (like `type`, `default`, `defaultExpr`, ...) via databaseAnnotation.getDatabase.
*/
annotationId;
abstract schemaParserType: ClassType<SchemaParser>;
serializer: Serializer;
namingStrategy: NamingStrategy;
placeholderStrategy: ClassType<SqlPlaceholderStrategy>;
applyLimitAndOffset(sql: Sql, limit?: number, offset?: number): void;
createSqlFilterBuilder(adapter: PreparedAdapter, reflectionClass: ReflectionClass<any>, tableName: string): SQLFilterBuilder;
getMigrationTableName();
quoteValue(value: any): string;
getAggregateSelect(tableName: string, property: ReflectionProperty, func: string);
addBinaryType(sqlType: string, size?: number, scale?: number);
/**
* Last matching check wins.
*/
addType(kind: ReflectionKind | TypeMappingChecker, sqlType: string, size?: number, scale?: number, unsigned?: boolean);
getColumnListDDL(columns: Column[]);
getSchemaDelimiter(): string;
/**
* If the platform supports the `SELECT FOR UPDATE` or `SELECT FOR SHARE`.
*/
supportsSelectFor(): boolean;
/**
* If the platform supports the `PRIMARY KEY` section in `CREATE TABLE(column, column, PRIMARY KEY())`;
*/
supportsInlinePrimaryKey(): boolean;
/**
* If the platform supports the `CONSTRAINT %s FOREIGN KEY` section in `CREATE TABLE(column, column, CONSTRAINT %s FOREIGN KEY)`;
*/
supportsInlineForeignKey(): boolean;
getPrimaryKeyDDL(table: Table);
normalizeTables(tables: Table[]);
getEntityFields(schema: ReflectionClass<any>): ReflectionProperty[];
/**
* Whether an accessor to e.g. "shippingAddress"->'$.street' = ?
* requires real json at ? or SQL value is enough.
* If this returns true, the value for ? is passed through JSON.stringify().
*/
deepColumnAccessorRequiresJsonString(): boolean;
getDeepColumnAccessor(table: string, column: string, path: string);
getColumnAccessor(table: string, path: string);
getModifyDatabaseDDL(databaseDiff: DatabaseDiff, options: MigrateOptions): string[];
createTables(entityRegistry: DatabaseEntityRegistry, database: DatabaseModel = new DatabaseModel()): Table[];
quoteIdentifier(id: string): string;
isJson(type: Type): boolean;
getSqlTypeCaster(type: Type): (placeholder: string) => string;
getTableIdentifier(schema: ReflectionClass<any>): string;
getIdentifier(object: Table | Column | IndexModel | ForeignKey, append: string = ): string;
getFullIdentifier(object: Table | Column, append: string = ): string;
getPrimaryKeyName(table: Table): string;
getDropPrimaryKeyDDL(table: Table);
getAddPrimaryKeyDDL(table: Table);
getBeginDDL(): string;
getEndDDL(): string;
getAddTablesDDL(database: DatabaseModel): string[];
getAddSchemasDDL(database: DatabaseModel): string;
getAddSchemaDDL(schemaName: string): string;
getUseSchemaDDL(table: Table);
getResetSchemaDDL(table: Table): string;
getRenameTableDDL(from: Table, to: Table): string;
supportsAggregatedAlterTable(): boolean;
getModifyTableDDL(diff: TableDiff, options: MigrateOptions): string[];
getAddTableDDL(table: Table, withForeignKey: boolean = true): string[];
getCreateTableDDL(table: Table, withForeignKey: boolean = true): string;
getAddForeignKeysDDL(table: Table): string[];
getAddIndicesDDL(table: Table): string[];
getAddForeignKeyDDL(foreignKey: ForeignKey): string;
getForeignKeyDDL(foreignKey: ForeignKey): string;
getAddIndexDDL(index: IndexModel): string;
getDropTableDDL(table: Table): string;
getRemoveColumnDDL(column: Column): string;
getRenameColumnDDL(from: Column, to: Column): string;
getModifyColumnDDL(diff: ColumnDiff): string;
getAddColumnDDL(column: Column);
getDropForeignKeyDDL(foreignKey: ForeignKey): string;
getDropIndexDDL(index: IndexModel): string;
getUniqueDDL(unique: IndexModel): string;
getColumnDDL(column: Column);
getColumnDefaultValueDDL(column: Column);
getDefaultExpression(column: Column): string;
getAutoIncrement();
getNotNullString();
getNullString();
}
export class SqlSerializer extends Serializer {
name;
override setExplicitUndefined(type: Type, state: TemplateState): boolean;
}
Const
string[]
Serializer
Functions
(path: string): [string, string]
(path: string): string
(id: string): SQLQueryIdentifier
(strings: TemplateStringsArray, ...params: ReadonlyArray<any>): SqlQuery
(platform: DefaultPlatform, entity: PreparedEntity, changeSets: DatabasePersistenceChangeSet<any>[], options?: { setNamesWithTableName?: true; }): { changedFields: string[]; ... 12 more ...; tableName: string; }
(types: (Type | ClassType | ReflectionClass<any>)[], adapter: SQLDatabaseAdapter): Promise<string>
(column: Column, type: string): void
(v: any): boolean
(type: Type): boolean
(type: Type): boolean
(type: Type): boolean
(type: Type): boolean
(type: Type): boolean
(type: Type): boolean
(type: Type): boolean
(type: Type): boolean
(placeholder: string): string
(adapter: PreparedAdapter, entity: ReflectionClass<any>): PreparedEntity
(entity: PreparedEntity, path: string): SqlTypeCast
(state: TemplateState): boolean
(u: any): Buffer
(buffer: Buffer): string
Types
type SORT_TYPE = SORT_ORDER | { $meta: 'textScore' };
type DEEP_SORT<T extends OrmEntity> = { [P in keyof T]?: SORT_TYPE } & { [P: string]: SORT_TYPE };
type SqlStatement = { sql: string, params: any[] };
interface Migration {
databaseName: string;
version: number;
name?: string;
up(): string[];
down(): string[];
}
type ForeignKeyAction = 'RESTRICT' | 'NO ACTION' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT';
interface NamingStrategy {
getColumnName(property: ReflectionProperty, databaseAdapterAnnotationId: string): string;
getTableName(reflectionClass: ReflectionClass<any>): string;
}
type TypeMappingChecker = (type: Type) => boolean;
interface TypeMapping {
sqlType: string;
size?: number;
scale?: number;
unsigned?: boolean;
}
type SqlTypeCast = (placeholder: string) => string;
interface PreparedField {
type: Type;
name: string; // actual name from property
columnName: string; // after naming strategy
optional: boolean;
json: boolean;
autoIncrement: boolean;
columnNameEscaped: string; // .e.g `{column}`
columnEscapedWithTable: string; // .e.g `user`.`{column}`
sqlTypeCast: SqlTypeCast;
}
interface PreparedEntity {
platform: DefaultPlatform,
type: TypeClass | TypeObjectLiteral;
name: string;
tableName: string;
tableNameEscaped: string; // .e.g `{table}`
primaryKey: PreparedField;
fieldMap: { [name: string]: PreparedField };
fields: PreparedField[];
sqlTypeCaster: { [path: string]: SqlTypeCast };
}
interface PreparedAdapter {
getName(): string;
platform: DefaultPlatform;
preparedEntities: Map<ReflectionClass<any>, PreparedEntity>;
}