uql-orm 0.65.1 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/querier/httpQuerier.js +1 -8
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/bunSql/bunSql.util.d.ts +2 -6
- package/dist/bunSql/bunSql.util.js +2 -6
- package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
- package/dist/bunSql/bunSqlQuerier.js +2 -5
- package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
- package/dist/cockroachdb/cockroachDialect.js +4 -13
- package/dist/context/context.browser.js +2 -10
- package/dist/context/context.d.ts +4 -17
- package/dist/context/context.js +4 -17
- package/dist/dialect/abstractDialect.d.ts +4 -19
- package/dist/dialect/abstractDialect.js +2 -20
- package/dist/dialect/abstractSqlDialect.d.ts +47 -212
- package/dist/dialect/abstractSqlDialect.js +68 -222
- package/dist/dialect/aliases.d.ts +2 -12
- package/dist/dialect/aliases.js +4 -12
- package/dist/dialect/hydrateColumn.d.ts +2 -6
- package/dist/dialect/hydrateColumn.js +3 -13
- package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
- package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
- package/dist/dialect/jsonSql.d.ts +6 -27
- package/dist/dialect/jsonSql.js +6 -27
- package/dist/dialect/mergeSqlDialect.d.ts +4 -22
- package/dist/dialect/mergeSqlDialect.js +4 -22
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
- package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
- package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
- package/dist/dialect/pgLikeSqlDialect.js +36 -39
- package/dist/dialect/queryContext.d.ts +4 -22
- package/dist/dialect/queryContext.js +4 -22
- package/dist/dialect/queryJoins.d.ts +3 -12
- package/dist/dialect/queryJoins.js +3 -12
- package/dist/dialect/vectorCast.d.ts +2 -12
- package/dist/dialect/vectorCast.js +3 -19
- package/dist/dialect/vectorSqlDialect.d.ts +8 -38
- package/dist/dialect/vectorSqlDialect.js +7 -38
- package/dist/entity/decorator/bag.d.ts +6 -19
- package/dist/entity/decorator/bag.js +6 -22
- package/dist/entity/decorator/entity.d.ts +5 -10
- package/dist/entity/decorator/entity.js +2 -7
- package/dist/entity/decorator/members.d.ts +10 -31
- package/dist/entity/decorator/members.js +3 -12
- package/dist/entity/metadata/definition.d.ts +5 -21
- package/dist/entity/metadata/definition.js +69 -91
- package/dist/http/handler.d.ts +2 -14
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/libsql/libsqlDialect.d.ts +1 -8
- package/dist/libsql/libsqlDialect.js +1 -8
- package/dist/maria/mariaDialect.d.ts +3 -5
- package/dist/maria/mariaDialect.js +5 -5
- package/dist/maria/mariadbQuerier.js +2 -2
- package/dist/maria/mariadbQuerierPool.js +1 -6
- package/dist/migrate/builder/migrationBuilder.js +3 -19
- package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
- package/dist/migrate/builder/splitSqlStatements.js +2 -22
- package/dist/migrate/builder/types.d.ts +2 -15
- package/dist/migrate/cli-config.js +2 -11
- package/dist/migrate/cli.js +2 -7
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
- package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
- package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
- package/dist/migrate/ddl/indexDdl.d.ts +2 -5
- package/dist/migrate/ddl/indexDdl.js +2 -5
- package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
- package/dist/migrate/ddl/pgIndexDdl.js +3 -13
- package/dist/migrate/generator/definitionToNode.d.ts +2 -9
- package/dist/migrate/generator/definitionToNode.js +3 -17
- package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
- package/dist/migrate/generator/indexNodeToSchema.js +2 -3
- package/dist/migrate/generator/mongoCommand.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
- package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
- package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
- package/dist/migrate/introspection/mongoIntrospector.js +48 -46
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
- package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
- package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
- package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
- package/dist/migrate/introspection/postgresIntrospector.js +68 -59
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
- package/dist/migrate/migrator.d.ts +9 -53
- package/dist/migrate/migrator.js +32 -65
- package/dist/migrate/schemaGenerator.d.ts +20 -66
- package/dist/migrate/schemaGenerator.js +32 -93
- package/dist/mongo/mongoDialect.d.ts +21 -53
- package/dist/mongo/mongoDialect.js +25 -70
- package/dist/mongo/mongodbQuerier.d.ts +5 -8
- package/dist/mongo/mongodbQuerier.js +31 -65
- package/dist/mssql/mssqlDialect.d.ts +8 -34
- package/dist/mssql/mssqlDialect.js +37 -51
- package/dist/mssql/mssqlQuerier.d.ts +37 -4
- package/dist/mssql/mssqlQuerier.js +2 -2
- package/dist/mssql/mssqlWireTypes.d.ts +2 -14
- package/dist/mssql/mssqlWireTypes.js +2 -14
- package/dist/nestjs/uqlModule.js +2 -7
- package/dist/pglite/pgliteQuerier.d.ts +1 -9
- package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
- package/dist/pglite/pgliteQuerierPool.js +3 -18
- package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
- package/dist/postgres/abstractPgQuerierPool.js +1 -8
- package/dist/postgres/pgNumericTypes.d.ts +3 -26
- package/dist/postgres/pgNumericTypes.js +3 -26
- package/dist/postgres/postgresDialect.d.ts +4 -10
- package/dist/postgres/postgresDialect.js +4 -10
- package/dist/querier/abstractQuerier.d.ts +35 -103
- package/dist/querier/abstractQuerier.js +105 -201
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
- package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
- package/dist/querier/abstractSqlQuerier.d.ts +15 -36
- package/dist/querier/abstractSqlQuerier.js +49 -131
- package/dist/schema/canonicalType.d.ts +3 -21
- package/dist/schema/canonicalType.js +22 -67
- package/dist/schema/dependencyGraph.d.ts +2 -8
- package/dist/schema/dependencyGraph.js +2 -32
- package/dist/schema/index.d.ts +1 -25
- package/dist/schema/index.js +0 -26
- package/dist/schema/indexColumns.d.ts +1 -8
- package/dist/schema/indexColumns.js +1 -8
- package/dist/schema/indexDifferences.d.ts +7 -40
- package/dist/schema/indexDifferences.js +6 -31
- package/dist/schema/schemaAST.d.ts +8 -175
- package/dist/schema/schemaAST.js +13 -365
- package/dist/schema/schemaASTBuilder.d.ts +2 -24
- package/dist/schema/schemaASTBuilder.js +6 -41
- package/dist/schema/schemaASTDiffer.d.ts +6 -46
- package/dist/schema/schemaASTDiffer.js +8 -56
- package/dist/schema/types.d.ts +5 -61
- package/dist/schema/types.js +3 -6
- package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
- package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
- package/dist/sqlite/localSqliteQuerierPool.js +1 -7
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
- package/dist/sqlite/sqliteDialect.d.ts +5 -20
- package/dist/sqlite/sqliteDialect.js +29 -35
- package/dist/turso/tursoDialect.d.ts +4 -6
- package/dist/turso/tursoDialect.js +4 -6
- package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
- package/dist/turso/tursoLocalQuerierPool.js +1 -7
- package/dist/turso/tursoQuerierPool.d.ts +2 -6
- package/dist/turso/tursoQuerierPool.js +2 -6
- package/dist/turso/tursoSessionQuerier.d.ts +1 -7
- package/dist/turso/tursoSessionQuerier.js +1 -7
- package/dist/type/dialect.d.ts +42 -94
- package/dist/type/dialect.js +3 -13
- package/dist/type/entity.d.ts +189 -551
- package/dist/type/entity.js +26 -9
- package/dist/type/logger.d.ts +2 -14
- package/dist/type/migration.d.ts +9 -38
- package/dist/type/querier.d.ts +9 -28
- package/dist/type/querierPool.d.ts +4 -26
- package/dist/type/query.d.ts +28 -78
- package/dist/type/query.js +2 -7
- package/dist/type/queryAggregate.d.ts +18 -98
- package/dist/type/queryRaw.d.ts +1 -8
- package/dist/type/queryRaw.js +1 -8
- package/dist/type/queryWhere.d.ts +13 -61
- package/dist/type/universalQuerier.d.ts +18 -105
- package/dist/type/utility.d.ts +12 -24
- package/dist/type/vector.d.ts +8 -38
- package/dist/type/vector.js +1 -1
- package/dist/type/wire.d.ts +2 -5
- package/dist/util/dialect.util.d.ts +9 -27
- package/dist/util/dialect.util.js +10 -27
- package/dist/util/field.util.d.ts +5 -37
- package/dist/util/field.util.js +7 -50
- package/dist/util/fieldOption.util.d.ts +7 -15
- package/dist/util/fieldOption.util.js +1 -1
- package/dist/util/filters.util.d.ts +2 -5
- package/dist/util/filters.util.js +2 -5
- package/dist/util/logger.d.ts +2 -6
- package/dist/util/logger.js +2 -6
- package/dist/util/object.util.d.ts +2 -6
- package/dist/util/object.util.js +1 -5
- package/dist/util/raw.d.ts +3 -23
- package/dist/util/relationQuery.util.d.ts +3 -14
- package/dist/util/relationQuery.util.js +3 -14
- package/dist/util/rowKey.util.d.ts +2 -10
- package/dist/util/rowKey.util.js +2 -10
- package/dist/util/sql.util.d.ts +6 -37
- package/dist/util/sql.util.js +13 -73
- package/dist/util/sqlLiteral.d.ts +2 -13
- package/dist/util/sqlLiteral.js +8 -13
- package/dist/util/string.util.js +0 -2
- package/package.json +4 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { SchemaAST } from '../../schema/schemaAST.js';
|
|
1
|
+
import { createTableNode, SchemaAST } from '../../schema/schemaAST.js';
|
|
2
|
+
import { isMongoQuerier, } from '../../type/index.js';
|
|
2
3
|
/**
|
|
3
4
|
* MongoDB schema introspector.
|
|
4
5
|
* MongoDB doesn't have a fixed schema, so this primarily focuses on collections and indexes.
|
|
@@ -16,55 +17,22 @@ export class MongoSchemaIntrospector {
|
|
|
16
17
|
for (const name of tableNames) {
|
|
17
18
|
const schema = await this.getTableSchema(name);
|
|
18
19
|
if (schema) {
|
|
19
|
-
|
|
20
|
-
const table = {
|
|
21
|
-
name,
|
|
22
|
-
columns,
|
|
23
|
-
primaryKey: [],
|
|
24
|
-
indexes: [],
|
|
25
|
-
incomingRelations: [],
|
|
26
|
-
outgoingRelations: [],
|
|
27
|
-
};
|
|
28
|
-
if (schema.indexes) {
|
|
29
|
-
for (const idx of schema.indexes) {
|
|
30
|
-
for (const { column: colName } of idx.entries) {
|
|
31
|
-
let column = columns.get(colName);
|
|
32
|
-
if (!column) {
|
|
33
|
-
column = {
|
|
34
|
-
name: colName,
|
|
35
|
-
type: { category: 'string' }, // MongoDB fields are flexible, but indexes usually target strings/numbers
|
|
36
|
-
nullable: true,
|
|
37
|
-
isPrimaryKey: false,
|
|
38
|
-
isAutoIncrement: false,
|
|
39
|
-
isUnique: false,
|
|
40
|
-
table,
|
|
41
|
-
referencedBy: [],
|
|
42
|
-
};
|
|
43
|
-
columns.set(colName, column);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
table.indexes.push({ name: idx.name, table, entries: idx.entries, unique: idx.unique });
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
ast.addTable(table);
|
|
20
|
+
ast.addTable(buildTable(schema));
|
|
50
21
|
}
|
|
51
22
|
}
|
|
52
23
|
return ast;
|
|
53
24
|
}
|
|
54
25
|
async getTableSchema(tableName) {
|
|
55
|
-
return this.
|
|
56
|
-
|
|
57
|
-
const collections = await db.listCollections({ name: tableName }).toArray();
|
|
58
|
-
if (collections.length === 0) {
|
|
26
|
+
return this.withDb(async (db) => {
|
|
27
|
+
if (!(await hasCollection(db, tableName))) {
|
|
59
28
|
return undefined;
|
|
60
29
|
}
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
// silently made every field below unchecked.
|
|
30
|
+
// Annotated rather than inferred: the driver's `indexes()` is overloaded and resolves to `any` on
|
|
31
|
+
// some versions, which silently made every field below unchecked.
|
|
64
32
|
const indexes = await db.collection(tableName).indexes();
|
|
65
33
|
return {
|
|
66
34
|
name: tableName,
|
|
67
|
-
columns: [],
|
|
35
|
+
columns: [],
|
|
68
36
|
indexes: indexes.map((idx) => ({
|
|
69
37
|
name: idx.name ?? Object.keys(idx.key).join('_'),
|
|
70
38
|
entries: Object.keys(idx.key).map((column) => ({ column })),
|
|
@@ -73,15 +41,49 @@ export class MongoSchemaIntrospector {
|
|
|
73
41
|
};
|
|
74
42
|
});
|
|
75
43
|
}
|
|
44
|
+
/** Collections only, the way a SQL engine lists its base tables: no view, nor the `system.views` behind one. */
|
|
76
45
|
async getTableNames() {
|
|
77
|
-
return this.
|
|
78
|
-
const {
|
|
79
|
-
const collections = await db.listCollections().toArray();
|
|
80
|
-
return collections.map((
|
|
46
|
+
return this.withDb(async (db) => {
|
|
47
|
+
const filter = { type: 'collection', name: { $not: /^system\./ } };
|
|
48
|
+
const collections = await db.listCollections(filter, { nameOnly: true }).toArray();
|
|
49
|
+
return collections.map((collection) => collection.name);
|
|
81
50
|
});
|
|
82
51
|
}
|
|
83
52
|
async tableExists(tableName) {
|
|
84
|
-
|
|
85
|
-
return names.includes(tableName);
|
|
53
|
+
return this.withDb((db) => hasCollection(db, tableName));
|
|
86
54
|
}
|
|
55
|
+
withDb(task) {
|
|
56
|
+
return this.pool.withQuerier((querier) => {
|
|
57
|
+
if (!isMongoQuerier(querier)) {
|
|
58
|
+
throw new TypeError('MongoSchemaIntrospector requires a MongoDB querier');
|
|
59
|
+
}
|
|
60
|
+
return task(querier.db);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function hasCollection(db, name) {
|
|
65
|
+
const collections = await db.listCollections({ name, type: 'collection' }, { nameOnly: true }).toArray();
|
|
66
|
+
return collections.length > 0;
|
|
67
|
+
}
|
|
68
|
+
/** Mongo has no columns to read, so a table's are the fields its indexes name, one node per field. */
|
|
69
|
+
function buildTable({ name, indexes = [] }) {
|
|
70
|
+
const table = createTableNode(name);
|
|
71
|
+
for (const index of indexes) {
|
|
72
|
+
for (const { column } of index.entries) {
|
|
73
|
+
if (!table.columns.has(column)) {
|
|
74
|
+
table.columns.set(column, {
|
|
75
|
+
name: column,
|
|
76
|
+
type: { category: 'string' },
|
|
77
|
+
nullable: true,
|
|
78
|
+
isPrimaryKey: false,
|
|
79
|
+
isAutoIncrement: false,
|
|
80
|
+
isUnique: false,
|
|
81
|
+
table,
|
|
82
|
+
referencedBy: [],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
table.indexes.push({ name: index.name, table, entries: index.entries, unique: index.unique });
|
|
87
|
+
}
|
|
88
|
+
return table;
|
|
87
89
|
}
|
|
@@ -12,8 +12,8 @@ export declare class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospect
|
|
|
12
12
|
protected readonly defaultSchemaExpr = "SCHEMA_NAME()";
|
|
13
13
|
protected getTableNamesQuery(): string;
|
|
14
14
|
protected tableExistsQuery(): string;
|
|
15
|
-
protected parseTableExistsResult(
|
|
16
|
-
count
|
|
15
|
+
protected parseTableExistsResult([row]: {
|
|
16
|
+
count: number;
|
|
17
17
|
}[]): boolean;
|
|
18
18
|
/**
|
|
19
19
|
* From `sys` rather than `INFORMATION_SCHEMA`, which has no identity flag and no per-column view of
|
|
@@ -40,8 +40,8 @@ export declare class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospect
|
|
|
40
40
|
update_rule: string;
|
|
41
41
|
}[]): Promise<ForeignKeySchema[]>;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
* `(N'x')`
|
|
43
|
+
* The engine reprints a default from its own parse tree: all of it in one pair of parentheses, and a
|
|
44
|
+
* number in a second, so `((0))`, `((1)+(2))`, `(N'x')` and `(getdate())`.
|
|
45
45
|
*/
|
|
46
46
|
protected parseDefaultValue(defaultValue: string | null): unknown;
|
|
47
47
|
}
|
|
@@ -26,9 +26,8 @@ export class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
26
26
|
AND TABLE_NAME = @p1
|
|
27
27
|
`;
|
|
28
28
|
}
|
|
29
|
-
parseTableExistsResult(
|
|
30
|
-
|
|
31
|
-
return Number(results[0]?.count) > 0;
|
|
29
|
+
parseTableExistsResult([row]) {
|
|
30
|
+
return row.count > 0;
|
|
32
31
|
}
|
|
33
32
|
/**
|
|
34
33
|
* From `sys` rather than `INFORMATION_SCHEMA`, which has no identity flag and no per-column view of
|
|
@@ -142,46 +141,38 @@ export class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
142
141
|
async mapIndexesResult(_read, _tableName, results) {
|
|
143
142
|
return results.map((row) => ({
|
|
144
143
|
name: row.index_name,
|
|
145
|
-
entries:
|
|
144
|
+
entries: row.columns.split(',').map((column) => ({ column })),
|
|
146
145
|
unique: Boolean(row.is_unique),
|
|
147
146
|
}));
|
|
148
147
|
}
|
|
149
148
|
async mapForeignKeysResult(_read, _tableName, results) {
|
|
150
149
|
return results.map((row) => ({
|
|
151
150
|
name: row.constraint_name,
|
|
152
|
-
columns:
|
|
153
|
-
references: { table: row.referenced_table, columns:
|
|
151
|
+
columns: row.columns.split(','),
|
|
152
|
+
references: { table: row.referenced_table, columns: row.referenced_columns.split(',') },
|
|
154
153
|
// `sys` spells them with an underscore: `SET_NULL`, `NO_ACTION`.
|
|
155
|
-
onDelete: this.normalizeReferentialAction(
|
|
156
|
-
onUpdate: this.normalizeReferentialAction(
|
|
154
|
+
onDelete: this.normalizeReferentialAction(row.delete_rule.replaceAll('_', ' ')),
|
|
155
|
+
onUpdate: this.normalizeReferentialAction(row.update_rule.replaceAll('_', ' ')),
|
|
157
156
|
}));
|
|
158
157
|
}
|
|
159
158
|
/**
|
|
160
|
-
*
|
|
161
|
-
* `(N'x')`
|
|
159
|
+
* The engine reprints a default from its own parse tree: all of it in one pair of parentheses, and a
|
|
160
|
+
* number in a second, so `((0))`, `((1)+(2))`, `(N'x')` and `(getdate())`.
|
|
162
161
|
*/
|
|
163
162
|
parseDefaultValue(defaultValue) {
|
|
164
|
-
if (defaultValue === null
|
|
163
|
+
if (defaultValue === null) {
|
|
165
164
|
return undefined;
|
|
166
165
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
const text = defaultValue.slice(1, -1);
|
|
167
|
+
const number = /^\((-?\d+(?:\.\d+)?)\)$/.exec(text);
|
|
168
|
+
if (number) {
|
|
169
|
+
return Number(number[1]);
|
|
170
170
|
}
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
const quoted = /^N?'(.*)'$/s.exec(text);
|
|
172
|
+
if (quoted) {
|
|
173
|
+
return quoted[1].replaceAll("''", "'");
|
|
173
174
|
}
|
|
174
|
-
|
|
175
|
-
if (unicode.startsWith("'") && unicode.endsWith("'")) {
|
|
176
|
-
return unicode.slice(1, -1).replaceAll("''", "'");
|
|
177
|
-
}
|
|
178
|
-
if (/^-?\d+$/.test(text)) {
|
|
179
|
-
return Number.parseInt(text, 10);
|
|
180
|
-
}
|
|
181
|
-
if (/^-?\d+\.\d+$/.test(text)) {
|
|
182
|
-
return Number.parseFloat(text);
|
|
183
|
-
}
|
|
184
|
-
return text;
|
|
175
|
+
return text === 'NULL' ? null : text;
|
|
185
176
|
}
|
|
186
177
|
}
|
|
187
178
|
/** The types whose `max_length` is a width rather than a fixed storage size. */
|
|
@@ -8,8 +8,8 @@ export declare class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospect
|
|
|
8
8
|
protected readonly defaultSchemaExpr = "DATABASE()";
|
|
9
9
|
protected getTableNamesQuery(): string;
|
|
10
10
|
protected tableExistsQuery(): string;
|
|
11
|
-
protected parseTableExistsResult(
|
|
12
|
-
count
|
|
11
|
+
protected parseTableExistsResult([row]: {
|
|
12
|
+
count: number | bigint;
|
|
13
13
|
}[]): boolean;
|
|
14
14
|
protected getColumnsQuery(_tableName: string): string;
|
|
15
15
|
protected getIndexesQuery(_tableName: string): string;
|
|
@@ -29,6 +29,11 @@ export declare class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospect
|
|
|
29
29
|
delete_rule: string;
|
|
30
30
|
update_rule: string;
|
|
31
31
|
}[]): Promise<ForeignKeySchema[]>;
|
|
32
|
+
/**
|
|
33
|
+
* MariaDB prints a string default as the literal it is (`'it''s'`). MySQL prints one bare, save an
|
|
34
|
+
* expression default (`DEFAULT ('x')`, what a `TEXT` column takes), which comes with a charset
|
|
35
|
+
* introducer and every quote and backslash escaped once more: `_utf8mb4\'x\'`.
|
|
36
|
+
*/
|
|
32
37
|
protected parseDefaultValue(defaultValue: string | null): unknown;
|
|
33
38
|
}
|
|
34
39
|
type MysqlColumnRow = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { unescapeMysqlString } from '../../util/sqlLiteral.js';
|
|
1
2
|
import { AbstractSqlSchemaIntrospector } from './abstractSqlSchemaIntrospector.js';
|
|
2
3
|
/**
|
|
3
4
|
* MySQL/MariaDB schema introspector.
|
|
@@ -23,9 +24,8 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
23
24
|
AND TABLE_NAME = ?
|
|
24
25
|
`;
|
|
25
26
|
}
|
|
26
|
-
parseTableExistsResult(
|
|
27
|
-
|
|
28
|
-
return Number(results[0]?.count) > 0;
|
|
27
|
+
parseTableExistsResult([row]) {
|
|
28
|
+
return Number(row.count) > 0;
|
|
29
29
|
}
|
|
30
30
|
getColumnsQuery(_tableName) {
|
|
31
31
|
return /*sql*/ `
|
|
@@ -98,7 +98,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
98
98
|
nullable: row.is_nullable === 'YES',
|
|
99
99
|
defaultValue: this.parseDefaultValue(row.column_default),
|
|
100
100
|
isPrimaryKey: row.column_key === 'PRI',
|
|
101
|
-
isAutoIncrement:
|
|
101
|
+
isAutoIncrement: row.extra.toLowerCase().includes('auto_increment'),
|
|
102
102
|
isUnique: row.column_key === 'UNI',
|
|
103
103
|
length: this.toNumber(row.character_maximum_length),
|
|
104
104
|
precision: this.toNumber(row.numeric_precision),
|
|
@@ -112,7 +112,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
112
112
|
// A functional or multi-valued key part has no `COLUMN_NAME` - the `COALESCE` above keeps its
|
|
113
113
|
// place in the list, and it is reported as the expression it is, which is what stops diffing
|
|
114
114
|
// from comparing an entry list the server cannot state against the entity's own.
|
|
115
|
-
entries:
|
|
115
|
+
entries: row.columns.split(',').map((column) => (column ? { column } : { column, expression: true })),
|
|
116
116
|
unique: Boolean(row.is_unique),
|
|
117
117
|
}));
|
|
118
118
|
}
|
|
@@ -125,6 +125,11 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
125
125
|
onUpdate: this.normalizeReferentialAction(row.update_rule),
|
|
126
126
|
}));
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* MariaDB prints a string default as the literal it is (`'it''s'`). MySQL prints one bare, save an
|
|
130
|
+
* expression default (`DEFAULT ('x')`, what a `TEXT` column takes), which comes with a charset
|
|
131
|
+
* introducer and every quote and backslash escaped once more: `_utf8mb4\'x\'`.
|
|
132
|
+
*/
|
|
128
133
|
parseDefaultValue(defaultValue) {
|
|
129
134
|
if (defaultValue === null) {
|
|
130
135
|
return undefined;
|
|
@@ -136,16 +141,13 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
136
141
|
if (normalized === 'CURRENT_TIMESTAMP' || normalized === 'CURRENT_TIMESTAMP()') {
|
|
137
142
|
return 'CURRENT_TIMESTAMP';
|
|
138
143
|
}
|
|
139
|
-
if (/^-?\d
|
|
140
|
-
return Number
|
|
144
|
+
if (/^-?\d+(\.\d+)?$/.test(defaultValue)) {
|
|
145
|
+
return Number(defaultValue);
|
|
141
146
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return defaultValue.slice(1, -1);
|
|
147
|
-
}
|
|
148
|
-
return defaultValue;
|
|
147
|
+
const introduced = /^_\w+(\\'.*\\')$/s.exec(defaultValue);
|
|
148
|
+
const literal = introduced ? unescapeMysqlString(introduced[1]) : defaultValue;
|
|
149
|
+
const quoted = /^'(.*)'$/s.exec(literal);
|
|
150
|
+
return quoted ? unescapeMysqlString(quoted[1]) : literal;
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
153
|
/**
|
|
@@ -13,7 +13,7 @@ export declare class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrosp
|
|
|
13
13
|
readonly indexFacets: ReadonlySet<IndexFacet>;
|
|
14
14
|
protected getTableNamesQuery(): string;
|
|
15
15
|
protected tableExistsQuery(): string;
|
|
16
|
-
protected parseTableExistsResult(
|
|
16
|
+
protected parseTableExistsResult([row]: RawRow[]): boolean;
|
|
17
17
|
protected getColumnsQuery(_tableName: string): string;
|
|
18
18
|
/**
|
|
19
19
|
* `attname` where the entry is a column, `pg_get_indexdef` for that one position where it is an
|
|
@@ -36,22 +36,29 @@ export declare class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrosp
|
|
|
36
36
|
* compare. This one decides which indexes are reported at all.
|
|
37
37
|
*/
|
|
38
38
|
protected readonly constraintIndexTypes: readonly string[];
|
|
39
|
+
/** From `pg_constraint`, whose key arrays keep each column paired with the one it references. */
|
|
39
40
|
protected getForeignKeysQuery(_tableName: string): string;
|
|
40
41
|
protected getPrimaryKeyQuery(_tableName: string): string;
|
|
41
42
|
protected mapColumnsResult(_read: TableRowReader, _tableName: string, results: PostgresColumnRow[]): Promise<ColumnSchema[]>;
|
|
42
43
|
protected mapIndexesResult(_read: TableRowReader, _tableName: string, results: PostgresIndexRow[]): Promise<IndexSchema[]>;
|
|
43
|
-
protected mapForeignKeysResult(_read: TableRowReader, _tableName: string, results:
|
|
44
|
-
constraint_name: string;
|
|
45
|
-
columns: string[];
|
|
46
|
-
referenced_table: string;
|
|
47
|
-
referenced_columns: string[];
|
|
48
|
-
delete_rule: string;
|
|
49
|
-
update_rule: string;
|
|
50
|
-
}[]): Promise<ForeignKeySchema[]>;
|
|
44
|
+
protected mapForeignKeysResult(_read: TableRowReader, _tableName: string, results: PostgresForeignKeyRow[]): Promise<ForeignKeySchema[]>;
|
|
51
45
|
protected normalizeType(dataType: string, udtName: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Postgres quotes a negative number (`'-3'::integer`); CockroachDB parenthesizes one (`(-3)`) and
|
|
48
|
+
* writes a quote-bearing string in escape syntax (`e'it\'s'`). Any other cast is dropped, and a
|
|
49
|
+
* function call (`now()`, `nextval(...)`) is returned as written.
|
|
50
|
+
*/
|
|
52
51
|
protected parseDefaultValue(defaultValue: string | null): unknown;
|
|
53
52
|
protected isAutoIncrement(columnDefault: string | null, isIdentity: string): boolean;
|
|
54
53
|
}
|
|
54
|
+
/** `pg_constraint`'s one-letter spelling of each action. */
|
|
55
|
+
declare const FOREIGN_KEY_ACTION_CODES: {
|
|
56
|
+
readonly a: 'NO ACTION';
|
|
57
|
+
readonly r: 'RESTRICT';
|
|
58
|
+
readonly c: 'CASCADE';
|
|
59
|
+
readonly n: 'SET NULL';
|
|
60
|
+
readonly d: 'SET DEFAULT';
|
|
61
|
+
};
|
|
55
62
|
/**
|
|
56
63
|
* CockroachDB answers the same catalogue queries and differs only in what it can express: v26.2.5
|
|
57
64
|
* still rejects `NULLS FIRST/LAST` and operator classes as "unimplemented", and it sorts nulls first
|
|
@@ -69,6 +76,14 @@ export declare class CockroachSchemaIntrospector extends PostgresSchemaIntrospec
|
|
|
69
76
|
*/
|
|
70
77
|
protected readonly constraintIndexTypes: readonly string[];
|
|
71
78
|
}
|
|
79
|
+
type PostgresForeignKeyRow = {
|
|
80
|
+
constraint_name: string;
|
|
81
|
+
columns: string[];
|
|
82
|
+
referenced_table: string;
|
|
83
|
+
referenced_columns: string[];
|
|
84
|
+
delete_rule: keyof typeof FOREIGN_KEY_ACTION_CODES;
|
|
85
|
+
update_rule: keyof typeof FOREIGN_KEY_ACTION_CODES;
|
|
86
|
+
};
|
|
72
87
|
/** One entry of one index; what the index itself is repeats across its rows. */
|
|
73
88
|
type PostgresIndexRow = {
|
|
74
89
|
index_name: string;
|
|
@@ -34,8 +34,8 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
34
34
|
) AS exists
|
|
35
35
|
`;
|
|
36
36
|
}
|
|
37
|
-
parseTableExistsResult(
|
|
38
|
-
return
|
|
37
|
+
parseTableExistsResult([row]) {
|
|
38
|
+
return row['exists'] === true;
|
|
39
39
|
}
|
|
40
40
|
getColumnsQuery(_tableName) {
|
|
41
41
|
return /*sql*/ `
|
|
@@ -50,28 +50,25 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
50
50
|
c.numeric_scale,
|
|
51
51
|
c.is_identity,
|
|
52
52
|
c.identity_generation,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
LIMIT 1),
|
|
61
|
-
FALSE
|
|
53
|
+
EXISTS (
|
|
54
|
+
SELECT 1 FROM information_schema.table_constraints tc
|
|
55
|
+
JOIN information_schema.key_column_usage kcu USING (constraint_schema, constraint_name)
|
|
56
|
+
WHERE tc.table_schema = c.table_schema
|
|
57
|
+
AND tc.table_name = c.table_name
|
|
58
|
+
AND tc.constraint_type = 'PRIMARY KEY'
|
|
59
|
+
AND kcu.column_name = c.column_name
|
|
62
60
|
) AS is_primary_key,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
FALSE
|
|
61
|
+
EXISTS (
|
|
62
|
+
SELECT 1 FROM information_schema.table_constraints tc
|
|
63
|
+
JOIN information_schema.key_column_usage kcu USING (constraint_schema, constraint_name)
|
|
64
|
+
WHERE tc.table_schema = c.table_schema
|
|
65
|
+
AND tc.table_name = c.table_name
|
|
66
|
+
AND tc.constraint_type = 'UNIQUE'
|
|
67
|
+
GROUP BY tc.constraint_name
|
|
68
|
+
HAVING COUNT(*) = 1 AND MIN(kcu.column_name) = c.column_name
|
|
72
69
|
) AS is_unique,
|
|
73
70
|
pg_catalog.col_description(
|
|
74
|
-
(
|
|
71
|
+
(quote_ident(c.table_schema) || '.' || quote_ident(c.table_name))::regclass,
|
|
75
72
|
c.ordinal_position
|
|
76
73
|
) AS column_comment
|
|
77
74
|
FROM information_schema.columns c
|
|
@@ -113,7 +110,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
113
110
|
LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum AND k.attnum > 0
|
|
114
111
|
LEFT JOIN pg_opclass op ON op.oid = ix.indclass[k.n - 1]
|
|
115
112
|
WHERE t.relname = $1
|
|
116
|
-
AND n.nspname =
|
|
113
|
+
AND n.nspname = ${this.schemaExpr}
|
|
117
114
|
AND NOT ix.indisprimary
|
|
118
115
|
AND NOT EXISTS (
|
|
119
116
|
SELECT 1 FROM pg_constraint con
|
|
@@ -132,30 +129,29 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
132
129
|
* compare. This one decides which indexes are reported at all.
|
|
133
130
|
*/
|
|
134
131
|
constraintIndexTypes = ['p', 'u', 'x'];
|
|
132
|
+
/** From `pg_constraint`, whose key arrays keep each column paired with the one it references. */
|
|
135
133
|
getForeignKeysQuery(_tableName) {
|
|
134
|
+
const columnsOf = (keys, table) => /*sql*/ `ARRAY_TO_JSON(ARRAY(
|
|
135
|
+
SELECT a.attname FROM UNNEST(${keys}) WITH ORDINALITY AS k(attnum, n)
|
|
136
|
+
JOIN pg_attribute a ON a.attrelid = ${table} AND a.attnum = k.attnum
|
|
137
|
+
ORDER BY k.n
|
|
138
|
+
))`;
|
|
136
139
|
return /*sql*/ `
|
|
137
140
|
SELECT
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
FROM
|
|
145
|
-
JOIN
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
AND
|
|
151
|
-
|
|
152
|
-
ON rc.constraint_name = tc.constraint_name
|
|
153
|
-
AND rc.constraint_schema = tc.table_schema
|
|
154
|
-
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
155
|
-
AND tc.table_name = $1
|
|
156
|
-
AND tc.table_schema = ${this.schemaExpr}
|
|
157
|
-
GROUP BY tc.constraint_name, ccu.table_name, rc.delete_rule, rc.update_rule
|
|
158
|
-
ORDER BY tc.constraint_name
|
|
141
|
+
con.conname AS constraint_name,
|
|
142
|
+
${columnsOf('con.conkey', 'con.conrelid')} AS columns,
|
|
143
|
+
ref.relname AS referenced_table,
|
|
144
|
+
${columnsOf('con.confkey', 'con.confrelid')} AS referenced_columns,
|
|
145
|
+
con.confdeltype AS delete_rule,
|
|
146
|
+
con.confupdtype AS update_rule
|
|
147
|
+
FROM pg_constraint con
|
|
148
|
+
JOIN pg_class t ON t.oid = con.conrelid
|
|
149
|
+
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
150
|
+
JOIN pg_class ref ON ref.oid = con.confrelid
|
|
151
|
+
WHERE con.contype = 'f'
|
|
152
|
+
AND t.relname = $1
|
|
153
|
+
AND n.nspname = ${this.schemaExpr}
|
|
154
|
+
ORDER BY con.conname
|
|
159
155
|
`;
|
|
160
156
|
}
|
|
161
157
|
getPrimaryKeyQuery(_tableName) {
|
|
@@ -205,8 +201,8 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
205
201
|
name: row.constraint_name,
|
|
206
202
|
columns: row.columns,
|
|
207
203
|
references: { table: row.referenced_table, columns: row.referenced_columns },
|
|
208
|
-
onDelete:
|
|
209
|
-
onUpdate:
|
|
204
|
+
onDelete: FOREIGN_KEY_ACTION_CODES[row.delete_rule],
|
|
205
|
+
onUpdate: FOREIGN_KEY_ACTION_CODES[row.update_rule],
|
|
210
206
|
}));
|
|
211
207
|
}
|
|
212
208
|
normalizeType(dataType, udtName) {
|
|
@@ -219,29 +215,32 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
219
215
|
}
|
|
220
216
|
return dataType.toUpperCase();
|
|
221
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Postgres quotes a negative number (`'-3'::integer`); CockroachDB parenthesizes one (`(-3)`) and
|
|
220
|
+
* writes a quote-bearing string in escape syntax (`e'it\'s'`). Any other cast is dropped, and a
|
|
221
|
+
* function call (`now()`, `nextval(...)`) is returned as written.
|
|
222
|
+
*/
|
|
222
223
|
parseDefaultValue(defaultValue) {
|
|
223
224
|
if (!defaultValue) {
|
|
224
225
|
return undefined;
|
|
225
226
|
}
|
|
226
|
-
// Remove type casting (e.g., ::text, ::character varying, ::text[])
|
|
227
227
|
const cleaned = defaultValue.replace(/::[a-z_]+(\s+[a-z_]+)?(\[\])?/gi, '').trim();
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
const number = NUMBER_DEFAULT.exec(cleaned) ?? QUOTED_NUMBER_DEFAULT.exec(defaultValue);
|
|
229
|
+
if (number) {
|
|
230
|
+
return Number(number[1]);
|
|
230
231
|
}
|
|
231
|
-
|
|
232
|
-
|
|
232
|
+
const quoted = /^'(.*)'$/s.exec(cleaned);
|
|
233
|
+
if (quoted) {
|
|
234
|
+
return quoted[1].replaceAll("''", "'");
|
|
233
235
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
const escaped = /^e'(.*)'$/s.exec(cleaned);
|
|
237
|
+
if (escaped) {
|
|
238
|
+
return escaped[1].replace(/\\(.)/gs, '$1');
|
|
236
239
|
}
|
|
237
|
-
if (
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
if (/^-?\d+\.\d+$/.test(cleaned)) {
|
|
241
|
-
return Number.parseFloat(cleaned);
|
|
240
|
+
if (cleaned === 'true' || cleaned === 'false') {
|
|
241
|
+
return cleaned === 'true';
|
|
242
242
|
}
|
|
243
|
-
|
|
244
|
-
return cleaned;
|
|
243
|
+
return cleaned === 'NULL' ? null : cleaned;
|
|
245
244
|
}
|
|
246
245
|
isAutoIncrement(columnDefault, isIdentity) {
|
|
247
246
|
// PostgreSQL identity columns (GENERATED ... AS IDENTITY)
|
|
@@ -252,6 +251,16 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
252
251
|
return columnDefault?.includes('nextval(') ?? false;
|
|
253
252
|
}
|
|
254
253
|
}
|
|
254
|
+
/** `pg_constraint`'s one-letter spelling of each action. */
|
|
255
|
+
const FOREIGN_KEY_ACTION_CODES = {
|
|
256
|
+
a: 'NO ACTION',
|
|
257
|
+
r: 'RESTRICT',
|
|
258
|
+
c: 'CASCADE',
|
|
259
|
+
n: 'SET NULL',
|
|
260
|
+
d: 'SET DEFAULT',
|
|
261
|
+
};
|
|
262
|
+
const NUMBER_DEFAULT = /^\(?(-?\d+(?:\.\d+)?)\)?$/;
|
|
263
|
+
const QUOTED_NUMBER_DEFAULT = /^'(-?\d+(?:\.\d+)?)'::(?:smallint|integer|bigint|numeric|real|double precision)$/;
|
|
255
264
|
/**
|
|
256
265
|
* Postgres states every entry in full: a plain column still reports `order: 'asc'`, and only a
|
|
257
266
|
* non-default operator class is named. The diff defaults the entity side to match, so an option
|
|
@@ -6,7 +6,7 @@ import { AbstractSqlSchemaIntrospector, type TableRowReader } from './abstractSq
|
|
|
6
6
|
export declare class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
7
7
|
protected getTableNamesQuery(): string;
|
|
8
8
|
protected tableExistsQuery(): string;
|
|
9
|
-
protected parseTableExistsResult(
|
|
9
|
+
protected parseTableExistsResult([row]: SqliteCountRow[]): boolean;
|
|
10
10
|
/**
|
|
11
11
|
* `table_xinfo`, not `table_info`: the latter omits generated columns entirely, so a table carrying
|
|
12
12
|
* one read back without it and every sync offered to add a column that was already there - which
|
|
@@ -21,9 +21,8 @@ export class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
21
21
|
AND name = ?
|
|
22
22
|
`;
|
|
23
23
|
}
|
|
24
|
-
parseTableExistsResult(
|
|
25
|
-
|
|
26
|
-
return Number(results[0]?.count) > 0;
|
|
24
|
+
parseTableExistsResult([row]) {
|
|
25
|
+
return Number(row.count) > 0;
|
|
27
26
|
}
|
|
28
27
|
/**
|
|
29
28
|
* `table_xinfo`, not `table_info`: the latter omits generated columns entirely, so a table carrying
|
|
@@ -59,15 +58,16 @@ export class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
59
58
|
return row.name;
|
|
60
59
|
}
|
|
61
60
|
async mapColumnsResult(read, tableName, results) {
|
|
62
|
-
// Get unique columns from indexes
|
|
63
61
|
const uniqueColumns = await this.getUniqueColumns(read, tableName);
|
|
62
|
+
// Only a sole `INTEGER PRIMARY KEY` is the rowid, which is what numbers itself.
|
|
63
|
+
const soleKey = results.filter((row) => row.pk > 0).length === 1;
|
|
64
64
|
return results.map((row) => ({
|
|
65
65
|
name: row.name,
|
|
66
66
|
type: this.normalizeType(row.type),
|
|
67
67
|
nullable: row.notnull === 0,
|
|
68
68
|
defaultValue: this.parseDefaultValue(row.dflt_value),
|
|
69
69
|
isPrimaryKey: row.pk > 0,
|
|
70
|
-
isAutoIncrement: row.pk > 0 && row.type.toUpperCase() === 'INTEGER',
|
|
70
|
+
isAutoIncrement: soleKey && row.pk > 0 && row.type.toUpperCase() === 'INTEGER',
|
|
71
71
|
isUnique: uniqueColumns.has(row.name),
|
|
72
72
|
length: this.extractLength(row.type),
|
|
73
73
|
precision: undefined,
|
|
@@ -130,8 +130,9 @@ export class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
130
130
|
async getUniqueColumns(read, tableName) {
|
|
131
131
|
const indexes = await read(this.getIndexesQuery(tableName));
|
|
132
132
|
const uniqueColumns = new Set();
|
|
133
|
+
// The key's own index is left out: a key column is unique already, which the entity side never states.
|
|
133
134
|
for (const index of indexes) {
|
|
134
|
-
if (index.unique) {
|
|
135
|
+
if (index.unique && index.origin !== 'pk') {
|
|
135
136
|
const columns = await this.getIndexColumns(read, index.name);
|
|
136
137
|
// Only single-column unique constraints, and only over a real column (not an expression)
|
|
137
138
|
const [column] = columns;
|
|
@@ -165,14 +166,11 @@ export class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
165
166
|
return defaultValue;
|
|
166
167
|
}
|
|
167
168
|
if (/^'.*'$/.test(defaultValue)) {
|
|
168
|
-
return defaultValue.slice(1, -1);
|
|
169
|
+
return defaultValue.slice(1, -1).replaceAll("''", "'");
|
|
169
170
|
}
|
|
170
171
|
if (/^-?\d+$/.test(defaultValue)) {
|
|
171
172
|
return Number.parseInt(defaultValue, 10);
|
|
172
173
|
}
|
|
173
|
-
if (typeof defaultValue !== 'string') {
|
|
174
|
-
return defaultValue;
|
|
175
|
-
}
|
|
176
174
|
if (/^-?\d+\.\d+$/.test(defaultValue)) {
|
|
177
175
|
return Number.parseFloat(defaultValue);
|
|
178
176
|
}
|