Initial commit - Event Planner application
This commit is contained in:
8
node_modules/@mikro-orm/sql/dialects/sqlite/BaseSqliteConnection.d.ts
generated
vendored
Normal file
8
node_modules/@mikro-orm/sql/dialects/sqlite/BaseSqliteConnection.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { type Dialect } from 'kysely';
|
||||
import type { Dictionary } from '@mikro-orm/core';
|
||||
import { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
||||
export declare class BaseSqliteConnection extends AbstractSqlConnection {
|
||||
createKyselyDialect(options: Dictionary): Dialect;
|
||||
connect(options?: { skipOnConnect?: boolean }): Promise<void>;
|
||||
protected attachDatabases(): Promise<void>;
|
||||
}
|
||||
27
node_modules/@mikro-orm/sql/dialects/sqlite/BaseSqliteConnection.js
generated
vendored
Normal file
27
node_modules/@mikro-orm/sql/dialects/sqlite/BaseSqliteConnection.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import { CompiledQuery } from 'kysely';
|
||||
import { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
||||
export class BaseSqliteConnection extends AbstractSqlConnection {
|
||||
createKyselyDialect(options) {
|
||||
throw new Error(
|
||||
'No SQLite dialect configured. Pass a Kysely dialect via the `driverOptions` config option, ' +
|
||||
'e.g. `new NodeSqliteDialect(...)` for node:sqlite or a custom dialect for other libraries.',
|
||||
);
|
||||
}
|
||||
async connect(options) {
|
||||
await super.connect(options);
|
||||
await this.getClient().executeQuery(CompiledQuery.raw('pragma foreign_keys = on'));
|
||||
await this.attachDatabases();
|
||||
}
|
||||
async attachDatabases() {
|
||||
const attachDatabases = this.config.get('attachDatabases');
|
||||
if (!attachDatabases?.length) {
|
||||
return;
|
||||
}
|
||||
const { fs } = await import('@mikro-orm/core/fs-utils');
|
||||
const baseDir = this.config.get('baseDir');
|
||||
for (const db of attachDatabases) {
|
||||
const path = fs.absolutePath(db.path, baseDir);
|
||||
await this.execute(`attach database '${path}' as ${this.platform.quoteIdentifier(db.name)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
node_modules/@mikro-orm/sql/dialects/sqlite/NodeSqliteDialect.d.ts
generated
vendored
Normal file
21
node_modules/@mikro-orm/sql/dialects/sqlite/NodeSqliteDialect.d.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { SqliteDialect } from 'kysely';
|
||||
/**
|
||||
* Kysely dialect for `node:sqlite` (Node.js 22.5+, Deno 2.2+).
|
||||
*
|
||||
* Bridges `node:sqlite`'s `DatabaseSync` to the `better-sqlite3` interface
|
||||
* that Kysely's `SqliteDialect` expects.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { SqliteDriver, NodeSqliteDialect } from '@mikro-orm/sql';
|
||||
*
|
||||
* const orm = await MikroORM.init({
|
||||
* driver: SqliteDriver,
|
||||
* dbName: ':memory:',
|
||||
* driverOptions: new NodeSqliteDialect(':memory:'),
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export declare class NodeSqliteDialect extends SqliteDialect {
|
||||
constructor(dbName: string);
|
||||
}
|
||||
43
node_modules/@mikro-orm/sql/dialects/sqlite/NodeSqliteDialect.js
generated
vendored
Normal file
43
node_modules/@mikro-orm/sql/dialects/sqlite/NodeSqliteDialect.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import { SqliteDialect } from 'kysely';
|
||||
/**
|
||||
* Kysely dialect for `node:sqlite` (Node.js 22.5+, Deno 2.2+).
|
||||
*
|
||||
* Bridges `node:sqlite`'s `DatabaseSync` to the `better-sqlite3` interface
|
||||
* that Kysely's `SqliteDialect` expects.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { SqliteDriver, NodeSqliteDialect } from '@mikro-orm/sql';
|
||||
*
|
||||
* const orm = await MikroORM.init({
|
||||
* driver: SqliteDriver,
|
||||
* dbName: ':memory:',
|
||||
* driverOptions: new NodeSqliteDialect(':memory:'),
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export class NodeSqliteDialect extends SqliteDialect {
|
||||
constructor(dbName) {
|
||||
const { DatabaseSync } = globalThis.process.getBuiltinModule('node:sqlite');
|
||||
super({
|
||||
database: () => {
|
||||
const db = new DatabaseSync(dbName);
|
||||
return {
|
||||
prepare(sql) {
|
||||
const stmt = db.prepare(sql);
|
||||
return {
|
||||
reader: /^\s*(select|pragma|explain|with)/i.test(sql) || /\breturning\b/i.test(sql),
|
||||
all: params => stmt.all(...params),
|
||||
run: params => stmt.run(...params),
|
||||
/* v8 ignore next */
|
||||
get: params => stmt.get(...params),
|
||||
};
|
||||
},
|
||||
close() {
|
||||
db.close();
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
12
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteDriver.d.ts
generated
vendored
Normal file
12
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteDriver.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { Configuration } from '@mikro-orm/core';
|
||||
import { AbstractSqlDriver } from '../../AbstractSqlDriver.js';
|
||||
import { BaseSqliteConnection } from './BaseSqliteConnection.js';
|
||||
/**
|
||||
* Generic SQLite driver that uses `driverOptions` for the Kysely dialect.
|
||||
* Use this with any SQLite library by passing a Kysely dialect via `driverOptions`.
|
||||
*
|
||||
* For the default better-sqlite3 experience, use `@mikro-orm/sqlite` instead.
|
||||
*/
|
||||
export declare class SqliteDriver extends AbstractSqlDriver<BaseSqliteConnection> {
|
||||
constructor(config: Configuration);
|
||||
}
|
||||
14
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteDriver.js
generated
vendored
Normal file
14
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteDriver.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { AbstractSqlDriver } from '../../AbstractSqlDriver.js';
|
||||
import { BaseSqliteConnection } from './BaseSqliteConnection.js';
|
||||
import { SqlitePlatform } from './SqlitePlatform.js';
|
||||
/**
|
||||
* Generic SQLite driver that uses `driverOptions` for the Kysely dialect.
|
||||
* Use this with any SQLite library by passing a Kysely dialect via `driverOptions`.
|
||||
*
|
||||
* For the default better-sqlite3 experience, use `@mikro-orm/sqlite` instead.
|
||||
*/
|
||||
export class SqliteDriver extends AbstractSqlDriver {
|
||||
constructor(config) {
|
||||
super(config, new SqlitePlatform(), BaseSqliteConnection, ['kysely']);
|
||||
}
|
||||
}
|
||||
9
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteExceptionConverter.d.ts
generated
vendored
Normal file
9
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteExceptionConverter.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ExceptionConverter, type Dictionary, type DriverException } from '@mikro-orm/core';
|
||||
export declare class SqliteExceptionConverter extends ExceptionConverter {
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @see http://www.sqlite.org/c3ref/c_abort.html
|
||||
* @see https://github.com/doctrine/dbal/blob/master/src/Driver/AbstractSQLiteDriver.php
|
||||
*/
|
||||
convertException(exception: Error & Dictionary): DriverException;
|
||||
}
|
||||
70
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteExceptionConverter.js
generated
vendored
Normal file
70
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteExceptionConverter.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
ConnectionException,
|
||||
ExceptionConverter,
|
||||
InvalidFieldNameException,
|
||||
LockWaitTimeoutException,
|
||||
NonUniqueFieldNameException,
|
||||
CheckConstraintViolationException,
|
||||
NotNullConstraintViolationException,
|
||||
ReadOnlyException,
|
||||
SyntaxErrorException,
|
||||
TableExistsException,
|
||||
TableNotFoundException,
|
||||
UniqueConstraintViolationException,
|
||||
ForeignKeyConstraintViolationException,
|
||||
} from '@mikro-orm/core';
|
||||
export class SqliteExceptionConverter extends ExceptionConverter {
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @see http://www.sqlite.org/c3ref/c_abort.html
|
||||
* @see https://github.com/doctrine/dbal/blob/master/src/Driver/AbstractSQLiteDriver.php
|
||||
*/
|
||||
convertException(exception) {
|
||||
/* v8 ignore next */
|
||||
if (exception.message.includes('database is locked')) {
|
||||
return new LockWaitTimeoutException(exception);
|
||||
}
|
||||
if (
|
||||
exception.message.includes('must be unique') ||
|
||||
exception.message.includes('is not unique') ||
|
||||
exception.message.includes('are not unique') ||
|
||||
exception.message.includes('UNIQUE constraint failed')
|
||||
) {
|
||||
return new UniqueConstraintViolationException(exception);
|
||||
}
|
||||
if (exception.message.includes('may not be NULL') || exception.message.includes('NOT NULL constraint failed')) {
|
||||
return new NotNullConstraintViolationException(exception);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (exception.message.includes('CHECK constraint failed')) {
|
||||
return new CheckConstraintViolationException(exception);
|
||||
}
|
||||
if (exception.message.includes('no such table:')) {
|
||||
return new TableNotFoundException(exception);
|
||||
}
|
||||
if (exception.message.includes('already exists')) {
|
||||
return new TableExistsException(exception);
|
||||
}
|
||||
if (exception.message.includes('no such column:')) {
|
||||
return new InvalidFieldNameException(exception);
|
||||
}
|
||||
if (exception.message.includes('ambiguous column name')) {
|
||||
return new NonUniqueFieldNameException(exception);
|
||||
}
|
||||
if (exception.message.includes('syntax error')) {
|
||||
return new SyntaxErrorException(exception);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (exception.message.includes('attempt to write a readonly database')) {
|
||||
return new ReadOnlyException(exception);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (exception.message.includes('unable to open database file')) {
|
||||
return new ConnectionException(exception);
|
||||
}
|
||||
if (exception.message.includes('FOREIGN KEY constraint failed')) {
|
||||
return new ForeignKeyConstraintViolationException(exception);
|
||||
}
|
||||
return super.convertException(exception);
|
||||
}
|
||||
}
|
||||
6
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteNativeQueryBuilder.d.ts
generated
vendored
Normal file
6
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteNativeQueryBuilder.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { NativeQueryBuilder } from '../../query/NativeQueryBuilder.js';
|
||||
/** @internal */
|
||||
export declare class SqliteNativeQueryBuilder extends NativeQueryBuilder {
|
||||
protected compileTruncate(): void;
|
||||
protected addLockClause(): void;
|
||||
}
|
||||
11
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteNativeQueryBuilder.js
generated
vendored
Normal file
11
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteNativeQueryBuilder.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { NativeQueryBuilder } from '../../query/NativeQueryBuilder.js';
|
||||
/** @internal */
|
||||
export class SqliteNativeQueryBuilder extends NativeQueryBuilder {
|
||||
compileTruncate() {
|
||||
const sql = `delete from ${this.getTableName()}`;
|
||||
this.parts.push(sql);
|
||||
}
|
||||
addLockClause() {
|
||||
return; // not supported
|
||||
}
|
||||
}
|
||||
71
node_modules/@mikro-orm/sql/dialects/sqlite/SqlitePlatform.d.ts
generated
vendored
Normal file
71
node_modules/@mikro-orm/sql/dialects/sqlite/SqlitePlatform.d.ts
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
import { type EntityProperty, type IsolationLevel } from '@mikro-orm/core';
|
||||
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
|
||||
import { SqliteNativeQueryBuilder } from './SqliteNativeQueryBuilder.js';
|
||||
import { SqliteSchemaHelper } from './SqliteSchemaHelper.js';
|
||||
import { SqliteExceptionConverter } from './SqliteExceptionConverter.js';
|
||||
export declare class SqlitePlatform extends AbstractSqlPlatform {
|
||||
protected readonly schemaHelper: SqliteSchemaHelper;
|
||||
protected readonly exceptionConverter: SqliteExceptionConverter;
|
||||
/** @internal */
|
||||
createNativeQueryBuilder(): SqliteNativeQueryBuilder;
|
||||
usesDefaultKeyword(): boolean;
|
||||
usesReturningStatement(): boolean;
|
||||
usesEnumCheckConstraints(): boolean;
|
||||
getCurrentTimestampSQL(length: number): string;
|
||||
getDateTimeTypeDeclarationSQL(column: { length: number }): string;
|
||||
getBeginTransactionSQL(options?: { isolationLevel?: IsolationLevel; readOnly?: boolean }): string[];
|
||||
getEnumTypeDeclarationSQL(column: {
|
||||
items?: unknown[];
|
||||
fieldNames: string[];
|
||||
length?: number;
|
||||
unsigned?: boolean;
|
||||
autoincrement?: boolean;
|
||||
}): string;
|
||||
getTinyIntTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
|
||||
getSmallIntTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
|
||||
getIntegerTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
|
||||
getFloatDeclarationSQL(): string;
|
||||
getBooleanTypeDeclarationSQL(): string;
|
||||
getCharTypeDeclarationSQL(column: { length?: number }): string;
|
||||
getVarcharTypeDeclarationSQL(column: { length?: number }): string;
|
||||
normalizeColumnType(
|
||||
type: string,
|
||||
options: {
|
||||
length?: number;
|
||||
precision?: number;
|
||||
scale?: number;
|
||||
},
|
||||
): string;
|
||||
convertsJsonAutomatically(): boolean;
|
||||
/**
|
||||
* This is used to narrow the value of Date properties as they will be stored as timestamps in sqlite.
|
||||
* We use this method to convert Dates to timestamps when computing the changeset, so we have the right
|
||||
* data type in the payload as well as in original entity data. Without that, we would end up with diffs
|
||||
* including all Date properties, as we would be comparing Date object with timestamp.
|
||||
*/
|
||||
processDateProperty(value: unknown): string | number | Date;
|
||||
getIndexName(
|
||||
tableName: string,
|
||||
columns: string[],
|
||||
type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence',
|
||||
): string;
|
||||
supportsDeferredUniqueConstraints(): boolean;
|
||||
/**
|
||||
* SQLite supports schemas via ATTACH DATABASE. Returns true when there are
|
||||
* attached databases configured.
|
||||
*/
|
||||
supportsSchemas(): boolean;
|
||||
getDefaultSchemaName(): string | undefined;
|
||||
getFullTextWhereClause(): string;
|
||||
escape(value: any): string;
|
||||
convertVersionValue(
|
||||
value: Date | number,
|
||||
prop: EntityProperty,
|
||||
):
|
||||
| number
|
||||
| {
|
||||
$in: (string | number)[];
|
||||
};
|
||||
getJsonArrayElementPropertySQL(alias: string, property: string, _type: string): string;
|
||||
quoteValue(value: any): string;
|
||||
}
|
||||
145
node_modules/@mikro-orm/sql/dialects/sqlite/SqlitePlatform.js
generated
vendored
Normal file
145
node_modules/@mikro-orm/sql/dialects/sqlite/SqlitePlatform.js
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
|
||||
import { SqliteNativeQueryBuilder } from './SqliteNativeQueryBuilder.js';
|
||||
import { SqliteSchemaHelper } from './SqliteSchemaHelper.js';
|
||||
import { SqliteExceptionConverter } from './SqliteExceptionConverter.js';
|
||||
export class SqlitePlatform extends AbstractSqlPlatform {
|
||||
schemaHelper = new SqliteSchemaHelper(this);
|
||||
exceptionConverter = new SqliteExceptionConverter();
|
||||
/** @internal */
|
||||
createNativeQueryBuilder() {
|
||||
return new SqliteNativeQueryBuilder(this);
|
||||
}
|
||||
usesDefaultKeyword() {
|
||||
return false;
|
||||
}
|
||||
usesReturningStatement() {
|
||||
return true;
|
||||
}
|
||||
usesEnumCheckConstraints() {
|
||||
return true;
|
||||
}
|
||||
getCurrentTimestampSQL(length) {
|
||||
return `(strftime('%s', 'now') * 1000)`;
|
||||
}
|
||||
getDateTimeTypeDeclarationSQL(column) {
|
||||
return 'datetime';
|
||||
}
|
||||
getBeginTransactionSQL(options) {
|
||||
return ['begin'];
|
||||
}
|
||||
getEnumTypeDeclarationSQL(column) {
|
||||
if (column.items?.every(item => typeof item === 'string')) {
|
||||
return 'text';
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return this.getTinyIntTypeDeclarationSQL(column);
|
||||
}
|
||||
getTinyIntTypeDeclarationSQL(column) {
|
||||
return this.getIntegerTypeDeclarationSQL(column);
|
||||
}
|
||||
getSmallIntTypeDeclarationSQL(column) {
|
||||
return this.getIntegerTypeDeclarationSQL(column);
|
||||
}
|
||||
getIntegerTypeDeclarationSQL(column) {
|
||||
return 'integer';
|
||||
}
|
||||
getFloatDeclarationSQL() {
|
||||
return 'real';
|
||||
}
|
||||
getBooleanTypeDeclarationSQL() {
|
||||
return 'integer';
|
||||
}
|
||||
getCharTypeDeclarationSQL(column) {
|
||||
return 'text';
|
||||
}
|
||||
getVarcharTypeDeclarationSQL(column) {
|
||||
return 'text';
|
||||
}
|
||||
normalizeColumnType(type, options) {
|
||||
const simpleType = this.extractSimpleType(type);
|
||||
if (['varchar', 'text'].includes(simpleType)) {
|
||||
return this.getVarcharTypeDeclarationSQL(options);
|
||||
}
|
||||
return simpleType;
|
||||
}
|
||||
convertsJsonAutomatically() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* This is used to narrow the value of Date properties as they will be stored as timestamps in sqlite.
|
||||
* We use this method to convert Dates to timestamps when computing the changeset, so we have the right
|
||||
* data type in the payload as well as in original entity data. Without that, we would end up with diffs
|
||||
* including all Date properties, as we would be comparing Date object with timestamp.
|
||||
*/
|
||||
processDateProperty(value) {
|
||||
if (value instanceof Date) {
|
||||
return +value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
getIndexName(tableName, columns, type) {
|
||||
if (type === 'primary') {
|
||||
return this.getDefaultPrimaryName(tableName, columns);
|
||||
}
|
||||
return super.getIndexName(tableName, columns, type);
|
||||
}
|
||||
supportsDeferredUniqueConstraints() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* SQLite supports schemas via ATTACH DATABASE. Returns true when there are
|
||||
* attached databases configured.
|
||||
*/
|
||||
supportsSchemas() {
|
||||
const attachDatabases = this.config.get('attachDatabases');
|
||||
return !!attachDatabases?.length;
|
||||
}
|
||||
getDefaultSchemaName() {
|
||||
// Return 'main' only when schema support is active (i.e., databases are attached)
|
||||
return this.supportsSchemas() ? 'main' : undefined;
|
||||
}
|
||||
getFullTextWhereClause() {
|
||||
return `:column: match :query`;
|
||||
}
|
||||
escape(value) {
|
||||
if (value == null) {
|
||||
return 'null';
|
||||
}
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? 'true' : 'false';
|
||||
}
|
||||
if (typeof value === 'number' || typeof value === 'bigint') {
|
||||
return '' + value;
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return '' + +value;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(v => this.escape(v)).join(', ');
|
||||
}
|
||||
if (Buffer.isBuffer(value)) {
|
||||
return `X'${value.toString('hex')}'`;
|
||||
}
|
||||
return `'${String(value).replace(/'/g, "''")}'`;
|
||||
}
|
||||
convertVersionValue(value, prop) {
|
||||
if (prop.runtimeType === 'Date') {
|
||||
const ts = +value;
|
||||
const str = new Date(ts)
|
||||
.toISOString()
|
||||
.replace('T', ' ')
|
||||
.replace(/\.\d{3}Z$/, '');
|
||||
return { $in: [ts, str] };
|
||||
}
|
||||
return value;
|
||||
}
|
||||
getJsonArrayElementPropertySQL(alias, property, _type) {
|
||||
return `json_extract(${this.quoteIdentifier(alias)}.value, '$.${this.quoteJsonKey(property)}')`;
|
||||
}
|
||||
quoteValue(value) {
|
||||
if (value instanceof Date) {
|
||||
return '' + +value;
|
||||
}
|
||||
return super.quoteValue(value);
|
||||
}
|
||||
}
|
||||
78
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteSchemaHelper.d.ts
generated
vendored
Normal file
78
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteSchemaHelper.d.ts
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import { type Connection } from '@mikro-orm/core';
|
||||
import type { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
||||
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
||||
import type { Column, IndexDef, Table, TableDifference } from '../../typings.js';
|
||||
import type { DatabaseTable } from '../../schema/DatabaseTable.js';
|
||||
import type { DatabaseSchema } from '../../schema/DatabaseSchema.js';
|
||||
export declare class SqliteSchemaHelper extends SchemaHelper {
|
||||
disableForeignKeysSQL(): string;
|
||||
enableForeignKeysSQL(): string;
|
||||
supportsSchemaConstraints(): boolean;
|
||||
getCreateNamespaceSQL(name: string): string;
|
||||
getDropNamespaceSQL(name: string): string;
|
||||
getListTablesSQL(): string;
|
||||
getAllTables(connection: AbstractSqlConnection, schemas?: string[]): Promise<Table[]>;
|
||||
getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
|
||||
private getIgnoredViewsCondition;
|
||||
getListViewsSQL(): string;
|
||||
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
|
||||
getDropDatabaseSQL(name: string): string;
|
||||
loadInformationSchema(
|
||||
schema: DatabaseSchema,
|
||||
connection: AbstractSqlConnection,
|
||||
tables: Table[],
|
||||
schemas?: string[],
|
||||
): Promise<void>;
|
||||
createTable(table: DatabaseTable, alter?: boolean): string[];
|
||||
createTableColumn(column: Column, table: DatabaseTable, _changedProperties?: Set<string>): string | undefined;
|
||||
getAddColumnsSQL(table: DatabaseTable, columns: Column[], diff?: TableDifference): string[];
|
||||
dropForeignKey(tableName: string, constraintName: string): string;
|
||||
getDropColumnsSQL(tableName: string, columns: Column[], schemaName?: string): string;
|
||||
getCreateIndexSQL(tableName: string, index: IndexDef): string;
|
||||
private parseTableDefinition;
|
||||
/**
|
||||
* Returns schema prefix for pragma and sqlite_master queries.
|
||||
* Returns empty string for main database (no prefix needed).
|
||||
*/
|
||||
private getSchemaPrefix;
|
||||
/**
|
||||
* Returns all database names excluding 'temp'.
|
||||
*/
|
||||
private getDatabaseList;
|
||||
/**
|
||||
* Extracts the SELECT part from a CREATE VIEW statement.
|
||||
*/
|
||||
private extractViewDefinition;
|
||||
private getColumns;
|
||||
/**
|
||||
* SQLite strips outer parentheses from expression defaults (`DEFAULT (expr)` → `expr` in pragma).
|
||||
* We need to add them back so they match what we generate in DDL.
|
||||
*/
|
||||
private wrapExpressionDefault;
|
||||
private getEnumDefinitions;
|
||||
getPrimaryKeys(
|
||||
connection: AbstractSqlConnection,
|
||||
indexes: IndexDef[],
|
||||
tableName: string,
|
||||
schemaName?: string,
|
||||
): Promise<string[]>;
|
||||
private getIndexes;
|
||||
private getChecks;
|
||||
private getColumnDefinitions;
|
||||
private getForeignKeys;
|
||||
getManagementDbName(): string;
|
||||
getCreateDatabaseSQL(name: string): string;
|
||||
databaseExists(connection: Connection, name: string): Promise<boolean>;
|
||||
/**
|
||||
* Implicit indexes will be ignored when diffing
|
||||
*/
|
||||
isImplicitIndex(name: string): boolean;
|
||||
dropIndex(table: string, index: IndexDef, oldIndexName?: string): string;
|
||||
/**
|
||||
* SQLite does not support schema-qualified table names in REFERENCES clauses.
|
||||
* Foreign key references can only point to tables in the same database.
|
||||
*/
|
||||
getReferencedTableName(referencedTableName: string, schema?: string): string;
|
||||
alterTable(diff: TableDifference, safe?: boolean): string[];
|
||||
private getAlterTempTableSQL;
|
||||
}
|
||||
543
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteSchemaHelper.js
generated
vendored
Normal file
543
node_modules/@mikro-orm/sql/dialects/sqlite/SqliteSchemaHelper.js
generated
vendored
Normal file
@@ -0,0 +1,543 @@
|
||||
import { Utils } from '@mikro-orm/core';
|
||||
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
||||
/** SpatiaLite system views that should be automatically ignored */
|
||||
const SPATIALITE_VIEWS = [
|
||||
'geometry_columns',
|
||||
'spatial_ref_sys',
|
||||
'views_geometry_columns',
|
||||
'virts_geometry_columns',
|
||||
'geom_cols_ref_sys',
|
||||
'spatial_ref_sys_aux',
|
||||
'vector_layers',
|
||||
'vector_layers_auth',
|
||||
'vector_layers_field_infos',
|
||||
'vector_layers_statistics',
|
||||
'ElementaryGeometries',
|
||||
];
|
||||
export class SqliteSchemaHelper extends SchemaHelper {
|
||||
disableForeignKeysSQL() {
|
||||
return 'pragma foreign_keys = off;';
|
||||
}
|
||||
enableForeignKeysSQL() {
|
||||
return 'pragma foreign_keys = on;';
|
||||
}
|
||||
supportsSchemaConstraints() {
|
||||
return false;
|
||||
}
|
||||
getCreateNamespaceSQL(name) {
|
||||
return '';
|
||||
}
|
||||
getDropNamespaceSQL(name) {
|
||||
return '';
|
||||
}
|
||||
getListTablesSQL() {
|
||||
return (
|
||||
`select name as table_name from sqlite_master where type = 'table' and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys' ` +
|
||||
`union all select name as table_name from sqlite_temp_master where type = 'table' order by name`
|
||||
);
|
||||
}
|
||||
async getAllTables(connection, schemas) {
|
||||
const databases = await this.getDatabaseList(connection);
|
||||
const hasAttachedDbs = databases.length > 1; // More than just 'main'
|
||||
// If no attached databases, use original behavior
|
||||
if (!hasAttachedDbs && !schemas?.length) {
|
||||
return connection.execute(this.getListTablesSQL());
|
||||
}
|
||||
// With attached databases, query each one
|
||||
const targetSchemas = schemas?.length ? schemas : databases;
|
||||
const allTables = [];
|
||||
for (const dbName of targetSchemas) {
|
||||
const prefix = this.getSchemaPrefix(dbName);
|
||||
const tables = await connection.execute(
|
||||
`select name from ${prefix}sqlite_master where type = 'table' ` +
|
||||
`and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys'`,
|
||||
);
|
||||
for (const t of tables) {
|
||||
allTables.push({ table_name: t.name, schema_name: dbName });
|
||||
}
|
||||
}
|
||||
return allTables;
|
||||
}
|
||||
async getNamespaces(connection) {
|
||||
return this.getDatabaseList(connection);
|
||||
}
|
||||
getIgnoredViewsCondition() {
|
||||
return SPATIALITE_VIEWS.map(v => `name != '${v}'`).join(' and ');
|
||||
}
|
||||
getListViewsSQL() {
|
||||
return `select name as view_name, sql as view_definition from sqlite_master where type = 'view' and ${this.getIgnoredViewsCondition()} order by name`;
|
||||
}
|
||||
async loadViews(schema, connection, schemaName) {
|
||||
const databases = await this.getDatabaseList(connection);
|
||||
const hasAttachedDbs = databases.length > 1; // More than just 'main'
|
||||
// If no attached databases and no specific schema, use original behavior
|
||||
if (!hasAttachedDbs && !schemaName) {
|
||||
const views = await connection.execute(this.getListViewsSQL());
|
||||
for (const view of views) {
|
||||
schema.addView(view.view_name, schemaName, this.extractViewDefinition(view.view_definition));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// With attached databases, query each one
|
||||
/* v8 ignore next - schemaName branch not commonly used */
|
||||
const targetDbs = schemaName ? [schemaName] : databases;
|
||||
for (const dbName of targetDbs) {
|
||||
const prefix = this.getSchemaPrefix(dbName);
|
||||
const views = await connection.execute(
|
||||
`select name as view_name, sql as view_definition from ${prefix}sqlite_master where type = 'view' and ${this.getIgnoredViewsCondition()} order by name`,
|
||||
);
|
||||
for (const view of views) {
|
||||
schema.addView(view.view_name, dbName, this.extractViewDefinition(view.view_definition));
|
||||
}
|
||||
}
|
||||
}
|
||||
getDropDatabaseSQL(name) {
|
||||
if (name === ':memory:') {
|
||||
return '';
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return `drop database if exists ${this.quote(name)}`;
|
||||
}
|
||||
async loadInformationSchema(schema, connection, tables, schemas) {
|
||||
for (const t of tables) {
|
||||
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
||||
const cols = await this.getColumns(connection, table.name, table.schema);
|
||||
const indexes = await this.getIndexes(connection, table.name, table.schema);
|
||||
const checks = await this.getChecks(connection, table.name, table.schema);
|
||||
const pks = await this.getPrimaryKeys(connection, indexes, table.name, table.schema);
|
||||
const fks = await this.getForeignKeys(connection, table.name, table.schema);
|
||||
const enums = await this.getEnumDefinitions(connection, table.name, table.schema);
|
||||
table.init(cols, indexes, checks, pks, fks, enums);
|
||||
}
|
||||
}
|
||||
createTable(table, alter) {
|
||||
let sql = `create table ${table.getQuotedName()} (`;
|
||||
const columns = table.getColumns();
|
||||
const lastColumn = columns[columns.length - 1].name;
|
||||
for (const column of columns) {
|
||||
const col = this.createTableColumn(column, table);
|
||||
if (col) {
|
||||
const comma = column.name === lastColumn ? '' : ', ';
|
||||
sql += col + comma;
|
||||
}
|
||||
}
|
||||
const primaryKey = table.getPrimaryKey();
|
||||
const createPrimary = primaryKey?.composite;
|
||||
if (createPrimary && primaryKey) {
|
||||
sql += `, primary key (${primaryKey.columnNames.map(c => this.quote(c)).join(', ')})`;
|
||||
}
|
||||
const parts = [];
|
||||
for (const fk of Object.values(table.getForeignKeys())) {
|
||||
parts.push(this.createForeignKey(table, fk, false));
|
||||
}
|
||||
for (const check of table.getChecks()) {
|
||||
const sql = `constraint ${this.quote(check.name)} check (${check.expression})`;
|
||||
parts.push(sql);
|
||||
}
|
||||
if (parts.length > 0) {
|
||||
sql += ', ' + parts.join(', ');
|
||||
}
|
||||
sql += ')';
|
||||
if (table.comment) {
|
||||
sql += ` /* ${table.comment} */`;
|
||||
}
|
||||
const ret = [];
|
||||
this.append(ret, sql);
|
||||
for (const index of table.getIndexes()) {
|
||||
this.append(ret, this.createIndex(index, table));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
createTableColumn(column, table, _changedProperties) {
|
||||
const col = [this.quote(column.name)];
|
||||
const checks = table.getChecks();
|
||||
const check = checks.findIndex(check => check.columnName === column.name);
|
||||
const useDefault = column.default != null && column.default !== 'null';
|
||||
let columnType = column.type;
|
||||
if (column.autoincrement) {
|
||||
columnType = 'integer';
|
||||
}
|
||||
if (column.generated) {
|
||||
columnType += ` generated always as ${column.generated}`;
|
||||
}
|
||||
col.push(columnType);
|
||||
if (check !== -1) {
|
||||
col.push(`check (${checks[check].expression})`);
|
||||
checks.splice(check, 1);
|
||||
}
|
||||
Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
|
||||
Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
|
||||
Utils.runIfNotEmpty(() => col.push('primary key'), column.primary);
|
||||
Utils.runIfNotEmpty(() => col.push('autoincrement'), column.autoincrement);
|
||||
Utils.runIfNotEmpty(() => col.push(`default ${column.default}`), useDefault);
|
||||
return col.join(' ');
|
||||
}
|
||||
getAddColumnsSQL(table, columns, diff) {
|
||||
return columns.map(column => {
|
||||
let sql = `alter table ${table.getQuotedName()} add column ${this.createTableColumn(column, table)}`;
|
||||
const foreignKey = Object.values(diff.addedForeignKeys).find(
|
||||
fk => fk.columnNames.length === 1 && fk.columnNames[0] === column.name,
|
||||
);
|
||||
if (foreignKey && this.options.createForeignKeyConstraints) {
|
||||
delete diff.addedForeignKeys[foreignKey.constraintName];
|
||||
sql += ' ' + this.createForeignKey(diff.toTable, foreignKey, false, true);
|
||||
}
|
||||
return sql;
|
||||
});
|
||||
}
|
||||
dropForeignKey(tableName, constraintName) {
|
||||
return '';
|
||||
}
|
||||
getDropColumnsSQL(tableName, columns, schemaName) {
|
||||
/* v8 ignore next */
|
||||
const name = this.quote(
|
||||
(schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName,
|
||||
);
|
||||
return columns
|
||||
.map(column => {
|
||||
return `alter table ${name} drop column ${this.quote(column.name)}`;
|
||||
})
|
||||
.join(';\n');
|
||||
}
|
||||
getCreateIndexSQL(tableName, index) {
|
||||
/* v8 ignore next */
|
||||
if (index.expression) {
|
||||
return index.expression;
|
||||
}
|
||||
// SQLite requires: CREATE INDEX schema.index_name ON table_name (columns)
|
||||
// NOT: CREATE INDEX index_name ON schema.table_name (columns)
|
||||
const [schemaName, rawTableName] = this.splitTableName(tableName);
|
||||
const quotedTableName = this.quote(rawTableName);
|
||||
// If there's a schema, prefix the index name with it
|
||||
let keyName;
|
||||
if (schemaName && schemaName !== 'main') {
|
||||
keyName = `${this.quote(schemaName)}.${this.quote(index.keyName)}`;
|
||||
} else {
|
||||
keyName = this.quote(index.keyName);
|
||||
}
|
||||
const sqlPrefix = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${quotedTableName}`;
|
||||
/* v8 ignore next 4 */
|
||||
if (index.columnNames.some(column => column.includes('.'))) {
|
||||
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
||||
const columns = this.platform.getJsonIndexDefinition(index);
|
||||
return `${sqlPrefix} (${columns.join(', ')})`;
|
||||
}
|
||||
// Use getIndexColumns to support advanced options like sort order and collation
|
||||
return `${sqlPrefix} (${this.getIndexColumns(index)})`;
|
||||
}
|
||||
parseTableDefinition(sql, cols) {
|
||||
const columns = {};
|
||||
const constraints = [];
|
||||
// extract all columns definitions
|
||||
let columnsDef = new RegExp(`create table [\`"']?.*?[\`"']? \\((.*)\\)`, 'i').exec(sql.replaceAll('\n', ''))?.[1];
|
||||
/* v8 ignore next */
|
||||
if (columnsDef) {
|
||||
if (columnsDef.includes(', constraint ')) {
|
||||
constraints.push(...columnsDef.substring(columnsDef.indexOf(', constraint') + 2).split(', '));
|
||||
columnsDef = columnsDef.substring(0, columnsDef.indexOf(', constraint'));
|
||||
}
|
||||
for (let i = cols.length - 1; i >= 0; i--) {
|
||||
const col = cols[i];
|
||||
const re = ` *, *[\`"']?${col.name}[\`"']? (.*)`;
|
||||
const columnDef = new RegExp(re, 'i').exec(columnsDef);
|
||||
if (columnDef) {
|
||||
columns[col.name] = { name: col.name, definition: columnDef[1] };
|
||||
columnsDef = columnsDef.substring(0, columnDef.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { columns, constraints };
|
||||
}
|
||||
/**
|
||||
* Returns schema prefix for pragma and sqlite_master queries.
|
||||
* Returns empty string for main database (no prefix needed).
|
||||
*/
|
||||
getSchemaPrefix(schemaName) {
|
||||
if (!schemaName || schemaName === 'main') {
|
||||
return '';
|
||||
}
|
||||
return `${this.platform.quoteIdentifier(schemaName)}.`;
|
||||
}
|
||||
/**
|
||||
* Returns all database names excluding 'temp'.
|
||||
*/
|
||||
async getDatabaseList(connection) {
|
||||
const databases = await connection.execute('pragma database_list');
|
||||
return databases.filter(d => d.name !== 'temp').map(d => d.name);
|
||||
}
|
||||
/**
|
||||
* Extracts the SELECT part from a CREATE VIEW statement.
|
||||
*/
|
||||
extractViewDefinition(viewDefinition) {
|
||||
const match = /create\s+view\s+[`"']?\w+[`"']?\s+as\s+(.*)/is.exec(viewDefinition);
|
||||
/* v8 ignore next - fallback for non-standard view definitions */
|
||||
return match ? match[1] : viewDefinition;
|
||||
}
|
||||
async getColumns(connection, tableName, schemaName) {
|
||||
const prefix = this.getSchemaPrefix(schemaName);
|
||||
const columns = await connection.execute(`pragma ${prefix}table_xinfo('${tableName}')`);
|
||||
const sql = `select sql from ${prefix}sqlite_master where type = ? and name = ?`;
|
||||
const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
|
||||
const composite = columns.reduce((count, col) => count + (col.pk ? 1 : 0), 0) > 1;
|
||||
// there can be only one, so naive check like this should be enough
|
||||
const hasAutoincrement = tableDefinition.sql.toLowerCase().includes('autoincrement');
|
||||
const { columns: columnDefinitions } = this.parseTableDefinition(tableDefinition.sql, columns);
|
||||
return columns.map(col => {
|
||||
const mappedType = connection.getPlatform().getMappedType(col.type);
|
||||
let generated;
|
||||
if (col.hidden > 1) {
|
||||
/* v8 ignore next */
|
||||
const storage = col.hidden === 2 ? 'virtual' : 'stored';
|
||||
const re = new RegExp(`(generated always)? as \\((.*)\\)( ${storage})?$`, 'i');
|
||||
const match = columnDefinitions[col.name].definition.match(re);
|
||||
if (match) {
|
||||
generated = `${match[2]} ${storage}`;
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: col.name,
|
||||
type: col.type,
|
||||
default: this.wrapExpressionDefault(col.dflt_value),
|
||||
nullable: !col.notnull,
|
||||
primary: !!col.pk,
|
||||
mappedType,
|
||||
unsigned: false,
|
||||
autoincrement: !composite && col.pk && this.platform.isNumericColumn(mappedType) && hasAutoincrement,
|
||||
generated,
|
||||
};
|
||||
});
|
||||
}
|
||||
/**
|
||||
* SQLite strips outer parentheses from expression defaults (`DEFAULT (expr)` → `expr` in pragma).
|
||||
* We need to add them back so they match what we generate in DDL.
|
||||
*/
|
||||
wrapExpressionDefault(value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
// simple values that are returned as-is from pragma (no wrapping needed)
|
||||
if (
|
||||
/^-?\d/.test(value) ||
|
||||
/^[xX]'/.test(value) ||
|
||||
value.startsWith("'") ||
|
||||
value.startsWith('"') ||
|
||||
value.startsWith('(')
|
||||
) {
|
||||
return value;
|
||||
}
|
||||
const lower = value.toLowerCase();
|
||||
if (['null', 'true', 'false', 'current_timestamp', 'current_date', 'current_time'].includes(lower)) {
|
||||
return value;
|
||||
}
|
||||
// everything else is an expression that had its outer parens stripped
|
||||
return `(${value})`;
|
||||
}
|
||||
async getEnumDefinitions(connection, tableName, schemaName) {
|
||||
const prefix = this.getSchemaPrefix(schemaName);
|
||||
const sql = `select sql from ${prefix}sqlite_master where type = ? and name = ?`;
|
||||
const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
|
||||
const checkConstraints = [...(tableDefinition.sql.match(/[`["'][^`\]"']+[`\]"'] text check \(.*?\)/gi) ?? [])];
|
||||
return checkConstraints.reduce((o, item) => {
|
||||
// check constraints are defined as (note that last closing paren is missing):
|
||||
// `type` text check (`type` in ('local', 'global')
|
||||
const match = /[`["']([^`\]"']+)[`\]"'] text check \(.* \((.*)\)/i.exec(item);
|
||||
/* v8 ignore next */
|
||||
if (match) {
|
||||
o[match[1]] = match[2].split(',').map(item => /^\(?'(.*)'/.exec(item.trim())[1]);
|
||||
}
|
||||
return o;
|
||||
}, {});
|
||||
}
|
||||
async getPrimaryKeys(connection, indexes, tableName, schemaName) {
|
||||
const prefix = this.getSchemaPrefix(schemaName);
|
||||
const sql = `pragma ${prefix}table_info(\`${tableName}\`)`;
|
||||
const cols = await connection.execute(sql);
|
||||
return cols.filter(col => !!col.pk).map(col => col.name);
|
||||
}
|
||||
async getIndexes(connection, tableName, schemaName) {
|
||||
const prefix = this.getSchemaPrefix(schemaName);
|
||||
const sql = `pragma ${prefix}table_info(\`${tableName}\`)`;
|
||||
const cols = await connection.execute(sql);
|
||||
const indexes = await connection.execute(`pragma ${prefix}index_list(\`${tableName}\`)`);
|
||||
const ret = [];
|
||||
for (const col of cols.filter(c => c.pk)) {
|
||||
ret.push({
|
||||
columnNames: [col.name],
|
||||
keyName: 'primary',
|
||||
constraint: true,
|
||||
unique: true,
|
||||
primary: true,
|
||||
});
|
||||
}
|
||||
for (const index of indexes.filter(index => !this.isImplicitIndex(index.name))) {
|
||||
const res = await connection.execute(`pragma ${prefix}index_info(\`${index.name}\`)`);
|
||||
ret.push(
|
||||
...res.map(row => ({
|
||||
columnNames: [row.name],
|
||||
keyName: index.name,
|
||||
unique: !!index.unique,
|
||||
constraint: !!index.unique,
|
||||
primary: false,
|
||||
})),
|
||||
);
|
||||
}
|
||||
return this.mapIndexes(ret);
|
||||
}
|
||||
async getChecks(connection, tableName, schemaName) {
|
||||
const { columns, constraints } = await this.getColumnDefinitions(connection, tableName, schemaName);
|
||||
const checks = [];
|
||||
for (const key of Object.keys(columns)) {
|
||||
const column = columns[key];
|
||||
const expression = / (check \((.*)\))/i.exec(column.definition);
|
||||
if (expression) {
|
||||
checks.push({
|
||||
name: this.platform.getConfig().getNamingStrategy().indexName(tableName, [column.name], 'check'),
|
||||
definition: expression[1],
|
||||
expression: expression[2],
|
||||
columnName: column.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const constraint of constraints) {
|
||||
const expression = /constraint *[`"']?(.*?)[`"']? * (check \((.*)\))/i.exec(constraint);
|
||||
if (expression) {
|
||||
checks.push({
|
||||
name: expression[1],
|
||||
definition: expression[2],
|
||||
expression: expression[3],
|
||||
});
|
||||
}
|
||||
}
|
||||
return checks;
|
||||
}
|
||||
async getColumnDefinitions(connection, tableName, schemaName) {
|
||||
const prefix = this.getSchemaPrefix(schemaName);
|
||||
const columns = await connection.execute(`pragma ${prefix}table_xinfo('${tableName}')`);
|
||||
const sql = `select sql from ${prefix}sqlite_master where type = ? and name = ?`;
|
||||
const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
|
||||
return this.parseTableDefinition(tableDefinition.sql, columns);
|
||||
}
|
||||
async getForeignKeys(connection, tableName, schemaName) {
|
||||
const { constraints } = await this.getColumnDefinitions(connection, tableName, schemaName);
|
||||
const prefix = this.getSchemaPrefix(schemaName);
|
||||
const fks = await connection.execute(`pragma ${prefix}foreign_key_list(\`${tableName}\`)`);
|
||||
const qualifiedTableName = schemaName ? `${schemaName}.${tableName}` : tableName;
|
||||
return fks.reduce((ret, fk) => {
|
||||
const constraintName = this.platform.getIndexName(tableName, [fk.from], 'foreign');
|
||||
const constraint = constraints?.find(c => c.includes(constraintName));
|
||||
ret[constraintName] = {
|
||||
constraintName,
|
||||
columnName: fk.from,
|
||||
columnNames: [fk.from],
|
||||
localTableName: qualifiedTableName,
|
||||
referencedTableName: fk.table,
|
||||
referencedColumnName: fk.to,
|
||||
referencedColumnNames: [fk.to],
|
||||
updateRule: fk.on_update.toLowerCase(),
|
||||
deleteRule: fk.on_delete.toLowerCase(),
|
||||
deferMode: constraint?.match(/ deferrable initially (deferred|immediate)/i)?.[1].toLowerCase(),
|
||||
};
|
||||
return ret;
|
||||
}, {});
|
||||
}
|
||||
getManagementDbName() {
|
||||
return '';
|
||||
}
|
||||
getCreateDatabaseSQL(name) {
|
||||
return '';
|
||||
}
|
||||
async databaseExists(connection, name) {
|
||||
const tables = await connection.execute(this.getListTablesSQL());
|
||||
return tables.length > 0;
|
||||
}
|
||||
/**
|
||||
* Implicit indexes will be ignored when diffing
|
||||
*/
|
||||
isImplicitIndex(name) {
|
||||
// Ignore indexes with reserved names, e.g. autoindexes
|
||||
return name.startsWith('sqlite_');
|
||||
}
|
||||
dropIndex(table, index, oldIndexName = index.keyName) {
|
||||
return `drop index ${this.quote(oldIndexName)}`;
|
||||
}
|
||||
/**
|
||||
* SQLite does not support schema-qualified table names in REFERENCES clauses.
|
||||
* Foreign key references can only point to tables in the same database.
|
||||
*/
|
||||
getReferencedTableName(referencedTableName, schema) {
|
||||
const [schemaName, tableName] = this.splitTableName(referencedTableName);
|
||||
// Strip any schema prefix - SQLite REFERENCES clause doesn't support it
|
||||
return tableName;
|
||||
}
|
||||
alterTable(diff, safe) {
|
||||
const ret = [];
|
||||
const [schemaName, tableName] = this.splitTableName(diff.name);
|
||||
if (
|
||||
Utils.hasObjectKeys(diff.removedChecks) ||
|
||||
Utils.hasObjectKeys(diff.changedChecks) ||
|
||||
Utils.hasObjectKeys(diff.changedForeignKeys) ||
|
||||
Utils.hasObjectKeys(diff.changedColumns)
|
||||
) {
|
||||
return this.getAlterTempTableSQL(diff);
|
||||
}
|
||||
for (const index of Object.values(diff.removedIndexes)) {
|
||||
this.append(ret, this.dropIndex(diff.name, index));
|
||||
}
|
||||
for (const index of Object.values(diff.changedIndexes)) {
|
||||
this.append(ret, this.dropIndex(diff.name, index));
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (!safe && Object.values(diff.removedColumns).length > 0) {
|
||||
this.append(ret, this.getDropColumnsSQL(tableName, Object.values(diff.removedColumns), schemaName));
|
||||
}
|
||||
if (Object.values(diff.addedColumns).length > 0) {
|
||||
this.append(ret, this.getAddColumnsSQL(diff.toTable, Object.values(diff.addedColumns), diff));
|
||||
}
|
||||
if (Utils.hasObjectKeys(diff.addedForeignKeys) || Utils.hasObjectKeys(diff.addedChecks)) {
|
||||
return this.getAlterTempTableSQL(diff);
|
||||
}
|
||||
for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
|
||||
this.append(ret, this.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
|
||||
}
|
||||
for (const index of Object.values(diff.addedIndexes)) {
|
||||
ret.push(this.createIndex(index, diff.toTable));
|
||||
}
|
||||
for (const index of Object.values(diff.changedIndexes)) {
|
||||
ret.push(this.createIndex(index, diff.toTable, true));
|
||||
}
|
||||
for (const [oldIndexName, index] of Object.entries(diff.renamedIndexes)) {
|
||||
if (index.unique) {
|
||||
this.append(ret, this.dropIndex(diff.name, index, oldIndexName));
|
||||
this.append(ret, this.createIndex(index, diff.toTable));
|
||||
} else {
|
||||
this.append(ret, this.getRenameIndexSQL(diff.name, index, oldIndexName));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
getAlterTempTableSQL(changedTable) {
|
||||
const tempName = `${changedTable.toTable.name}__temp_alter`;
|
||||
const quotedName = this.quote(changedTable.toTable.name);
|
||||
const quotedTempName = this.quote(tempName);
|
||||
const [first, ...rest] = this.createTable(changedTable.toTable);
|
||||
const sql = [
|
||||
'pragma foreign_keys = off;',
|
||||
first.replace(`create table ${quotedName}`, `create table ${quotedTempName}`),
|
||||
];
|
||||
const columns = [];
|
||||
for (const column of changedTable.toTable.getColumns()) {
|
||||
const fromColumn = changedTable.fromTable.getColumn(column.name);
|
||||
if (fromColumn) {
|
||||
columns.push(this.quote(column.name));
|
||||
} else {
|
||||
columns.push(`null as ${this.quote(column.name)}`);
|
||||
}
|
||||
}
|
||||
sql.push(`insert into ${quotedTempName} select ${columns.join(', ')} from ${quotedName};`);
|
||||
sql.push(`drop table ${quotedName};`);
|
||||
sql.push(`alter table ${quotedTempName} rename to ${quotedName};`);
|
||||
sql.push(...rest);
|
||||
sql.push('pragma foreign_keys = on;');
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
6
node_modules/@mikro-orm/sql/dialects/sqlite/index.d.ts
generated
vendored
Normal file
6
node_modules/@mikro-orm/sql/dialects/sqlite/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from './BaseSqliteConnection.js';
|
||||
export * from './NodeSqliteDialect.js';
|
||||
export * from './SqliteDriver.js';
|
||||
export * from './SqlitePlatform.js';
|
||||
export * from './SqliteSchemaHelper.js';
|
||||
export * from './SqliteNativeQueryBuilder.js';
|
||||
6
node_modules/@mikro-orm/sql/dialects/sqlite/index.js
generated
vendored
Normal file
6
node_modules/@mikro-orm/sql/dialects/sqlite/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from './BaseSqliteConnection.js';
|
||||
export * from './NodeSqliteDialect.js';
|
||||
export * from './SqliteDriver.js';
|
||||
export * from './SqlitePlatform.js';
|
||||
export * from './SqliteSchemaHelper.js';
|
||||
export * from './SqliteNativeQueryBuilder.js';
|
||||
Reference in New Issue
Block a user