uql-orm 0.42.1 → 0.44.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.d.ts +6 -0
- package/dist/browser/querier/httpQuerier.js +1 -1
- package/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/dialect/abstractDialect.js +5 -6
- package/dist/dialect/abstractSqlDialect.d.ts +10 -12
- package/dist/dialect/abstractSqlDialect.js +34 -34
- package/dist/dialect/jsonSql.d.ts +3 -2
- package/dist/dialect/jsonSql.js +7 -5
- package/dist/dialect/vectorCast.d.ts +0 -6
- package/dist/dialect/vectorCast.js +0 -8
- package/dist/entity/decorator/bag.d.ts +3 -0
- package/dist/entity/decorator/members.d.ts +5 -2
- package/dist/entity/index.d.ts +1 -1
- package/dist/entity/index.js +1 -1
- package/dist/entity/metadata/definition.d.ts +15 -13
- package/dist/entity/metadata/definition.js +73 -25
- package/dist/http/handler.d.ts +8 -0
- package/dist/http/handler.js +5 -5
- package/dist/maria/mariaDialect.js +2 -2
- package/dist/migrate/cli.d.ts +5 -0
- package/dist/migrate/cli.js +33 -16
- package/dist/migrate/codegen/entityTypes.d.ts +7 -0
- package/dist/migrate/codegen/entityTypes.js +69 -0
- package/dist/migrate/codegen/index.d.ts +1 -0
- package/dist/migrate/codegen/index.js +1 -0
- package/dist/migrate/drift/driftDetector.js +5 -1
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -1
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -1
- package/dist/migrate/index.d.ts +1 -1
- package/dist/migrate/migrator.d.ts +34 -20
- package/dist/migrate/migrator.js +77 -34
- package/dist/migrate/schemaGenerator.d.ts +1 -5
- package/dist/migrate/schemaGenerator.js +11 -15
- package/dist/schema/canonicalType.d.ts +19 -4
- package/dist/schema/canonicalType.js +114 -164
- package/dist/schema/schemaASTBuilder.d.ts +23 -2
- package/dist/schema/schemaASTBuilder.js +2 -2
- package/dist/schema/schemaASTDiffer.js +6 -2
- package/dist/type/entity.d.ts +36 -6
- package/dist/type/migration.d.ts +14 -1
- package/dist/type/query.d.ts +2 -6
- package/dist/type/queryWhere.d.ts +13 -3
- package/dist/util/field.util.d.ts +19 -8
- package/dist/util/field.util.js +47 -51
- package/dist/util/fieldOption.util.d.ts +79 -0
- package/dist/util/fieldOption.util.js +84 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +1 -0
- package/dist/util/object.util.d.ts +3 -3
- package/dist/util/object.util.js +3 -3
- package/dist/util/sql.util.d.ts +4 -0
- package/dist/util/sql.util.js +4 -0
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DialectName, LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, Type } from '../type/index.js';
|
|
1
|
+
import type { DialectName, LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, SyncOptions, Type } from '../type/index.js';
|
|
2
2
|
import { LoggerWrapper } from '../util/index.js';
|
|
3
3
|
import type { IMigrationBuilder } from './builder/types.js';
|
|
4
4
|
/**
|
|
@@ -88,31 +88,45 @@ export declare class Migrator {
|
|
|
88
88
|
private introspectClaimedSchemas;
|
|
89
89
|
findEntityForTable(tableName: string): Promise<Type<unknown> | undefined>;
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Drops and recreates all tables (Development only!)
|
|
91
|
+
* Applies the entity schema to the database: every registered entity, or the one `entity` names.
|
|
92
|
+
*
|
|
93
|
+
* The whole surface is this and {@link planSync}, which answers the same question without running
|
|
94
|
+
* it - `force` and a single entity included, so `--dry-run` means the same thing whatever else was
|
|
95
|
+
* asked for.
|
|
98
96
|
*/
|
|
99
|
-
|
|
97
|
+
sync(options?: SyncOptions): Promise<void>;
|
|
100
98
|
/**
|
|
101
|
-
*
|
|
99
|
+
* Every table dropped and recreated.
|
|
100
|
+
*
|
|
101
|
+
* Both directions span the whole entity set rather than looping an entity at a time. A per-entity
|
|
102
|
+
* AST cannot resolve a cross-entity foreign key, so the old create loop silently produced a schema
|
|
103
|
+
* with no referential integrity; and the old drop loop went in reverse *declaration* order, which
|
|
104
|
+
* says nothing about the relation graph and is rejected as soon as the constraints are really there.
|
|
102
105
|
*/
|
|
103
|
-
|
|
104
|
-
safe?: boolean;
|
|
105
|
-
drop?: boolean;
|
|
106
|
-
logging?: boolean;
|
|
107
|
-
}): Promise<void>;
|
|
106
|
+
private forceStatements;
|
|
108
107
|
/**
|
|
109
|
-
*
|
|
108
|
+
* Sync one entity, for a schema that grows while the process runs: a content type an admin just
|
|
109
|
+
* created is one table to add, where the whole set would read the catalogue to work that out.
|
|
110
|
+
*
|
|
111
|
+
* The new-table case costs one existence check and creates with `IF NOT EXISTS`, so instances racing
|
|
112
|
+
* the same admin save settle instead of colliding. An existing table still pays for introspection,
|
|
113
|
+
* since a column diff needs the columns.
|
|
114
|
+
*/
|
|
115
|
+
/** The DDL for one entity: {@link planSync} narrowed to the table it names. */
|
|
116
|
+
private planEntity;
|
|
117
|
+
/** An alter diff as statements, narrowed to what the caller allows. */
|
|
118
|
+
private alterFromDiff;
|
|
119
|
+
/** The same for one entity against the table it already has, and nothing where the two agree. */
|
|
120
|
+
private alterFromEntity;
|
|
121
|
+
/** The configured entities, with `entity` among them however the migrator was built. */
|
|
122
|
+
private entitiesWith;
|
|
123
|
+
/** The introspector for a claimed schema, which is the connection's own where none is claimed. */
|
|
124
|
+
private introspectorFor;
|
|
125
|
+
/**
|
|
126
|
+
* The DDL {@link sync} would run, without running it. Separate so `--dry-run` shows the real
|
|
110
127
|
* statements rather than a summary of a second, differently-computed diff.
|
|
111
128
|
*/
|
|
112
|
-
planSync(options?:
|
|
113
|
-
safe?: boolean;
|
|
114
|
-
drop?: boolean;
|
|
115
|
-
}): Promise<string[]>;
|
|
129
|
+
planSync(options?: SyncOptions): Promise<string[]>;
|
|
116
130
|
/**
|
|
117
131
|
* New tables are emitted together, never one at a time: a single-entity AST has no other table for a
|
|
118
132
|
* relation to resolve against, so every cross-entity foreign key was dropped and generated schemas
|
package/dist/migrate/migrator.js
CHANGED
|
@@ -305,7 +305,7 @@ export class Migrator {
|
|
|
305
305
|
const claimed = new Set(this.entities.map((entity) => this.pool.dialect.resolveSchema(getMeta(entity))));
|
|
306
306
|
const merged = new SchemaAST();
|
|
307
307
|
for (const schema of claimed) {
|
|
308
|
-
const introspector =
|
|
308
|
+
const introspector = this.introspectorFor(schema);
|
|
309
309
|
if (!introspector) {
|
|
310
310
|
continue;
|
|
311
311
|
}
|
|
@@ -330,52 +330,90 @@ export class Migrator {
|
|
|
330
330
|
return undefined;
|
|
331
331
|
}
|
|
332
332
|
/**
|
|
333
|
-
*
|
|
333
|
+
* Applies the entity schema to the database: every registered entity, or the one `entity` names.
|
|
334
|
+
*
|
|
335
|
+
* The whole surface is this and {@link planSync}, which answers the same question without running
|
|
336
|
+
* it - `force` and a single entity included, so `--dry-run` means the same thing whatever else was
|
|
337
|
+
* asked for.
|
|
334
338
|
*/
|
|
335
339
|
async sync(options = {}) {
|
|
336
|
-
|
|
337
|
-
|
|
340
|
+
const statements = await this.planSync(options);
|
|
341
|
+
if (statements.length) {
|
|
342
|
+
await this.executeSyncStatements(statements, options);
|
|
343
|
+
}
|
|
344
|
+
else if (options.logging) {
|
|
345
|
+
this.logger.logSchema('Schema is already in sync.');
|
|
338
346
|
}
|
|
339
|
-
return this.autoSync({ safe: true });
|
|
340
347
|
}
|
|
341
348
|
/**
|
|
342
|
-
*
|
|
349
|
+
* Every table dropped and recreated.
|
|
350
|
+
*
|
|
351
|
+
* Both directions span the whole entity set rather than looping an entity at a time. A per-entity
|
|
352
|
+
* AST cannot resolve a cross-entity foreign key, so the old create loop silently produced a schema
|
|
353
|
+
* with no referential integrity; and the old drop loop went in reverse *declaration* order, which
|
|
354
|
+
* says nothing about the relation graph and is rejected as soon as the constraints are really there.
|
|
343
355
|
*/
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// Both directions span the whole entity set rather than looping an entity at a time. A per-entity
|
|
347
|
-
// AST cannot resolve a cross-entity foreign key, so the old create loop silently produced a schema
|
|
348
|
-
// with no referential integrity; and the old drop loop went in reverse *declaration* order, which
|
|
349
|
-
// says nothing about the relation graph and is rejected as soon as the constraints are really there.
|
|
350
|
-
const statements = [
|
|
356
|
+
forceStatements() {
|
|
357
|
+
return [
|
|
351
358
|
...this.generator.generateDropSchema(this.entities, { ifExists: true, cascade: true }),
|
|
352
359
|
...this.generator.generateCreateSchema(this.entities),
|
|
353
360
|
];
|
|
354
|
-
await withSqlQuerierForMigrations(this.pool, 'Migrator', (querier) => querier.transaction(async () => {
|
|
355
|
-
for (const sql of statements) {
|
|
356
|
-
this.logger.logSchema(`Executing: ${sql}`);
|
|
357
|
-
await querier.run(sql);
|
|
358
|
-
}
|
|
359
|
-
}));
|
|
360
|
-
this.logger.logSchema('Schema sync (force) completed');
|
|
361
361
|
}
|
|
362
362
|
/**
|
|
363
|
-
*
|
|
363
|
+
* Sync one entity, for a schema that grows while the process runs: a content type an admin just
|
|
364
|
+
* created is one table to add, where the whole set would read the catalogue to work that out.
|
|
365
|
+
*
|
|
366
|
+
* The new-table case costs one existence check and creates with `IF NOT EXISTS`, so instances racing
|
|
367
|
+
* the same admin save settle instead of colliding. An existing table still pays for introspection,
|
|
368
|
+
* since a column diff needs the columns.
|
|
364
369
|
*/
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
370
|
+
/** The DDL for one entity: {@link planSync} narrowed to the table it names. */
|
|
371
|
+
async planEntity(entity, options) {
|
|
372
|
+
const meta = getMeta(entity);
|
|
373
|
+
// Before anything reads `this.generator`, whose own failure names neither the entity nor the
|
|
374
|
+
// dialect that has no support.
|
|
375
|
+
const introspector = this.introspectorFor(this.pool.dialect.resolveSchema(meta));
|
|
376
|
+
if (!introspector) {
|
|
377
|
+
throw new TypeError(`No introspector for '${meta.entity.name}' on '${this.dialectName}'`);
|
|
371
378
|
}
|
|
372
|
-
|
|
379
|
+
const tableName = this.generator.resolveTableName(meta);
|
|
380
|
+
return (await introspector.tableExists(tableName))
|
|
381
|
+
? this.alterFromEntity(entity, (await introspectSchema(introspector)).getTable(tableName), options)
|
|
382
|
+
: // Spanning the whole set, so a foreign key resolves against the tables it points at, and
|
|
383
|
+
// always including this entity: pinned to an explicit `entities` list, a sync of one outside
|
|
384
|
+
// it emitted nothing at all. `only` is what keeps the statements to this table.
|
|
385
|
+
this.generator.generateCreateSchema(this.entitiesWith(entity), { only: [tableName], ifNotExists: true });
|
|
386
|
+
}
|
|
387
|
+
/** An alter diff as statements, narrowed to what the caller allows. */
|
|
388
|
+
alterFromDiff(diff, options) {
|
|
389
|
+
return this.generator.generateAlterTable(this.filterDiff(diff, options));
|
|
390
|
+
}
|
|
391
|
+
/** The same for one entity against the table it already has, and nothing where the two agree. */
|
|
392
|
+
alterFromEntity(entity, table, options) {
|
|
393
|
+
const diff = this.generator.diffSchema(entity, table);
|
|
394
|
+
return diff?.type === 'alter' ? this.alterFromDiff(diff, options) : [];
|
|
395
|
+
}
|
|
396
|
+
/** The configured entities, with `entity` among them however the migrator was built. */
|
|
397
|
+
entitiesWith(entity) {
|
|
398
|
+
const entities = this.entities;
|
|
399
|
+
return entities.includes(entity) ? entities : [...entities, entity];
|
|
400
|
+
}
|
|
401
|
+
/** The introspector for a claimed schema, which is the connection's own where none is claimed. */
|
|
402
|
+
introspectorFor(schema) {
|
|
403
|
+
return schema === undefined ? this.schemaIntrospector : this.createIntrospector(schema);
|
|
373
404
|
}
|
|
374
405
|
/**
|
|
375
|
-
* The DDL {@link
|
|
406
|
+
* The DDL {@link sync} would run, without running it. Separate so `--dry-run` shows the real
|
|
376
407
|
* statements rather than a summary of a second, differently-computed diff.
|
|
377
408
|
*/
|
|
378
409
|
async planSync(options = {}) {
|
|
410
|
+
await this.ensureSchemaGenerator();
|
|
411
|
+
if (options.force) {
|
|
412
|
+
return this.forceStatements();
|
|
413
|
+
}
|
|
414
|
+
if (options.entity) {
|
|
415
|
+
return this.planEntity(options.entity, options);
|
|
416
|
+
}
|
|
379
417
|
const creating = [];
|
|
380
418
|
const altering = [];
|
|
381
419
|
for (const { diff, entity } of await this.pendingDiffs()) {
|
|
@@ -384,7 +422,7 @@ export class Migrator {
|
|
|
384
422
|
creating.push(diff.tableName);
|
|
385
423
|
}
|
|
386
424
|
else if (diff.type === 'alter') {
|
|
387
|
-
altering.push(...this.
|
|
425
|
+
altering.push(...this.alterFromDiff(diff, options));
|
|
388
426
|
}
|
|
389
427
|
}
|
|
390
428
|
return [...this.createSchema(creating), ...altering];
|
|
@@ -452,10 +490,15 @@ export class Migrator {
|
|
|
452
490
|
return filteredDiff;
|
|
453
491
|
}
|
|
454
492
|
async executeSyncStatements(statements, options) {
|
|
455
|
-
// Mongo creates collections and indexes outside any transaction, so only the SQL path opens one
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
493
|
+
// Mongo creates collections and indexes outside any transaction, so only the SQL path opens one -
|
|
494
|
+
// and asks for a SQL querier before it opens it, since `transaction` is what a Mongo one lacks and
|
|
495
|
+
// reaching for it first reports that instead of which querier the dialect needs.
|
|
496
|
+
if (this.dialectName === 'mongodb') {
|
|
497
|
+
await withQuerierForMigrations(this.pool, (querier) => this.executeMongoSyncStatements(statements, options, querier));
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
await withSqlQuerierForMigrations(this.pool, 'Migrator', (querier) => querier.transaction(() => this.executeSqlSyncStatements(statements, options, querier)));
|
|
501
|
+
}
|
|
459
502
|
if (options.logging)
|
|
460
503
|
this.logger.logSchema('Schema synchronization completed');
|
|
461
504
|
}
|
|
@@ -27,10 +27,6 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
27
27
|
* Primary key type for auto-increment integer IDs
|
|
28
28
|
*/
|
|
29
29
|
protected get serialType(): string;
|
|
30
|
-
/**
|
|
31
|
-
* Convert FieldOptions to CanonicalType using the unified type system.
|
|
32
|
-
*/
|
|
33
|
-
protected getCanonicalType(field: FieldOptions, fieldType?: unknown): CanonicalType;
|
|
34
30
|
protected canonicalTypeToSql(type: CanonicalType): string;
|
|
35
31
|
/**
|
|
36
32
|
* Every `CREATE TABLE` for `entities`, then their foreign keys.
|
|
@@ -85,7 +81,7 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
85
81
|
/** ` DEFAULT <sql>`, or nothing where the column declares none. Empty rather than `DEFAULT NULL`
|
|
86
82
|
* so an absent default stays absent - `defaultValue: null` is the way to ask for one. */
|
|
87
83
|
private defaultClause;
|
|
88
|
-
getSqlType(field: FieldMeta
|
|
84
|
+
getSqlType(field: FieldMeta): string;
|
|
89
85
|
/**
|
|
90
86
|
* Generate ALTER COLUMN statements (database-specific)
|
|
91
87
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbstractSqlDialect } from '../dialect/index.js';
|
|
2
2
|
import { getMeta, soleIdOf } from '../entity/index.js';
|
|
3
|
-
import { areTypesEqual, canonicalToSql, fieldOptionsToCanonical, isVectorCategory,
|
|
3
|
+
import { areTypesEqual, canonicalToSql, engineType, fieldOptionsToCanonical, isVectorCategory, } from '../schema/canonicalType.js';
|
|
4
4
|
import { indexSignature } from '../schema/indexDifferences.js';
|
|
5
5
|
import { buildSchemaAST } from '../schema/schemaASTBuilder.js';
|
|
6
6
|
import { diffTable } from '../schema/schemaASTDiffer.js';
|
|
@@ -52,12 +52,6 @@ export class SqlSchemaGenerator {
|
|
|
52
52
|
get serialType() {
|
|
53
53
|
return this.dialect.serialType;
|
|
54
54
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Convert FieldOptions to CanonicalType using the unified type system.
|
|
57
|
-
*/
|
|
58
|
-
getCanonicalType(field, fieldType) {
|
|
59
|
-
return fieldOptionsToCanonical(field, fieldType);
|
|
60
|
-
}
|
|
61
55
|
canonicalTypeToSql(type) {
|
|
62
56
|
return canonicalToSql(type, this.dialect);
|
|
63
57
|
}
|
|
@@ -275,18 +269,20 @@ export class SqlSchemaGenerator {
|
|
|
275
269
|
? ''
|
|
276
270
|
: ` DEFAULT ${formatDefaultValue(column.defaultValue, this.dialect, column.type)}`;
|
|
277
271
|
}
|
|
278
|
-
getSqlType(field
|
|
279
|
-
//
|
|
272
|
+
getSqlType(field) {
|
|
273
|
+
// A foreign key takes the type of the key it points at. A `referencedKey` the target does not
|
|
274
|
+
// have falls through to this column's own options, as the AST builder does with the same case.
|
|
280
275
|
if (field.references) {
|
|
281
|
-
const
|
|
282
|
-
const refMeta = getMeta(refEntity);
|
|
276
|
+
const refMeta = getMeta(field.references());
|
|
283
277
|
const refIdField = refMeta.fields[field.referencedKey ?? soleIdOf(refMeta, 'a foreign key')];
|
|
284
|
-
|
|
278
|
+
if (refIdField) {
|
|
279
|
+
return this.getSqlType({ ...refIdField, references: undefined, isId: undefined, autoIncrement: false });
|
|
280
|
+
}
|
|
285
281
|
}
|
|
286
282
|
// Get canonical type and convert to SQL
|
|
287
|
-
const canonical =
|
|
283
|
+
const canonical = fieldOptionsToCanonical(field);
|
|
288
284
|
// Special case for serial primary keys
|
|
289
|
-
if (isAutoIncrement(field,
|
|
285
|
+
if (isAutoIncrement(field, field.isId === true)) {
|
|
290
286
|
return this.dialect.serialType;
|
|
291
287
|
}
|
|
292
288
|
return this.canonicalTypeToSql(canonical);
|
|
@@ -408,7 +404,7 @@ export class SqlSchemaGenerator {
|
|
|
408
404
|
}
|
|
409
405
|
diffOptions() {
|
|
410
406
|
return {
|
|
411
|
-
normalizeType: (
|
|
407
|
+
normalizeType: engineType(this.dialect),
|
|
412
408
|
defaultsEqual: (expected, actual) => this.isDefaultValueEqual(actual, expected),
|
|
413
409
|
};
|
|
414
410
|
}
|
|
@@ -36,17 +36,32 @@ export declare function canonicalToSql(type: CanonicalType, dialect: AbstractDia
|
|
|
36
36
|
* Convert a canonical type to a TypeScript type string.
|
|
37
37
|
*/
|
|
38
38
|
export declare function canonicalToTypeScript(type: CanonicalType): string;
|
|
39
|
+
/**
|
|
40
|
+
* A type as `dialect` would actually store it: rendered to that engine's SQL and read back.
|
|
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.
|
|
46
|
+
*/
|
|
47
|
+
export declare function engineType(dialect: AbstractDialect): (type: CanonicalType) => CanonicalType;
|
|
39
48
|
/**
|
|
40
49
|
* Convert UQL FieldOptions to a canonical type.
|
|
41
50
|
*/
|
|
42
|
-
export declare function fieldOptionsToCanonical(options: FieldOptions
|
|
51
|
+
export declare function fieldOptionsToCanonical(options: FieldOptions): CanonicalType;
|
|
43
52
|
/**
|
|
44
|
-
* Compare two canonical types for equality.
|
|
45
|
-
*
|
|
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.
|
|
46
58
|
*/
|
|
47
59
|
export declare function areTypesEqual(a: CanonicalType, b: CanonicalType): boolean;
|
|
48
60
|
/**
|
|
49
|
-
*
|
|
61
|
+
* Whether changing a column from one type to the other can lose what it holds.
|
|
62
|
+
*
|
|
63
|
+
* An unstated bound is the engine's widest, so stating one for the first time narrows the column just
|
|
64
|
+
* as lowering one does: `TEXT` to `VARCHAR(50)` truncates, and `NUMERIC` to `NUMERIC(5,2)` rounds.
|
|
50
65
|
*/
|
|
51
66
|
export declare function isBreakingTypeChange(from: CanonicalType, to: CanonicalType): boolean;
|
|
52
67
|
/**
|