@easy-cms/drizzle 1.9.0 → 1.10.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/index.d.ts +7 -1
- package/dist/index.js +50 -7
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,10 @@ interface Dialect {
|
|
|
43
43
|
uniqueIndex(name: string): {
|
|
44
44
|
on(...columns: AnyColumn[]): IndexBuilder;
|
|
45
45
|
};
|
|
46
|
+
/** An index for `like` on any substring (`index: 'trigram'`); without it, none is made. */
|
|
47
|
+
trigramIndex?(name: string): {
|
|
48
|
+
on(column: AnyColumn): IndexBuilder;
|
|
49
|
+
};
|
|
46
50
|
/** Auto-incrementing integer primary key. */
|
|
47
51
|
serial(name: string): ColumnBuilder;
|
|
48
52
|
text(name: string): ColumnBuilder;
|
|
@@ -184,8 +188,10 @@ declare class Migrator {
|
|
|
184
188
|
private get runner();
|
|
185
189
|
private q;
|
|
186
190
|
private snapshotOf;
|
|
187
|
-
/** SQL statements that turn `prev` into `cur
|
|
191
|
+
/** SQL statements that turn `prev` into `cur`, with the extensions their indexes need. */
|
|
188
192
|
private diff;
|
|
193
|
+
/** Renames become drop + add unless interactive. */
|
|
194
|
+
private changes;
|
|
189
195
|
/**
|
|
190
196
|
* A new default locale changes which locale the plain column holds (`title` is the default
|
|
191
197
|
* locale's, `title__en` another's). Moves the values so every locale keeps its own.
|
package/dist/index.js
CHANGED
|
@@ -399,6 +399,8 @@ function buildTable(builder, name, kind, fields, options) {
|
|
|
399
399
|
indexes.push({ column, unique: false });
|
|
400
400
|
} else if (topLevel && kind === "root" && (field.unique || field.type === "slug")) {
|
|
401
401
|
indexes.push({ column, unique: true });
|
|
402
|
+
} else if (field.index === "trigram") {
|
|
403
|
+
indexes.push({ column, unique: false, trigram: true });
|
|
402
404
|
} else if (field.index || field.unique || field.type === "slug" || field.type === "relationship" || field.type === "upload") {
|
|
403
405
|
indexes.push({ column, unique: false });
|
|
404
406
|
}
|
|
@@ -410,8 +412,10 @@ function buildTable(builder, name, kind, fields, options) {
|
|
|
410
412
|
const table = dialect.table(
|
|
411
413
|
name,
|
|
412
414
|
columns,
|
|
413
|
-
(t) => indexes.
|
|
415
|
+
(t) => indexes.flatMap(({ column, unique, within, trigram }) => {
|
|
414
416
|
const col3 = t[column];
|
|
417
|
+
if (trigram)
|
|
418
|
+
return dialect.trigramIndex ? [dialect.trigramIndex(`${name}_${column}_trgm`).on(col3)] : [];
|
|
415
419
|
if (within) {
|
|
416
420
|
const columns2 = [within].flat();
|
|
417
421
|
return dialect.uniqueIndex(`${name}_${columns2.join("_")}_${column}_unique`).on(...columns2.map((w) => t[w]), col3);
|
|
@@ -485,8 +489,13 @@ var Migrator = class {
|
|
|
485
489
|
const meta = { localization: schema?.localization ?? null };
|
|
486
490
|
return { ...snapshot, [META]: meta };
|
|
487
491
|
}
|
|
488
|
-
/** SQL statements that turn `prev` into `cur
|
|
492
|
+
/** SQL statements that turn `prev` into `cur`, with the extensions their indexes need. */
|
|
489
493
|
async diff(prev, cur, interactive) {
|
|
494
|
+
const statements = await this.changes(prev, cur, interactive);
|
|
495
|
+
return statements.some((s) => s.includes("gin_trgm_ops")) ? ["CREATE EXTENSION IF NOT EXISTS pg_trgm", ...statements] : statements;
|
|
496
|
+
}
|
|
497
|
+
/** Renames become drop + add unless interactive. */
|
|
498
|
+
async changes(prev, cur, interactive) {
|
|
490
499
|
const { dialect } = this.options;
|
|
491
500
|
const moves = this.localeMoves(prev, metaOf(prev), metaOf(cur));
|
|
492
501
|
const [from, to] = [withoutMeta(prev), withoutMeta(cur)];
|
|
@@ -572,10 +581,16 @@ var Migrator = class {
|
|
|
572
581
|
if (statements.some((s) => DESTRUCTIVE.test(s))) {
|
|
573
582
|
this.options.logger.warn("Schema push drops tables or columns; data in them is lost.");
|
|
574
583
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
584
|
+
try {
|
|
585
|
+
await this.runner.transaction([
|
|
586
|
+
...statements.map((sql3) => ({ sql: sql3 })),
|
|
587
|
+
this.record(DEV_PUSH, this.options.schema.hash, cur, true)
|
|
588
|
+
]);
|
|
589
|
+
} catch (error) {
|
|
590
|
+
const hint = extensionHint(error);
|
|
591
|
+
if (hint) throw new SchemaError(`${error.message}${hint}`);
|
|
592
|
+
throw error;
|
|
593
|
+
}
|
|
579
594
|
if (statements.length > 0)
|
|
580
595
|
this.options.logger.info(`Schema pushed (${statements.length} statements).`);
|
|
581
596
|
}
|
|
@@ -647,7 +662,7 @@ ${BREAKPOINT}
|
|
|
647
662
|
]);
|
|
648
663
|
} catch (error) {
|
|
649
664
|
throw new SchemaError(
|
|
650
|
-
`Migration ${migration.name} failed and was rolled back: ${error.message}`
|
|
665
|
+
`Migration ${migration.name} failed and was rolled back: ${error.message}${extensionHint(error)}`
|
|
651
666
|
);
|
|
652
667
|
}
|
|
653
668
|
this.options.logger.info(`Applied ${migration.name}`);
|
|
@@ -689,6 +704,13 @@ function timestamp() {
|
|
|
689
704
|
const pad = (n) => String(n).padStart(2, "0");
|
|
690
705
|
return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}`;
|
|
691
706
|
}
|
|
707
|
+
function extensionHint(error) {
|
|
708
|
+
const match = /permission denied to create extension "([^"]+)"/.exec(
|
|
709
|
+
error?.message ?? ""
|
|
710
|
+
);
|
|
711
|
+
if (!match) return "";
|
|
712
|
+
return `. Ask the database's owner to run, once: CREATE EXTENSION IF NOT EXISTS ${match[1]} (with SCHEMA <yours> when this role's search_path is a schema of its own).`;
|
|
713
|
+
}
|
|
692
714
|
|
|
693
715
|
// src/query.ts
|
|
694
716
|
import { QueryError } from "@easy-cms/core";
|
|
@@ -1095,6 +1117,7 @@ async function connectDatabase(dialect, connection, args, options = {}) {
|
|
|
1095
1117
|
});
|
|
1096
1118
|
if (args.schema === "push") await migrator.push();
|
|
1097
1119
|
else if (args.schema === "verify") await migrator.verify();
|
|
1120
|
+
if (dialect.name === "postgres" && usesTrigram(args.config)) await checkCtype(connection, args);
|
|
1098
1121
|
const countCacheMs = (args.config.countCacheSeconds ?? 5) * 1e3;
|
|
1099
1122
|
return new DrizzleDatabase(dialect, connection, schema, migrator, prefix, countCacheMs);
|
|
1100
1123
|
} catch (error) {
|
|
@@ -1387,6 +1410,26 @@ var DrizzleDatabase = class {
|
|
|
1387
1410
|
await this.connection.close();
|
|
1388
1411
|
}
|
|
1389
1412
|
};
|
|
1413
|
+
function usesTrigram(config) {
|
|
1414
|
+
const search = (fields) => fields.some((field) => {
|
|
1415
|
+
const f = field;
|
|
1416
|
+
return f.index === "trigram" || (f.fields ? search(f.fields) : false) || (f.blocks ? f.blocks.some((b) => search(b.fields)) : false) || (f.tabs ? f.tabs.some((t) => search(t.fields)) : false);
|
|
1417
|
+
});
|
|
1418
|
+
return [...config.collections, ...config.globals].some((c) => search(c.fields));
|
|
1419
|
+
}
|
|
1420
|
+
async function checkCtype(connection, args) {
|
|
1421
|
+
try {
|
|
1422
|
+
const [row] = await connection.runner.query(
|
|
1423
|
+
"SELECT datctype FROM pg_database WHERE datname = current_database()"
|
|
1424
|
+
);
|
|
1425
|
+
const ctype = String(row?.datctype ?? "");
|
|
1426
|
+
if (ctype === "C" || ctype === "POSIX")
|
|
1427
|
+
args.logger.warn(
|
|
1428
|
+
`index: 'trigram' can't help searching Thai or other non-ASCII text in this database: its LC_CTYPE is ${ctype}. Create the database with LC_CTYPE 'C.UTF-8', 'en_US.UTF-8' or 'th_TH.UTF-8'.`
|
|
1429
|
+
);
|
|
1430
|
+
} catch {
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1390
1433
|
export {
|
|
1391
1434
|
DEFAULT_MIGRATION_DIR,
|
|
1392
1435
|
DEFAULT_TABLE_PREFIX,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easy-cms/drizzle",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Shared Drizzle ORM layer for Easy CMS database adapters",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"drizzle-orm": "0.45.4"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@easy-cms/core": "^1.
|
|
26
|
+
"@easy-cms/core": "^1.10.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@easy-cms/core": "^1.
|
|
29
|
+
"@easy-cms/core": "^1.10.0"
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"access": "public"
|