@uql/core 3.1.0 → 3.1.2
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/CHANGELOG.md +134 -176
- package/README.md +413 -0
- package/package.json +31 -26
- package/dist/package.json +0 -131
- package/src/@types/index.d.ts +0 -1
- package/src/@types/jest.d.ts +0 -6
- package/src/browser/http/bus.spec.ts +0 -22
- package/src/browser/http/bus.ts +0 -17
- package/src/browser/http/http.spec.ts +0 -70
- package/src/browser/http/http.ts +0 -55
- package/src/browser/http/index.ts +0 -2
- package/src/browser/index.ts +0 -4
- package/src/browser/options.spec.ts +0 -37
- package/src/browser/options.ts +0 -18
- package/src/browser/querier/genericClientRepository.spec.ts +0 -105
- package/src/browser/querier/genericClientRepository.ts +0 -49
- package/src/browser/querier/httpQuerier.ts +0 -82
- package/src/browser/querier/index.ts +0 -3
- package/src/browser/querier/querier.util.spec.ts +0 -35
- package/src/browser/querier/querier.util.ts +0 -18
- package/src/browser/type/clientQuerier.ts +0 -45
- package/src/browser/type/clientQuerierPool.ts +0 -5
- package/src/browser/type/clientRepository.ts +0 -22
- package/src/browser/type/index.ts +0 -4
- package/src/browser/type/request.ts +0 -25
- package/src/dialect/abstractDialect.ts +0 -28
- package/src/dialect/abstractSqlDialect-spec.ts +0 -1309
- package/src/dialect/abstractSqlDialect.ts +0 -805
- package/src/dialect/index.ts +0 -3
- package/src/dialect/namingStrategy.spec.ts +0 -52
- package/src/dialect/queryContext.ts +0 -69
- package/src/entity/decorator/definition.spec.ts +0 -736
- package/src/entity/decorator/definition.ts +0 -265
- package/src/entity/decorator/entity.ts +0 -8
- package/src/entity/decorator/field.ts +0 -9
- package/src/entity/decorator/id.ts +0 -9
- package/src/entity/decorator/index.ts +0 -5
- package/src/entity/decorator/relation.spec.ts +0 -41
- package/src/entity/decorator/relation.ts +0 -34
- package/src/entity/index.ts +0 -1
- package/src/express/@types/express.d.ts +0 -8
- package/src/express/@types/index.d.ts +0 -1
- package/src/express/index.ts +0 -2
- package/src/express/querierMiddleware.ts +0 -217
- package/src/express/query.util.spec.ts +0 -40
- package/src/express/query.util.ts +0 -21
- package/src/index.ts +0 -9
- package/src/maria/index.ts +0 -3
- package/src/maria/mariaDialect.spec.ts +0 -207
- package/src/maria/mariaDialect.ts +0 -42
- package/src/maria/mariaQuerierPool.test.ts +0 -23
- package/src/maria/mariadbQuerier.test.ts +0 -23
- package/src/maria/mariadbQuerier.ts +0 -45
- package/src/maria/mariadbQuerierPool.ts +0 -21
- package/src/migrate/cli.ts +0 -301
- package/src/migrate/generator/index.ts +0 -4
- package/src/migrate/generator/mongoSchemaGenerator.spec.ts +0 -112
- package/src/migrate/generator/mongoSchemaGenerator.ts +0 -115
- package/src/migrate/generator/mysqlSchemaGenerator.spec.ts +0 -34
- package/src/migrate/generator/mysqlSchemaGenerator.ts +0 -92
- package/src/migrate/generator/postgresSchemaGenerator.spec.ts +0 -44
- package/src/migrate/generator/postgresSchemaGenerator.ts +0 -127
- package/src/migrate/generator/sqliteSchemaGenerator.spec.ts +0 -33
- package/src/migrate/generator/sqliteSchemaGenerator.ts +0 -81
- package/src/migrate/index.ts +0 -41
- package/src/migrate/introspection/index.ts +0 -4
- package/src/migrate/introspection/mongoIntrospector.spec.ts +0 -75
- package/src/migrate/introspection/mongoIntrospector.ts +0 -47
- package/src/migrate/introspection/mysqlIntrospector.spec.ts +0 -113
- package/src/migrate/introspection/mysqlIntrospector.ts +0 -278
- package/src/migrate/introspection/postgresIntrospector.spec.ts +0 -112
- package/src/migrate/introspection/postgresIntrospector.ts +0 -329
- package/src/migrate/introspection/sqliteIntrospector.spec.ts +0 -112
- package/src/migrate/introspection/sqliteIntrospector.ts +0 -296
- package/src/migrate/migrator-mongo.test.ts +0 -54
- package/src/migrate/migrator.spec.ts +0 -255
- package/src/migrate/migrator.test.ts +0 -94
- package/src/migrate/migrator.ts +0 -719
- package/src/migrate/namingStrategy.spec.ts +0 -22
- package/src/migrate/schemaGenerator-advanced.spec.ts +0 -138
- package/src/migrate/schemaGenerator.spec.ts +0 -190
- package/src/migrate/schemaGenerator.ts +0 -478
- package/src/migrate/storage/databaseStorage.spec.ts +0 -69
- package/src/migrate/storage/databaseStorage.ts +0 -100
- package/src/migrate/storage/index.ts +0 -2
- package/src/migrate/storage/jsonStorage.ts +0 -58
- package/src/migrate/type.ts +0 -1
- package/src/mongo/index.ts +0 -3
- package/src/mongo/mongoDialect.spec.ts +0 -251
- package/src/mongo/mongoDialect.ts +0 -238
- package/src/mongo/mongodbQuerier.test.ts +0 -45
- package/src/mongo/mongodbQuerier.ts +0 -256
- package/src/mongo/mongodbQuerierPool.test.ts +0 -25
- package/src/mongo/mongodbQuerierPool.ts +0 -24
- package/src/mysql/index.ts +0 -3
- package/src/mysql/mysql2Querier.test.ts +0 -20
- package/src/mysql/mysql2Querier.ts +0 -49
- package/src/mysql/mysql2QuerierPool.test.ts +0 -20
- package/src/mysql/mysql2QuerierPool.ts +0 -21
- package/src/mysql/mysqlDialect.spec.ts +0 -20
- package/src/mysql/mysqlDialect.ts +0 -16
- package/src/namingStrategy/defaultNamingStrategy.ts +0 -18
- package/src/namingStrategy/index.spec.ts +0 -36
- package/src/namingStrategy/index.ts +0 -2
- package/src/namingStrategy/snakeCaseNamingStrategy.ts +0 -15
- package/src/options.spec.ts +0 -41
- package/src/options.ts +0 -18
- package/src/postgres/index.ts +0 -3
- package/src/postgres/manual-types.d.ts +0 -4
- package/src/postgres/pgQuerier.test.ts +0 -25
- package/src/postgres/pgQuerier.ts +0 -45
- package/src/postgres/pgQuerierPool.test.ts +0 -28
- package/src/postgres/pgQuerierPool.ts +0 -21
- package/src/postgres/postgresDialect.spec.ts +0 -428
- package/src/postgres/postgresDialect.ts +0 -144
- package/src/querier/abstractQuerier-test.ts +0 -584
- package/src/querier/abstractQuerier.ts +0 -353
- package/src/querier/abstractQuerierPool-test.ts +0 -20
- package/src/querier/abstractQuerierPool.ts +0 -18
- package/src/querier/abstractSqlQuerier-spec.ts +0 -979
- package/src/querier/abstractSqlQuerier-test.ts +0 -21
- package/src/querier/abstractSqlQuerier.ts +0 -138
- package/src/querier/decorator/index.ts +0 -3
- package/src/querier/decorator/injectQuerier.spec.ts +0 -74
- package/src/querier/decorator/injectQuerier.ts +0 -45
- package/src/querier/decorator/serialized.spec.ts +0 -98
- package/src/querier/decorator/serialized.ts +0 -13
- package/src/querier/decorator/transactional.spec.ts +0 -240
- package/src/querier/decorator/transactional.ts +0 -56
- package/src/querier/index.ts +0 -4
- package/src/repository/genericRepository.spec.ts +0 -111
- package/src/repository/genericRepository.ts +0 -74
- package/src/repository/index.ts +0 -1
- package/src/sqlite/index.ts +0 -3
- package/src/sqlite/manual-types.d.ts +0 -4
- package/src/sqlite/sqliteDialect.spec.ts +0 -155
- package/src/sqlite/sqliteDialect.ts +0 -76
- package/src/sqlite/sqliteQuerier.spec.ts +0 -36
- package/src/sqlite/sqliteQuerier.test.ts +0 -21
- package/src/sqlite/sqliteQuerier.ts +0 -37
- package/src/sqlite/sqliteQuerierPool.test.ts +0 -12
- package/src/sqlite/sqliteQuerierPool.ts +0 -38
- package/src/test/entityMock.ts +0 -375
- package/src/test/index.ts +0 -3
- package/src/test/it.util.ts +0 -69
- package/src/test/spec.util.ts +0 -57
- package/src/type/entity.ts +0 -218
- package/src/type/index.ts +0 -9
- package/src/type/migration.ts +0 -241
- package/src/type/namingStrategy.ts +0 -17
- package/src/type/querier.ts +0 -143
- package/src/type/querierPool.ts +0 -26
- package/src/type/query.ts +0 -506
- package/src/type/repository.ts +0 -142
- package/src/type/universalQuerier.ts +0 -133
- package/src/type/utility.ts +0 -21
- package/src/util/dialect.util-extra.spec.ts +0 -96
- package/src/util/dialect.util.spec.ts +0 -23
- package/src/util/dialect.util.ts +0 -134
- package/src/util/index.ts +0 -5
- package/src/util/object.util.spec.ts +0 -29
- package/src/util/object.util.ts +0 -27
- package/src/util/raw.ts +0 -11
- package/src/util/sql.util-extra.spec.ts +0 -17
- package/src/util/sql.util.spec.ts +0 -208
- package/src/util/sql.util.ts +0 -104
- package/src/util/string.util.spec.ts +0 -46
- package/src/util/string.util.ts +0 -35
- package/tsconfig.build.json +0 -5
- package/tsconfig.json +0 -8
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ColumnSchema,
|
|
3
|
-
ForeignKeySchema,
|
|
4
|
-
IndexSchema,
|
|
5
|
-
QuerierPool,
|
|
6
|
-
SchemaIntrospector,
|
|
7
|
-
SqlQuerier,
|
|
8
|
-
TableSchema,
|
|
9
|
-
} from '../../type/index.js';
|
|
10
|
-
import { isSqlQuerier } from '../../type/index.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* PostgreSQL schema introspector
|
|
14
|
-
*/
|
|
15
|
-
export class PostgresSchemaIntrospector implements SchemaIntrospector {
|
|
16
|
-
constructor(private readonly querierPool: QuerierPool) {}
|
|
17
|
-
|
|
18
|
-
async getTableSchema(tableName: string): Promise<TableSchema | undefined> {
|
|
19
|
-
const querier = await this.getQuerier();
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const exists = await this.tableExistsInternal(querier, tableName);
|
|
23
|
-
if (!exists) {
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const [columns, indexes, foreignKeys, primaryKey] = await Promise.all([
|
|
28
|
-
this.getColumns(querier, tableName),
|
|
29
|
-
this.getIndexes(querier, tableName),
|
|
30
|
-
this.getForeignKeys(querier, tableName),
|
|
31
|
-
this.getPrimaryKey(querier, tableName),
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
name: tableName,
|
|
36
|
-
columns,
|
|
37
|
-
primaryKey,
|
|
38
|
-
indexes,
|
|
39
|
-
foreignKeys,
|
|
40
|
-
};
|
|
41
|
-
} finally {
|
|
42
|
-
await querier.release();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async getTableNames(): Promise<string[]> {
|
|
47
|
-
const querier = await this.getQuerier();
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
const sql = `
|
|
51
|
-
SELECT table_name
|
|
52
|
-
FROM information_schema.tables
|
|
53
|
-
WHERE table_schema = 'public'
|
|
54
|
-
AND table_type = 'BASE TABLE'
|
|
55
|
-
ORDER BY table_name
|
|
56
|
-
`;
|
|
57
|
-
|
|
58
|
-
const results = await querier.all<{ table_name: string }>(sql);
|
|
59
|
-
return results.map((r: any) => r.table_name);
|
|
60
|
-
} finally {
|
|
61
|
-
await querier.release();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async tableExists(tableName: string): Promise<boolean> {
|
|
66
|
-
const querier = await this.getQuerier();
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
return this.tableExistsInternal(querier, tableName);
|
|
70
|
-
} finally {
|
|
71
|
-
await querier.release();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
private async tableExistsInternal(querier: SqlQuerier, tableName: string): Promise<boolean> {
|
|
76
|
-
const sql = `
|
|
77
|
-
SELECT EXISTS (
|
|
78
|
-
SELECT FROM information_schema.tables
|
|
79
|
-
WHERE table_schema = 'public'
|
|
80
|
-
AND table_name = $1
|
|
81
|
-
) AS exists
|
|
82
|
-
`;
|
|
83
|
-
|
|
84
|
-
const results = await querier.all<{ exists: boolean }>(sql, [tableName]);
|
|
85
|
-
return results[0]?.exists ?? false;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private async getQuerier(): Promise<SqlQuerier> {
|
|
89
|
-
const querier = await this.querierPool.getQuerier();
|
|
90
|
-
|
|
91
|
-
if (!isSqlQuerier(querier)) {
|
|
92
|
-
await querier.release();
|
|
93
|
-
throw new Error('PostgresSchemaIntrospector requires a SQL-based querier');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return querier;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private async getColumns(querier: SqlQuerier, tableName: string): Promise<ColumnSchema[]> {
|
|
100
|
-
const sql = /*sql*/ `
|
|
101
|
-
SELECT
|
|
102
|
-
c.column_name,
|
|
103
|
-
c.data_type,
|
|
104
|
-
c.udt_name,
|
|
105
|
-
c.is_nullable,
|
|
106
|
-
c.column_default,
|
|
107
|
-
c.character_maximum_length,
|
|
108
|
-
c.numeric_precision,
|
|
109
|
-
c.numeric_scale,
|
|
110
|
-
COALESCE(
|
|
111
|
-
(SELECT TRUE FROM information_schema.table_constraints tc
|
|
112
|
-
JOIN information_schema.key_column_usage kcu
|
|
113
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
114
|
-
WHERE tc.table_name = c.table_name
|
|
115
|
-
AND tc.constraint_type = 'PRIMARY KEY'
|
|
116
|
-
AND kcu.column_name = c.column_name
|
|
117
|
-
LIMIT 1),
|
|
118
|
-
FALSE
|
|
119
|
-
) AS is_primary_key,
|
|
120
|
-
COALESCE(
|
|
121
|
-
(SELECT TRUE FROM information_schema.table_constraints tc
|
|
122
|
-
JOIN information_schema.key_column_usage kcu
|
|
123
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
124
|
-
WHERE tc.table_name = c.table_name
|
|
125
|
-
AND tc.constraint_type = 'UNIQUE'
|
|
126
|
-
AND kcu.column_name = c.column_name
|
|
127
|
-
LIMIT 1),
|
|
128
|
-
FALSE
|
|
129
|
-
) AS is_unique,
|
|
130
|
-
pg_catalog.col_description(
|
|
131
|
-
(SELECT oid FROM pg_catalog.pg_class WHERE relname = c.table_name),
|
|
132
|
-
c.ordinal_position
|
|
133
|
-
) AS column_comment
|
|
134
|
-
FROM information_schema.columns c
|
|
135
|
-
WHERE c.table_schema = 'public'
|
|
136
|
-
AND c.table_name = $1
|
|
137
|
-
ORDER BY c.ordinal_position
|
|
138
|
-
`;
|
|
139
|
-
|
|
140
|
-
const results = await querier.all<{
|
|
141
|
-
column_name: string;
|
|
142
|
-
data_type: string;
|
|
143
|
-
udt_name: string;
|
|
144
|
-
is_nullable: string;
|
|
145
|
-
column_default: string | null;
|
|
146
|
-
character_maximum_length: number | null;
|
|
147
|
-
numeric_precision: number | null;
|
|
148
|
-
numeric_scale: number | null;
|
|
149
|
-
is_primary_key: boolean;
|
|
150
|
-
is_unique: boolean;
|
|
151
|
-
column_comment: string | null;
|
|
152
|
-
}>(sql, [tableName]);
|
|
153
|
-
|
|
154
|
-
return results.map((row: any) => ({
|
|
155
|
-
name: row.column_name,
|
|
156
|
-
type: this.normalizeType(row.data_type, row.udt_name),
|
|
157
|
-
nullable: row.is_nullable === 'YES',
|
|
158
|
-
defaultValue: this.parseDefaultValue(row.column_default),
|
|
159
|
-
isPrimaryKey: row.is_primary_key,
|
|
160
|
-
isAutoIncrement: this.isAutoIncrement(row.column_default),
|
|
161
|
-
isUnique: row.is_unique,
|
|
162
|
-
length: row.character_maximum_length ?? undefined,
|
|
163
|
-
precision: row.numeric_precision ?? undefined,
|
|
164
|
-
scale: row.numeric_scale ?? undefined,
|
|
165
|
-
comment: row.column_comment ?? undefined,
|
|
166
|
-
}));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private async getIndexes(querier: SqlQuerier, tableName: string): Promise<IndexSchema[]> {
|
|
170
|
-
const sql = /*sql*/ `
|
|
171
|
-
SELECT
|
|
172
|
-
i.relname AS index_name,
|
|
173
|
-
array_agg(a.attname ORDER BY k.n) AS columns,
|
|
174
|
-
ix.indisunique AS is_unique
|
|
175
|
-
FROM pg_class t
|
|
176
|
-
JOIN pg_index ix ON t.oid = ix.indrelid
|
|
177
|
-
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
178
|
-
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
179
|
-
CROSS JOIN LATERAL unnest(ix.indkey) WITH ORDINALITY AS k(attnum, n)
|
|
180
|
-
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum
|
|
181
|
-
WHERE t.relname = $1
|
|
182
|
-
AND n.nspname = 'public'
|
|
183
|
-
AND NOT ix.indisprimary
|
|
184
|
-
GROUP BY i.relname, ix.indisunique
|
|
185
|
-
ORDER BY i.relname
|
|
186
|
-
`;
|
|
187
|
-
|
|
188
|
-
const results = await querier.all<{
|
|
189
|
-
index_name: string;
|
|
190
|
-
columns: string[];
|
|
191
|
-
is_unique: boolean;
|
|
192
|
-
}>(sql, [tableName]);
|
|
193
|
-
|
|
194
|
-
return results.map((row: any) => ({
|
|
195
|
-
name: row.index_name,
|
|
196
|
-
columns: row.columns,
|
|
197
|
-
unique: row.is_unique,
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
private async getForeignKeys(querier: SqlQuerier, tableName: string): Promise<ForeignKeySchema[]> {
|
|
202
|
-
const sql = /*sql*/ `
|
|
203
|
-
SELECT
|
|
204
|
-
tc.constraint_name,
|
|
205
|
-
array_agg(kcu.column_name ORDER BY kcu.ordinal_position) AS columns,
|
|
206
|
-
ccu.table_name AS referenced_table,
|
|
207
|
-
array_agg(ccu.column_name ORDER BY kcu.ordinal_position) AS referenced_columns,
|
|
208
|
-
rc.delete_rule,
|
|
209
|
-
rc.update_rule
|
|
210
|
-
FROM information_schema.table_constraints tc
|
|
211
|
-
JOIN information_schema.key_column_usage kcu
|
|
212
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
213
|
-
AND tc.table_schema = kcu.table_schema
|
|
214
|
-
JOIN information_schema.constraint_column_usage ccu
|
|
215
|
-
ON ccu.constraint_name = tc.constraint_name
|
|
216
|
-
AND ccu.table_schema = tc.table_schema
|
|
217
|
-
JOIN information_schema.referential_constraints rc
|
|
218
|
-
ON rc.constraint_name = tc.constraint_name
|
|
219
|
-
AND rc.constraint_schema = tc.table_schema
|
|
220
|
-
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
221
|
-
AND tc.table_name = $1
|
|
222
|
-
AND tc.table_schema = 'public'
|
|
223
|
-
GROUP BY tc.constraint_name, ccu.table_name, rc.delete_rule, rc.update_rule
|
|
224
|
-
ORDER BY tc.constraint_name
|
|
225
|
-
`;
|
|
226
|
-
|
|
227
|
-
const results = await querier.all<{
|
|
228
|
-
constraint_name: string;
|
|
229
|
-
columns: string[];
|
|
230
|
-
referenced_table: string;
|
|
231
|
-
referenced_columns: string[];
|
|
232
|
-
delete_rule: string;
|
|
233
|
-
update_rule: string;
|
|
234
|
-
}>(sql, [tableName]);
|
|
235
|
-
|
|
236
|
-
return results.map((row: any) => ({
|
|
237
|
-
name: row.constraint_name,
|
|
238
|
-
columns: row.columns,
|
|
239
|
-
referencedTable: row.referenced_table,
|
|
240
|
-
referencedColumns: row.referenced_columns,
|
|
241
|
-
onDelete: this.normalizeReferentialAction(row.delete_rule),
|
|
242
|
-
onUpdate: this.normalizeReferentialAction(row.update_rule),
|
|
243
|
-
}));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
private async getPrimaryKey(querier: SqlQuerier, tableName: string): Promise<string[] | undefined> {
|
|
247
|
-
const sql = /*sql*/ `
|
|
248
|
-
SELECT kcu.column_name
|
|
249
|
-
FROM information_schema.table_constraints tc
|
|
250
|
-
JOIN information_schema.key_column_usage kcu
|
|
251
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
252
|
-
AND tc.table_schema = kcu.table_schema
|
|
253
|
-
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
254
|
-
AND tc.table_name = $1
|
|
255
|
-
AND tc.table_schema = 'public'
|
|
256
|
-
ORDER BY kcu.ordinal_position
|
|
257
|
-
`;
|
|
258
|
-
|
|
259
|
-
const results = await querier.all<{ column_name: string }>(sql, [tableName]);
|
|
260
|
-
|
|
261
|
-
if (results.length === 0) {
|
|
262
|
-
return undefined;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return results.map((r: any) => r.column_name);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
private normalizeType(dataType: string, udtName: string): string {
|
|
269
|
-
// Handle user-defined types and arrays
|
|
270
|
-
if (dataType === 'USER-DEFINED') {
|
|
271
|
-
return udtName.toUpperCase();
|
|
272
|
-
}
|
|
273
|
-
if (dataType === 'ARRAY') {
|
|
274
|
-
return `${udtName.replace(/^_/, '')}[]`;
|
|
275
|
-
}
|
|
276
|
-
return dataType.toUpperCase();
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
private parseDefaultValue(defaultValue: string | null): unknown {
|
|
280
|
-
if (!defaultValue) {
|
|
281
|
-
return undefined;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Remove type casting
|
|
285
|
-
const cleaned = defaultValue.replace(/::[a-z_]+(\[\])?/gi, '').trim();
|
|
286
|
-
|
|
287
|
-
// Check for common patterns
|
|
288
|
-
if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
289
|
-
return cleaned.slice(1, -1);
|
|
290
|
-
}
|
|
291
|
-
if (cleaned === 'true' || cleaned === 'false') {
|
|
292
|
-
return cleaned === 'true';
|
|
293
|
-
}
|
|
294
|
-
if (cleaned === 'NULL') {
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
if (/^-?\d+$/.test(cleaned)) {
|
|
298
|
-
return Number.parseInt(cleaned, 10);
|
|
299
|
-
}
|
|
300
|
-
if (/^-?\d+\.\d+$/.test(cleaned)) {
|
|
301
|
-
return Number.parseFloat(cleaned);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Return as-is for functions like CURRENT_TIMESTAMP, nextval(), etc.
|
|
305
|
-
return defaultValue;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
private isAutoIncrement(defaultValue: string | null): boolean {
|
|
309
|
-
if (!defaultValue) {
|
|
310
|
-
return false;
|
|
311
|
-
}
|
|
312
|
-
return defaultValue.includes('nextval(');
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
private normalizeReferentialAction(action: string): 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION' | undefined {
|
|
316
|
-
switch (action.toUpperCase()) {
|
|
317
|
-
case 'CASCADE':
|
|
318
|
-
return 'CASCADE';
|
|
319
|
-
case 'SET NULL':
|
|
320
|
-
return 'SET NULL';
|
|
321
|
-
case 'RESTRICT':
|
|
322
|
-
return 'RESTRICT';
|
|
323
|
-
case 'NO ACTION':
|
|
324
|
-
return 'NO ACTION';
|
|
325
|
-
default:
|
|
326
|
-
return undefined;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, jest } from 'bun:test';
|
|
2
|
-
import type { QuerierPool, SqlQuerier } from '../../type/index.js';
|
|
3
|
-
import { SqliteSchemaIntrospector } from './sqliteIntrospector.js';
|
|
4
|
-
|
|
5
|
-
describe('SqliteSchemaIntrospector', () => {
|
|
6
|
-
let introspector: SqliteSchemaIntrospector;
|
|
7
|
-
let pool: QuerierPool;
|
|
8
|
-
let querier: SqlQuerier;
|
|
9
|
-
|
|
10
|
-
let mockAll: ReturnType<typeof jest.fn>;
|
|
11
|
-
let mockRun: ReturnType<typeof jest.fn>;
|
|
12
|
-
let mockRelease: ReturnType<typeof jest.fn>;
|
|
13
|
-
let mockGetQuerier: ReturnType<typeof jest.fn>;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
mockAll = jest.fn<any>().mockResolvedValue([]);
|
|
17
|
-
mockRun = jest.fn<any>().mockResolvedValue({});
|
|
18
|
-
mockRelease = jest.fn<any>().mockResolvedValue(undefined);
|
|
19
|
-
|
|
20
|
-
querier = {
|
|
21
|
-
all: mockAll,
|
|
22
|
-
run: mockRun,
|
|
23
|
-
release: mockRelease,
|
|
24
|
-
dialect: { escapeIdChar: '`' },
|
|
25
|
-
} as any;
|
|
26
|
-
|
|
27
|
-
mockGetQuerier = jest.fn<any>().mockResolvedValue(querier);
|
|
28
|
-
pool = {
|
|
29
|
-
getQuerier: mockGetQuerier,
|
|
30
|
-
} as any;
|
|
31
|
-
|
|
32
|
-
introspector = new SqliteSchemaIntrospector(pool);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('getTableNames should return a list of tables', async () => {
|
|
36
|
-
mockAll.mockResolvedValueOnce([{ name: 'users' }, { name: 'posts' }]);
|
|
37
|
-
|
|
38
|
-
const names = await introspector.getTableNames();
|
|
39
|
-
|
|
40
|
-
expect(names).toEqual(['users', 'posts']);
|
|
41
|
-
expect(querier.all).toHaveBeenCalledWith(expect.stringContaining('sqlite_master'));
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('getTableSchema should return table details', async () => {
|
|
45
|
-
mockAll.mockImplementation((async (sql: string, _values?: unknown[]) => {
|
|
46
|
-
const normalizedSql = sql.replace(/\s+/g, ' ').trim();
|
|
47
|
-
if (normalizedSql.includes('SELECT COUNT(*) as count FROM sqlite_master')) {
|
|
48
|
-
return [{ count: 1 }];
|
|
49
|
-
}
|
|
50
|
-
if (normalizedSql.includes('PRAGMA table_info')) {
|
|
51
|
-
return [
|
|
52
|
-
{ cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null as any, pk: 1 },
|
|
53
|
-
{ cid: 1, name: 'username', type: 'VARCHAR(255)', notnull: 0, dflt_value: null as any, pk: 0 },
|
|
54
|
-
];
|
|
55
|
-
}
|
|
56
|
-
if (normalizedSql.includes('PRAGMA index_list')) {
|
|
57
|
-
return [
|
|
58
|
-
{ seq: 0, name: 'sqlite_autoindex_users_1', unique: 1, origin: 'u', partial: 0 },
|
|
59
|
-
{ seq: 1, name: 'idx_users_username', unique: 0, origin: 'c', partial: 0 },
|
|
60
|
-
];
|
|
61
|
-
}
|
|
62
|
-
if (normalizedSql.includes('PRAGMA index_info')) {
|
|
63
|
-
return [{ name: 'username' }];
|
|
64
|
-
}
|
|
65
|
-
if (normalizedSql.includes('PRAGMA foreign_key_list')) {
|
|
66
|
-
return [
|
|
67
|
-
{
|
|
68
|
-
id: 0,
|
|
69
|
-
seq: 0,
|
|
70
|
-
table: 'users',
|
|
71
|
-
from: 'author_id',
|
|
72
|
-
to: 'id',
|
|
73
|
-
on_update: 'CASCADE',
|
|
74
|
-
on_delete: 'RESTRICT',
|
|
75
|
-
match: 'NONE',
|
|
76
|
-
},
|
|
77
|
-
];
|
|
78
|
-
}
|
|
79
|
-
return [];
|
|
80
|
-
}) as any);
|
|
81
|
-
|
|
82
|
-
const schema = await introspector.getTableSchema('users');
|
|
83
|
-
|
|
84
|
-
expect(schema).toBeDefined();
|
|
85
|
-
expect(schema?.name).toBe('users');
|
|
86
|
-
expect(schema?.columns).toHaveLength(2);
|
|
87
|
-
expect(schema?.columns[0]).toMatchObject({
|
|
88
|
-
name: 'id',
|
|
89
|
-
type: 'INTEGER',
|
|
90
|
-
nullable: false,
|
|
91
|
-
isAutoIncrement: true,
|
|
92
|
-
isPrimaryKey: true,
|
|
93
|
-
});
|
|
94
|
-
expect(schema?.columns[1]).toMatchObject({
|
|
95
|
-
name: 'username',
|
|
96
|
-
type: 'VARCHAR',
|
|
97
|
-
nullable: true,
|
|
98
|
-
isUnique: true,
|
|
99
|
-
length: 255,
|
|
100
|
-
});
|
|
101
|
-
expect(schema?.indexes).toHaveLength(1);
|
|
102
|
-
expect(schema?.indexes?.[0].name).toBe('idx_users_username');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('getTableSchema should return undefined for non-existent table', async () => {
|
|
106
|
-
mockAll.mockResolvedValueOnce([{ count: 0 }]);
|
|
107
|
-
|
|
108
|
-
const schema = await introspector.getTableSchema('non_existent');
|
|
109
|
-
|
|
110
|
-
expect(schema).toBeUndefined();
|
|
111
|
-
});
|
|
112
|
-
});
|