@easy-cms/drizzle 0.9.1 → 0.11.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 CHANGED
@@ -58,11 +58,18 @@ interface Dialect {
58
58
  * (any element when it returns undefined). Anything but an array has no elements.
59
59
  */
60
60
  someElement(array: AnyColumn | SQL, condition: (el: JsonElement) => SQL | undefined): SQL;
61
+ /**
62
+ * True when a JSON column contains `pattern` (Postgres `@>`, which can skip unpacking arrays).
63
+ * Optional: without it, equality inside blocks uses `someElement`.
64
+ */
65
+ jsonContains?(column: AnyColumn, pattern: unknown): SQL;
61
66
  /**
62
67
  * For sorting: the value at `path` in the first element that has one, stepping through the
63
68
  * nested `lists` in each element (in order) like `someElement`.
64
69
  */
65
70
  firstElementValue(array: AnyColumn | SQL, lists: readonly (readonly string[])[], path: readonly string[], type: JsonValueType): SQL;
71
+ /** SQL that copies the whole database to a file while it is in use (SQLite: `VACUUM INTO`). */
72
+ backupSQL?(file: string): string;
66
73
  /** Placeholder for the n-th parameter (1-based) in raw SQL. */
67
74
  param(n: number): string;
68
75
  /** CREATE TABLE IF NOT EXISTS for the migrations table. */
package/dist/index.js CHANGED
@@ -300,7 +300,10 @@ function buildTable(builder, name, kind, fields, options) {
300
300
  add("id", dialect.serial("id"), "id:int");
301
301
  add("created_at", dialect.text("created_at").notNull(), "text!");
302
302
  add("updated_at", dialect.text("updated_at").notNull(), "text!");
303
- if (options.drafts) add("status", dialect.text("status").notNull().default("draft"), "status");
303
+ if (options.drafts) {
304
+ add("status", dialect.text("status").notNull().default("draft"), "status");
305
+ indexes.push({ column: "status", unique: false });
306
+ }
304
307
  indexes.push({ column: "created_at", unique: false });
305
308
  } else {
306
309
  const parentKind = options.parentIdKind ?? "integer";
@@ -937,9 +940,33 @@ var WhereBuilder = class {
937
940
  if (inner === null) return void 0;
938
941
  return operatorSQL(this.dialect, el.get(inner, type), field, op, value, path);
939
942
  };
943
+ const contains = this.containment(target, op, value);
944
+ if (contains) return contains;
940
945
  const some = this.dialect.someElement(target.column, (el) => match(el, 0));
941
946
  return inner === null && value === false ? not(some) : some;
942
947
  }
948
+ /**
949
+ * `equals` and `in` as JSON containment where the database has it: `layout.items.title = x`
950
+ * becomes `layout @> [{"items": [{"title": x}]}]`, which matches exactly the same documents
951
+ * without unpacking every array.
952
+ */
953
+ containment(target, op, value) {
954
+ const { jsonContains } = this.dialect;
955
+ const { lists, path, type, field } = target.value;
956
+ if (!jsonContains || !path) return void 0;
957
+ const values = op === "equals" ? [value] : op === "in" && Array.isArray(value) ? value : null;
958
+ if (!values || values.length === 0 || values.some((v) => v === null || v === void 0))
959
+ return void 0;
960
+ const nest = (segments, inner) => segments.reduceRight((acc, segment) => ({ [segment]: acc }), inner);
961
+ const patterns = values.map((raw) => {
962
+ const coerced = coerce(field, raw);
963
+ let pattern = type === "text" && typeof coerced !== "string" ? String(coerced) : coerced;
964
+ pattern = nest(path, pattern);
965
+ for (const list of [...lists].reverse()) pattern = nest(list, [pattern]);
966
+ return jsonContains(target.column, [pattern]);
967
+ });
968
+ return patterns.length === 1 ? patterns[0] : or(...patterns);
969
+ }
943
970
  /** Conditions on array rows or hasMany values become (NOT) EXISTS subqueries. */
944
971
  child(parent, child, rest, op, value, path, locale) {
945
972
  const table = child.table;
@@ -1162,6 +1189,13 @@ var DrizzleDatabase = class {
1162
1189
  migrationStatus() {
1163
1190
  return this.migrator.status();
1164
1191
  }
1192
+ get backup() {
1193
+ const { backupSQL } = this.dialect;
1194
+ if (!backupSQL) return void 0;
1195
+ return (file) => this.write(async () => {
1196
+ await this.connection.runner.query(backupSQL(file));
1197
+ });
1198
+ }
1165
1199
  async destroy() {
1166
1200
  await this.connection.close();
1167
1201
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easy-cms/drizzle",
3
- "version": "0.9.1",
3
+ "version": "0.11.0",
4
4
  "description": "Shared Drizzle ORM layer for Easy CMS database adapters",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,17 +23,17 @@
23
23
  "drizzle-orm": "0.45.3"
24
24
  },
25
25
  "peerDependencies": {
26
- "@easy-cms/core": "^0.9.1"
26
+ "@easy-cms/core": "^0.11.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@easy-cms/core": "^0.9.1"
29
+ "@easy-cms/core": "^0.11.0"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
36
- "url": "git+https://github.com/maritonx/easy-crm.git",
36
+ "url": "git+https://github.com/maritonx/easy-cms.git",
37
37
  "directory": "packages/drizzle"
38
38
  },
39
39
  "keywords": [