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,19 +1,14 @@
|
|
|
1
1
|
import { COUNT_ALIAS, TOTAL_ALIAS } from '../dialect/aliases.js';
|
|
2
2
|
import { decodeColumn } from '../dialect/hydrateColumn.js';
|
|
3
|
-
import { getMeta,
|
|
3
|
+
import { getMeta, namesKey } from '../entity/index.js';
|
|
4
4
|
import { COUNT_RESULT_KEY } from '../type/index.js';
|
|
5
|
-
import { buildUpdateResult,
|
|
5
|
+
import { buildUpdateResult, clone, getInsertFieldKeys, insertShapeOf, isAutoIncrement, isRecord, obtainAttrsPaths, throwNoPendingTransaction, throwPendingTransaction, unflatObject, unflatObjects, } from '../util/index.js';
|
|
6
6
|
import { AbstractQuerier } from './abstractQuerier.js';
|
|
7
7
|
import { streamViaCursor } from './cursorStream.js';
|
|
8
8
|
import { enrichError } from './queryError.js';
|
|
9
9
|
/**
|
|
10
|
-
* Row indexes
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Deliberately coarser than {@link groupByInsertShape}, and the two must not be merged: an insert's
|
|
14
|
-
* `VALUES` list takes the union of the batch's columns and fills the rest with `DEFAULT`, so the
|
|
15
|
-
* key's presence is the only thing that changes what the statement can report. Splitting an insert
|
|
16
|
-
* by full shape instead would turn a batch of optional fields into a statement per combination.
|
|
10
|
+
* Row indexes split by whether the row names its key, the one thing that changes what an insert can
|
|
11
|
+
* report; coarser than {@link groupByInsertShape} on purpose, since an insert fills a missing column with `DEFAULT`.
|
|
17
12
|
*/
|
|
18
13
|
function partitionBySuppliedId(payload, idKey) {
|
|
19
14
|
const supplied = [];
|
|
@@ -110,15 +105,21 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
110
105
|
return this.timed(query, values, () => this.internalRun(query, this.dialect.normalizeValues(values)));
|
|
111
106
|
});
|
|
112
107
|
}
|
|
108
|
+
/** The rows of a statement the dialect builds. */
|
|
109
|
+
query(build) {
|
|
110
|
+
const ctx = this.dialect.createContext();
|
|
111
|
+
build(ctx);
|
|
112
|
+
return this.all(ctx.sql, ctx.values);
|
|
113
|
+
}
|
|
114
|
+
/** Runs a statement the dialect builds. */
|
|
115
|
+
exec(build) {
|
|
116
|
+
const ctx = this.dialect.createContext();
|
|
117
|
+
build(ctx);
|
|
118
|
+
return this.run(ctx.sql, ctx.values);
|
|
119
|
+
}
|
|
113
120
|
/**
|
|
114
|
-
* `$lock`
|
|
115
|
-
*
|
|
116
|
-
* before the caller has seen a row: the SQL is correct, nothing is omitted, and no layer below
|
|
117
|
-
* this one can tell. The dialect cannot check it either, being stateless and shared by every
|
|
118
|
-
* connection of the pool, so this is the only place it can be caught.
|
|
119
|
-
*
|
|
120
|
-
* The capability check runs first on purpose: "this engine has no row locks" is the more
|
|
121
|
-
* actionable answer, and on SQLite it is the answer either way.
|
|
121
|
+
* Refuses a `$lock` the engine lacks, then one outside a transaction, where the lock would drop as the
|
|
122
|
+
* statement commits; only the querier knows whether one is open.
|
|
122
123
|
*/
|
|
123
124
|
assertLockable(entity, q) {
|
|
124
125
|
if (!q.$lock) {
|
|
@@ -130,14 +131,8 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* Same shape as {@link assertLockable} and for the same reason: a `SET LOCAL` outside a transaction
|
|
136
|
-
* is accepted, applies to nothing, and leaves the query running at the engine's default recall -
|
|
137
|
-
* correct SQL, silently untuned. Only the querier knows whether a transaction is open.
|
|
138
|
-
*
|
|
139
|
-
* The statements go through `internalRun`, sharing this querier's single connection with the query
|
|
140
|
-
* they precede; `SET LOCAL` then expires with the transaction, so nothing is left behind.
|
|
134
|
+
* Runs the `SET`s tuning an ANN index for the query on its connection, refusing where they would apply to
|
|
135
|
+
* nothing: a `SET LOCAL` outside a transaction.
|
|
141
136
|
*/
|
|
142
137
|
async applyVectorTuning(entity, q) {
|
|
143
138
|
// Resolved before the transaction check, so the refusal fires only where the tuning would have
|
|
@@ -147,7 +142,7 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
147
142
|
if (!statements.length) {
|
|
148
143
|
return;
|
|
149
144
|
}
|
|
150
|
-
if (this.dialect.vectorTuningNeedsTransaction && !this.hasOpenTransaction) {
|
|
145
|
+
if (this.dialect.features.vectorTuningNeedsTransaction && !this.hasOpenTransaction) {
|
|
151
146
|
throw new TypeError(`$candidates requires an open transaction on ${this.dialect.dialectName}; run the query inside pool.transaction(...)`);
|
|
152
147
|
}
|
|
153
148
|
for (const statement of statements) {
|
|
@@ -157,39 +152,23 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
157
152
|
async internalFindMany(entity, q, opts) {
|
|
158
153
|
return this.hydrateRows(entity, await this.selectRows(entity, q, opts));
|
|
159
154
|
}
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
*/
|
|
166
|
-
countedSeparately(entity, q, opts) {
|
|
167
|
-
if (q.$distinct) {
|
|
168
|
-
return (ctx) => this.dialect.countDistinct(ctx, entity, q, opts);
|
|
169
|
-
}
|
|
170
|
-
if (q.$lock && !this.dialect.supportsWindowWithRowLock) {
|
|
171
|
-
return (ctx) => this.dialect.count(ctx, entity, q, opts);
|
|
172
|
-
}
|
|
173
|
-
return undefined;
|
|
155
|
+
/** Every row `q` matches past its page, deduplicated where it reads `$distinct`. */
|
|
156
|
+
countUnpaged(entity, q, opts) {
|
|
157
|
+
return q.$distinct
|
|
158
|
+
? this.runCount((ctx) => this.dialect.countDistinct(ctx, entity, q, opts))
|
|
159
|
+
: this.internalCount(entity, { $where: q.$where }, opts);
|
|
174
160
|
}
|
|
175
161
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* A `$required` relation needs no special case: the window counts what the INNER JOIN left, which
|
|
181
|
-
* is exactly the total a caller of a filtered read is asking for. A `$lock` is the one clause an
|
|
182
|
-
* engine may refuse to have in the same statement, which {@link AbstractSqlDialect.supportsWindowWithRowLock}
|
|
183
|
-
* answers; where it does, the total comes from a count of its own. A `$distinct` read needs one
|
|
184
|
-
* too, and a deduplicating one: see {@link AbstractSqlDialect.countDistinct}.
|
|
162
|
+
* The page and its unpaged total in one statement, a window column on each row, and a count of its own for
|
|
163
|
+
* an empty page. A window counts before `DISTINCT`, and the Postgres family refuses one beside a `$lock`,
|
|
164
|
+
* so those count apart.
|
|
185
165
|
*/
|
|
186
166
|
async internalFindManyAndCount(entity, q, opts) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return Promise.all([this.internalFindMany(entity, q, opts), this.runCount(separately)]);
|
|
167
|
+
if (q.$distinct || (q.$lock && !this.dialect.features.rowLockWithWindow)) {
|
|
168
|
+
return Promise.all([this.internalFindMany(entity, q, opts), this.countUnpaged(entity, q, opts)]);
|
|
190
169
|
}
|
|
191
170
|
const rows = await this.selectRows(entity, q, opts, TOTAL_ALIAS);
|
|
192
|
-
const total = rows.length ? Number(rows[0][TOTAL_ALIAS]) : await this.
|
|
171
|
+
const total = rows.length ? Number(rows[0][TOTAL_ALIAS]) : await this.countUnpaged(entity, q, opts);
|
|
193
172
|
for (const row of rows) {
|
|
194
173
|
delete row[TOTAL_ALIAS];
|
|
195
174
|
}
|
|
@@ -203,9 +182,7 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
203
182
|
if (q.$candidates !== undefined) {
|
|
204
183
|
await this.applyVectorTuning(entity, q);
|
|
205
184
|
}
|
|
206
|
-
|
|
207
|
-
this.dialect.find(ctx, entity, q, opts, totalAlias);
|
|
208
|
-
return this.all(ctx.sql, ctx.values);
|
|
185
|
+
return this.query((ctx) => this.dialect.find(ctx, entity, q, opts, totalAlias));
|
|
209
186
|
}
|
|
210
187
|
hydrateRows(entity, rows) {
|
|
211
188
|
const founds = unflatObjects(rows);
|
|
@@ -219,8 +196,7 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
219
196
|
await this.applyVectorTuning(entity, q);
|
|
220
197
|
}
|
|
221
198
|
const meta = getMeta(entity);
|
|
222
|
-
// The one path
|
|
223
|
-
// a freshly acquired querier used to reach `getConn()` with nothing acquired.
|
|
199
|
+
// The one path not going through `all`/`run`, so it connects on its own.
|
|
224
200
|
await this.lazyConnect();
|
|
225
201
|
// No `normalizeValues` here, unlike `all`/`run`: those also take raw SQL, while every value a
|
|
226
202
|
// context holds was normalized as it was bound.
|
|
@@ -319,21 +295,17 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
319
295
|
* a catalog that does not know the table answers with no row, which is nothing counted.
|
|
320
296
|
*/
|
|
321
297
|
async runCount(build) {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
const res = await this.all(ctx.sql, ctx.values);
|
|
325
|
-
return Number(res[0]?.[COUNT_ALIAS] ?? 0);
|
|
298
|
+
const [row] = await this.query(build);
|
|
299
|
+
return Number(row?.[COUNT_ALIAS] ?? 0);
|
|
326
300
|
}
|
|
327
|
-
async internalCount(entity, q
|
|
301
|
+
async internalCount(entity, q, opts) {
|
|
328
302
|
return this.runCount((ctx) => this.dialect.count(ctx, entity, q, opts));
|
|
329
303
|
}
|
|
330
304
|
async estimatedCount(entity) {
|
|
331
305
|
return this.runCount((ctx) => this.dialect.estimatedCount(ctx, entity));
|
|
332
306
|
}
|
|
333
307
|
async internalAggregate(entity, q, opts) {
|
|
334
|
-
const
|
|
335
|
-
this.dialect.aggregate(ctx, entity, q, opts);
|
|
336
|
-
const rows = await this.all(ctx.sql, ctx.values);
|
|
308
|
+
const rows = await this.query((ctx) => this.dialect.aggregate(ctx, entity, q, opts));
|
|
337
309
|
const hydratable = this.dialect.hydratableAggregates(entity, q);
|
|
338
310
|
for (const row of rows) {
|
|
339
311
|
const cells = row;
|
|
@@ -354,12 +326,8 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
354
326
|
const idField = sole ? meta.fields[idKey] : undefined;
|
|
355
327
|
const generatedKey = !!idField && isAutoIncrement(idField, true);
|
|
356
328
|
for (const group of partitionBySuppliedId(rows, idKey)) {
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
// statement* left it to the database. That is a property of the statement, not of the batch:
|
|
360
|
-
// asking it of the whole batch meant one supplied id made every id `undefined`, which a
|
|
361
|
-
// cascade then wrote into a child as a null foreign key. Splitting on that one axis costs at
|
|
362
|
-
// most one extra statement and keeps each of them inferable.
|
|
329
|
+
// Header ids are only sound where every row of this statement left its key to the database, so
|
|
330
|
+
// the batch is split on that alone, and a supplied id cannot void the others.
|
|
363
331
|
const idsReliable = sole &&
|
|
364
332
|
(this.dialect.insertIdSource === 'returning' ||
|
|
365
333
|
(generatedKey && group.every((index) => rows[index][idKey] === undefined)));
|
|
@@ -371,9 +339,8 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
371
339
|
// Per group, not per batch: the two carry different columns - one names the key, one does not -
|
|
372
340
|
// so a budget taken over their union would under-fill the statement that is missing one.
|
|
373
341
|
for (const indexes of chunkByBindBudget(meta, rows, group, this.dialect.maxBindValues)) {
|
|
374
|
-
const
|
|
375
|
-
this.dialect.insert(ctx, entity,
|
|
376
|
-
const { ids = [] } = await this.run(ctx.sql, ctx.values);
|
|
342
|
+
const chunk = indexes.map((index) => rows[index]);
|
|
343
|
+
const { ids = [] } = await this.exec((ctx) => this.dialect.insert(ctx, entity, chunk));
|
|
377
344
|
if (idsReliable) {
|
|
378
345
|
for (let position = 0; position < indexes.length; position++) {
|
|
379
346
|
rows[indexes[position]][idKey] ??= ids[position];
|
|
@@ -384,31 +351,9 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
384
351
|
await this.insertRelations(entity, rows);
|
|
385
352
|
}
|
|
386
353
|
async internalUpdateMany(entity, q, payload, opts) {
|
|
387
|
-
|
|
388
|
-
// Settled first for the reason `internalDeleteMany` settles: `ORDER BY`/`LIMIT` on an UPDATE is
|
|
389
|
-
// MySQL's alone, so a paged update has to name the rows it picked.
|
|
390
|
-
let target = q;
|
|
391
|
-
if (isPagedQuery(q)) {
|
|
392
|
-
const ids = await this.settleIds(entity, q, opts);
|
|
393
|
-
if (!ids.length) {
|
|
394
|
-
return 0;
|
|
395
|
-
}
|
|
396
|
-
target = { $where: whereIds(getMeta(entity), ids) };
|
|
397
|
-
}
|
|
398
|
-
const ctx = this.dialect.createContext();
|
|
399
|
-
this.dialect.update(ctx, entity, target, payload, opts);
|
|
400
|
-
const { changes = 0 } = await this.run(ctx.sql, ctx.values);
|
|
401
|
-
await this.updateRelations(entity, target, payload, opts);
|
|
354
|
+
const { changes = 0 } = await this.exec((ctx) => this.dialect.update(ctx, entity, q, payload, opts));
|
|
402
355
|
return changes;
|
|
403
356
|
}
|
|
404
|
-
/** The ids matching `q`, in `q`'s own order and page, so a write can name the rows it settled on. */
|
|
405
|
-
async settleIds(entity, q, opts) {
|
|
406
|
-
const meta = getMeta(entity);
|
|
407
|
-
const ctx = this.dialect.createContext();
|
|
408
|
-
this.dialect.find(ctx, entity, idOnlyQuery(meta, q), opts);
|
|
409
|
-
const founds = await this.all(ctx.sql, ctx.values);
|
|
410
|
-
return founds.map((found) => idOf(meta, found));
|
|
411
|
-
}
|
|
412
357
|
async internalUpsertOne(entity, conflictPaths, payload) {
|
|
413
358
|
return this.internalUpsertMany(entity, conflictPaths, [payload]);
|
|
414
359
|
}
|
|
@@ -425,12 +370,8 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
425
370
|
if (statements.length === 1) {
|
|
426
371
|
return this.runUpsert(entity, conflictPaths, payload);
|
|
427
372
|
}
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
// union writes the omitting row's `DEFAULT` (null) over a column it never mentioned, and
|
|
431
|
-
// sampling one row drops every column that row happens to lack. One statement per shape is the
|
|
432
|
-
// only form that writes exactly what each row asked for. Transactional because it is now more
|
|
433
|
-
// than one statement; `transaction` is re-entrant, so this is free inside a caller's own.
|
|
373
|
+
// An upsert's assignment list is the statement's, so rows of different shapes go in statements
|
|
374
|
+
// of their own, together in a transaction (`transaction` is re-entrant).
|
|
434
375
|
return this.transaction(async () => {
|
|
435
376
|
let changes = 0;
|
|
436
377
|
// Placed by index, since grouping by shape reorders the rows. A statement reporting fewer ids
|
|
@@ -453,10 +394,9 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
453
394
|
const meta = getMeta(entity);
|
|
454
395
|
// Asked first: the statement fills an `onInsert` key into these rows whether it inserts them or not.
|
|
455
396
|
const unnamed = meta.ids.length === 1 && payload.some((row) => !namesKey(meta, row));
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const ordered = payload.length === 1 || (this.dialect.insertIdSource === 'returning' && this.dialect.upsertReturningOrdered);
|
|
397
|
+
const result = await this.exec((ctx) => this.dialect.upsert(ctx, entity, conflictPaths, payload));
|
|
398
|
+
const ordered = payload.length === 1 ||
|
|
399
|
+
(this.dialect.insertIdSource === 'returning' && this.dialect.features.orderedUpsertReturning);
|
|
460
400
|
if (ordered && result.ids?.length === payload.length) {
|
|
461
401
|
return result;
|
|
462
402
|
}
|
|
@@ -470,29 +410,7 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
470
410
|
: { changes, created };
|
|
471
411
|
}
|
|
472
412
|
async internalDeleteMany(entity, q, opts) {
|
|
473
|
-
const
|
|
474
|
-
// Resolving the ids first is what makes the two hard cases work at all: a cascade needs its
|
|
475
|
-
// parents' ids to find their children, and no engine but MySQL accepts `ORDER BY`/`LIMIT` on a
|
|
476
|
-
// DELETE, so a paged delete has to name the rows it settled on. A plain predicate needs neither,
|
|
477
|
-
// and there the round trip buys nothing: the statement can say what the caller already said.
|
|
478
|
-
if (!isPagedQuery(q) && !cascadesOnDelete(meta)) {
|
|
479
|
-
const ctx = this.dialect.createContext();
|
|
480
|
-
this.dialect.delete(ctx, entity, q, opts);
|
|
481
|
-
const { changes = 0 } = await this.run(ctx.sql, ctx.values);
|
|
482
|
-
return changes;
|
|
483
|
-
}
|
|
484
|
-
// A hard delete also targets already-soft-deleted rows, so drop the soft-delete filter when finding ids.
|
|
485
|
-
const findOpts = opts?.hardDelete ? { ...opts, filters: withoutSoftDeleteFilter(opts.filters) } : opts;
|
|
486
|
-
const ids = await this.settleIds(entity, q, findOpts);
|
|
487
|
-
if (!ids.length) {
|
|
488
|
-
return 0;
|
|
489
|
-
}
|
|
490
|
-
// Children first: they hold the foreign key, so deleting the parent ahead of them is rejected
|
|
491
|
-
// outright by any schema that declares the constraint without `ON DELETE CASCADE`.
|
|
492
|
-
await this.deleteRelations(entity, ids, opts);
|
|
493
|
-
const deleteCtx = this.dialect.createContext();
|
|
494
|
-
this.dialect.delete(deleteCtx, entity, { $where: whereIds(meta, ids) }, opts);
|
|
495
|
-
const { changes = 0 } = await this.run(deleteCtx.sql, deleteCtx.values);
|
|
413
|
+
const { changes = 0 } = await this.exec((ctx) => this.dialect.delete(ctx, entity, q, opts));
|
|
496
414
|
return changes;
|
|
497
415
|
}
|
|
498
416
|
get hasOpenTransaction() {
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical Type System
|
|
3
|
-
*
|
|
4
|
-
* Provides bidirectional mapping between:
|
|
5
|
-
* - SQL types (dialect-specific)
|
|
6
|
-
* - Canonical types (dialect-agnostic)
|
|
7
|
-
* - TypeScript types (for entity generation)
|
|
8
|
-
*/
|
|
9
1
|
import type { AbstractDialect } from '../dialect/abstractDialect.js';
|
|
10
2
|
import type { VectorCast } from '../dialect/vectorCast.js';
|
|
11
3
|
import type { ColumnType, FieldOptions } from '../type/entity.js';
|
|
@@ -37,25 +29,15 @@ export declare function canonicalToSql(type: CanonicalType, dialect: AbstractDia
|
|
|
37
29
|
*/
|
|
38
30
|
export declare function canonicalToTypeScript(type: CanonicalType): string;
|
|
39
31
|
/**
|
|
40
|
-
* A type as `dialect`
|
|
41
|
-
*
|
|
42
|
-
* Several canonical types share one storage type per engine - a `boolean` is `TINYINT(1)` on MySQL and
|
|
43
|
-
* `INTEGER` on SQLite - and only the engine settles an unstated bound, since `VARCHAR` is 255 on MySQL
|
|
44
|
-
* and `TEXT` on Postgres. Both paths that diff a schema compare through this, so a migration and a
|
|
45
|
-
* drift report cannot disagree about what changed.
|
|
32
|
+
* A type as `dialect` stores it, rendered and read back: several types share one storage type, and only
|
|
33
|
+
* the engine settles an unstated bound. Migrations and drift both compare through it.
|
|
46
34
|
*/
|
|
47
35
|
export declare function engineType(dialect: AbstractDialect): (type: CanonicalType) => CanonicalType;
|
|
48
36
|
/**
|
|
49
37
|
* Convert UQL FieldOptions to a canonical type.
|
|
50
38
|
*/
|
|
51
39
|
export declare function fieldOptionsToCanonical(options: FieldOptions): CanonicalType;
|
|
52
|
-
/**
|
|
53
|
-
* Compare two canonical types for equality. Used for schema diffing.
|
|
54
|
-
*
|
|
55
|
-
* Nothing here guesses an engine's own default for an unstated bound: `VARCHAR` is 255 on MySQL and
|
|
56
|
-
* `TEXT` on Postgres, and a comparison that assumed either was blind to that difference on the other.
|
|
57
|
-
* `DiffOptions.normalizeType` is what settles it, by putting both sides through the engine first.
|
|
58
|
-
*/
|
|
40
|
+
/** Whether two canonical types are equal, guessing no engine default: `DiffOptions.normalizeType` settles those. */
|
|
59
41
|
export declare function areTypesEqual(a: CanonicalType, b: CanonicalType): boolean;
|
|
60
42
|
/**
|
|
61
43
|
* Whether changing a column from one type to the other can lose what it holds.
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Canonical Type System
|
|
3
|
-
*
|
|
4
|
-
* Provides bidirectional mapping between:
|
|
5
|
-
* - SQL types (dialect-specific)
|
|
6
|
-
* - Canonical types (dialect-agnostic)
|
|
7
|
-
* - TypeScript types (for entity generation)
|
|
8
|
-
*/
|
|
1
|
+
// Canonical types, between an engine's SQL types and TypeScript's.
|
|
9
2
|
import { columnFamily, isIntegerColumn } from '../util/field.util.js';
|
|
10
3
|
/** Whether a category is one of the vector types, narrowing it to the cast pgvector names use. */
|
|
11
4
|
export function isVectorCategory(category) {
|
|
@@ -92,7 +85,7 @@ const SQL_TO_CANONICAL = {
|
|
|
92
85
|
};
|
|
93
86
|
/**
|
|
94
87
|
* pgvector is the only engine with three vector column types, so every other engine maps all three
|
|
95
|
-
* canonical categories onto the single type it does have (see `
|
|
88
|
+
* canonical categories onto the single type it does have (see `SqlDialectFeatures.narrowVectorTypes`,
|
|
96
89
|
* the dialect-side half of the same fact).
|
|
97
90
|
*/
|
|
98
91
|
function withVectorType(scalars, vector) {
|
|
@@ -242,59 +235,31 @@ const CANONICAL_TO_TS = {
|
|
|
242
235
|
*/
|
|
243
236
|
export function sqlToCanonical(sqlType) {
|
|
244
237
|
const normalized = sqlType.toLowerCase().trim();
|
|
245
|
-
|
|
246
|
-
const hasUnsigned = normalized.includes('unsigned');
|
|
238
|
+
const unsigned = normalized.includes('unsigned');
|
|
247
239
|
const withoutUnsigned = normalized.replace(/\s*unsigned\s*/i, ' ').trim();
|
|
248
240
|
// Extract base type and parameters: "VARCHAR(255)" -> ["varchar", "255"]
|
|
249
241
|
const match = withoutUnsigned.match(/^([a-z][a-z0-9 ]*?)(?:\(([^)]+)\))?$/);
|
|
250
|
-
|
|
242
|
+
const base = match ? SQL_TO_CANONICAL[match[1]] : undefined;
|
|
243
|
+
if (!match || !base) {
|
|
251
244
|
return { category: 'string', raw: sqlType };
|
|
252
245
|
}
|
|
253
|
-
const [,
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
246
|
+
const params = match[2]?.split(',').map((param) => param.trim()) ?? [];
|
|
247
|
+
const [first, second] = params
|
|
248
|
+
.map((param) => Number.parseInt(param, 10))
|
|
249
|
+
.map((n) => (Number.isNaN(n) ? undefined : n));
|
|
250
|
+
// A length for a string or a blob, the dimensions for a vector: `VARCHAR(255)`, `VECTOR(1536)`.
|
|
251
|
+
const measured = base.category === 'string' || base.category === 'blob' || isVectorCategory(base.category);
|
|
252
|
+
const decimal = base.category === 'decimal';
|
|
253
|
+
return {
|
|
260
254
|
category: base.category,
|
|
261
|
-
|
|
255
|
+
// SQL Server's unbounded `(MAX)` is what it creates for a `TEXT`.
|
|
256
|
+
size: measured && params[0] === 'max' ? 'small' : base.size,
|
|
262
257
|
withTimezone: base.withTimezone,
|
|
258
|
+
length: measured ? first : undefined,
|
|
259
|
+
precision: decimal ? first : undefined,
|
|
260
|
+
scale: decimal ? second : undefined,
|
|
261
|
+
unsigned: unsigned || undefined,
|
|
263
262
|
};
|
|
264
|
-
// Parse parameters
|
|
265
|
-
if (params) {
|
|
266
|
-
const paramParts = params.split(',').map((p) => p.trim());
|
|
267
|
-
if (result.category === 'string' || result.category === 'blob') {
|
|
268
|
-
// VARCHAR(255) -> length
|
|
269
|
-
const length = Number.parseInt(paramParts[0], 10);
|
|
270
|
-
if (!Number.isNaN(length)) {
|
|
271
|
-
result.length = length;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
else if (result.category === 'decimal') {
|
|
275
|
-
// DECIMAL(10,2) -> precision, scale
|
|
276
|
-
const precision = Number.parseInt(paramParts[0], 10);
|
|
277
|
-
const scale = paramParts[1] ? Number.parseInt(paramParts[1], 10) : undefined;
|
|
278
|
-
if (!Number.isNaN(precision)) {
|
|
279
|
-
result.precision = precision;
|
|
280
|
-
}
|
|
281
|
-
if (scale !== undefined && !Number.isNaN(scale)) {
|
|
282
|
-
result.scale = scale;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
else if (isVectorCategory(result.category)) {
|
|
286
|
-
// VECTOR(1536), HALFVEC(1536), SPARSEVEC(4000) -> length (dimensions)
|
|
287
|
-
const dimensions = Number.parseInt(paramParts[0], 10);
|
|
288
|
-
if (!Number.isNaN(dimensions)) {
|
|
289
|
-
result.length = dimensions;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
// Check for UNSIGNED modifier
|
|
294
|
-
if (hasUnsigned) {
|
|
295
|
-
result.unsigned = true;
|
|
296
|
-
}
|
|
297
|
-
return result;
|
|
298
263
|
}
|
|
299
264
|
/**
|
|
300
265
|
* The canonical type for a column an engine reported, merging the metadata columns it reports beside
|
|
@@ -363,12 +328,8 @@ export function canonicalToTypeScript(type) {
|
|
|
363
328
|
return CANONICAL_TO_TS[type.category];
|
|
364
329
|
}
|
|
365
330
|
/**
|
|
366
|
-
* A type as `dialect`
|
|
367
|
-
*
|
|
368
|
-
* Several canonical types share one storage type per engine - a `boolean` is `TINYINT(1)` on MySQL and
|
|
369
|
-
* `INTEGER` on SQLite - and only the engine settles an unstated bound, since `VARCHAR` is 255 on MySQL
|
|
370
|
-
* and `TEXT` on Postgres. Both paths that diff a schema compare through this, so a migration and a
|
|
371
|
-
* drift report cannot disagree about what changed.
|
|
331
|
+
* A type as `dialect` stores it, rendered and read back: several types share one storage type, and only
|
|
332
|
+
* the engine settles an unstated bound. Migrations and drift both compare through it.
|
|
372
333
|
*/
|
|
373
334
|
export function engineType(dialect) {
|
|
374
335
|
return (type) => sqlToCanonical(canonicalToSql(type, dialect));
|
|
@@ -407,13 +368,7 @@ export function fieldOptionsToCanonical(options) {
|
|
|
407
368
|
return { category: 'string', length: options.length };
|
|
408
369
|
}
|
|
409
370
|
}
|
|
410
|
-
/**
|
|
411
|
-
* Compare two canonical types for equality. Used for schema diffing.
|
|
412
|
-
*
|
|
413
|
-
* Nothing here guesses an engine's own default for an unstated bound: `VARCHAR` is 255 on MySQL and
|
|
414
|
-
* `TEXT` on Postgres, and a comparison that assumed either was blind to that difference on the other.
|
|
415
|
-
* `DiffOptions.normalizeType` is what settles it, by putting both sides through the engine first.
|
|
416
|
-
*/
|
|
371
|
+
/** Whether two canonical types are equal, guessing no engine default: `DiffOptions.normalizeType` settles those. */
|
|
417
372
|
export function areTypesEqual(a, b) {
|
|
418
373
|
return (a.category === b.category &&
|
|
419
374
|
a.size === b.size &&
|
|
@@ -4,15 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export type DependenciesOf<N> = (node: N) => Iterable<N>;
|
|
6
6
|
/**
|
|
7
|
-
* Nodes in creation order, dependencies first. Cycle-tolerant
|
|
8
|
-
*
|
|
9
|
-
* throwing. Use {@link findCycles} to report one.
|
|
7
|
+
* Nodes in creation order, dependencies first. Cycle-tolerant: a cyclic foreign key is legal SQL,
|
|
8
|
+
* handled by deferring the constraint, so a cycle orders arbitrarily rather than throwing.
|
|
10
9
|
*/
|
|
11
10
|
export declare function createOrder<N>(nodes: Iterable<N>, dependenciesOf: DependenciesOf<N>): N[];
|
|
12
11
|
/** Nodes in drop order, dependents first. */
|
|
13
12
|
export declare function dropOrder<N>(nodes: Iterable<N>, dependenciesOf: DependenciesOf<N>): N[];
|
|
14
|
-
/**
|
|
15
|
-
* Every dependency cycle, each starting where it closes. A separate walk from {@link createOrder}
|
|
16
|
-
* rather than a flag on it: ordering must succeed on any graph, reporting must see every cycle.
|
|
17
|
-
*/
|
|
18
|
-
export declare function findCycles<N>(nodes: Iterable<N>, dependenciesOf: DependenciesOf<N>): N[][];
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* describing its edges rather than by adding a branch here.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* Nodes in creation order, dependencies first. Cycle-tolerant
|
|
7
|
-
*
|
|
8
|
-
* throwing. Use {@link findCycles} to report one.
|
|
6
|
+
* Nodes in creation order, dependencies first. Cycle-tolerant: a cyclic foreign key is legal SQL,
|
|
7
|
+
* handled by deferring the constraint, so a cycle orders arbitrarily rather than throwing.
|
|
9
8
|
*/
|
|
10
9
|
export function createOrder(nodes, dependenciesOf) {
|
|
11
10
|
const ordered = [];
|
|
@@ -29,32 +28,3 @@ export function createOrder(nodes, dependenciesOf) {
|
|
|
29
28
|
export function dropOrder(nodes, dependenciesOf) {
|
|
30
29
|
return createOrder(nodes, dependenciesOf).reverse();
|
|
31
30
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Every dependency cycle, each starting where it closes. A separate walk from {@link createOrder}
|
|
34
|
-
* rather than a flag on it: ordering must succeed on any graph, reporting must see every cycle.
|
|
35
|
-
*/
|
|
36
|
-
export function findCycles(nodes, dependenciesOf) {
|
|
37
|
-
const cycles = [];
|
|
38
|
-
const visited = new Set();
|
|
39
|
-
const onPath = new Set();
|
|
40
|
-
const visit = (node, path) => {
|
|
41
|
-
// A node on the walk was handed down in `path` too, so the cycle closes where it first appears.
|
|
42
|
-
if (onPath.has(node)) {
|
|
43
|
-
cycles.push(path.slice(path.indexOf(node)));
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (visited.has(node)) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
visited.add(node);
|
|
50
|
-
onPath.add(node);
|
|
51
|
-
for (const dependency of dependenciesOf(node)) {
|
|
52
|
-
visit(dependency, [...path, node]);
|
|
53
|
-
}
|
|
54
|
-
onPath.delete(node);
|
|
55
|
-
};
|
|
56
|
-
for (const node of nodes) {
|
|
57
|
-
visit(node, []);
|
|
58
|
-
}
|
|
59
|
-
return cycles;
|
|
60
|
-
}
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,26 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema AST Module
|
|
3
|
-
*
|
|
4
|
-
* Provides a unified graph representation of database schema for:
|
|
5
|
-
* - Schema diffing and migration generation
|
|
6
|
-
* - Entity code generation from database
|
|
7
|
-
* - Drift detection
|
|
8
|
-
* - Smart relation inference
|
|
9
|
-
*/
|
|
10
|
-
import type { SchemaIntrospector } from '../type/migration.js';
|
|
11
|
-
import type { SchemaAST } from './schemaAST.js';
|
|
12
|
-
export { areTypesEqual, canonicalToColumnType, canonicalToSql, canonicalToTypeScript, fieldOptionsToCanonical, isBreakingTypeChange, sqlToCanonical, } from './canonicalType.js';
|
|
13
|
-
/**
|
|
14
|
-
* Introspect the database and build a SchemaAST from it.
|
|
15
|
-
*
|
|
16
|
-
* @param introspector - The schema introspector to use
|
|
17
|
-
* @returns The SchemaAST representing the database schema
|
|
18
|
-
*/
|
|
19
|
-
export declare function introspectSchema(introspector: SchemaIntrospector): Promise<SchemaAST>;
|
|
20
|
-
export { createOrder, dropOrder, findCycles, type DependenciesOf } from './dependencyGraph.js';
|
|
21
1
|
export { SchemaAST } from './schemaAST.js';
|
|
22
|
-
export type {
|
|
23
|
-
export { buildSchemaAST } from './schemaASTBuilder.js';
|
|
24
|
-
export type { DiffOptions } from './schemaASTDiffer.js';
|
|
25
|
-
export { diffSchemas } from './schemaASTDiffer.js';
|
|
26
|
-
export type { CanonicalType, ColumnDiff, ColumnNode, Drift, DriftReport, DriftSeverity, DriftStatus, DriftType, ForeignKeyAction, IndexDiff, IndexNode, IndexSource, IndexSyncStatus, IndexType, RelationshipDiff, RelationshipNode, RelationshipSource, RelationshipType, SchemaAST as ISchemaAST, SchemaDiffResult, SizeVariant, TableDiff, TableNode, TypeCategory, ValidationError, ValidationErrorType, } from './types.js';
|
|
2
|
+
export type { Drift, DriftReport } from './types.js';
|
package/dist/schema/index.js
CHANGED
|
@@ -1,27 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema AST Module
|
|
3
|
-
*
|
|
4
|
-
* Provides a unified graph representation of database schema for:
|
|
5
|
-
* - Schema diffing and migration generation
|
|
6
|
-
* - Entity code generation from database
|
|
7
|
-
* - Drift detection
|
|
8
|
-
* - Smart relation inference
|
|
9
|
-
*/
|
|
10
|
-
// Canonical type utilities
|
|
11
|
-
export { areTypesEqual, canonicalToColumnType, canonicalToSql, canonicalToTypeScript, fieldOptionsToCanonical, isBreakingTypeChange, sqlToCanonical, } from './canonicalType.js';
|
|
12
|
-
/**
|
|
13
|
-
* Introspect the database and build a SchemaAST from it.
|
|
14
|
-
*
|
|
15
|
-
* @param introspector - The schema introspector to use
|
|
16
|
-
* @returns The SchemaAST representing the database schema
|
|
17
|
-
*/
|
|
18
|
-
export async function introspectSchema(introspector) {
|
|
19
|
-
return introspector.introspect();
|
|
20
|
-
}
|
|
21
|
-
// SchemaAST class
|
|
22
|
-
export { createOrder, dropOrder, findCycles } from './dependencyGraph.js';
|
|
23
1
|
export { SchemaAST } from './schemaAST.js';
|
|
24
|
-
// Builder
|
|
25
|
-
export { buildSchemaAST } from './schemaASTBuilder.js';
|
|
26
|
-
// Differ
|
|
27
|
-
export { diffSchemas } from './schemaASTDiffer.js';
|
|
@@ -1,10 +1,3 @@
|
|
|
1
1
|
import type { ColumnNode, IndexNode } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* The table columns an index resolves to, in order.
|
|
4
|
-
*
|
|
5
|
-
* Derived rather than stored: an index is defined by its entries, and a second field repeating them
|
|
6
|
-
* as columns is a second thing to keep in step. It went out of step - one introspector rebuilt the
|
|
7
|
-
* entries from the columns it had just built from the entries, and every fixture had to write both.
|
|
8
|
-
* An expression entry resolves to no column at all, which is why the two were never the same list.
|
|
9
|
-
*/
|
|
2
|
+
/** The table columns an index's entries resolve to, in order; an expression entry resolves to none. */
|
|
10
3
|
export declare function indexColumns(index: IndexNode): ColumnNode[];
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The table columns an index resolves to, in order.
|
|
3
|
-
*
|
|
4
|
-
* Derived rather than stored: an index is defined by its entries, and a second field repeating them
|
|
5
|
-
* as columns is a second thing to keep in step. It went out of step - one introspector rebuilt the
|
|
6
|
-
* entries from the columns it had just built from the entries, and every fixture had to write both.
|
|
7
|
-
* An expression entry resolves to no column at all, which is why the two were never the same list.
|
|
8
|
-
*/
|
|
1
|
+
/** The table columns an index's entries resolve to, in order; an expression entry resolves to none. */
|
|
9
2
|
export function indexColumns(index) {
|
|
10
3
|
return index.entries.flatMap((entry) => (entry.expression ? [] : (index.table.columns.get(entry.column) ?? [])));
|
|
11
4
|
}
|