@lunora/do 0.0.0 → 1.0.0-alpha.10

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.
Files changed (50) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +115 -9
  3. package/__assets__/package-og.svg +14 -0
  4. package/dist/index.d.mts +6347 -0
  5. package/dist/index.d.ts +6347 -0
  6. package/dist/index.mjs +37 -0
  7. package/dist/packem_shared/ADMIN_FUNCTIONS-D_UiYJFk.mjs +316 -0
  8. package/dist/packem_shared/AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs +54 -0
  9. package/dist/packem_shared/AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs +84 -0
  10. package/dist/packem_shared/CDC_LOG_TABLE-DSycmnDf.mjs +107 -0
  11. package/dist/packem_shared/ConflictError-C0STs6bU.mjs +13 -0
  12. package/dist/packem_shared/CountRlsUnsupportedError-28ZvvwKS.mjs +133 -0
  13. package/dist/packem_shared/DATA_MIGRATION_STATE_TABLE-PTtTiQ7U.mjs +237 -0
  14. package/dist/packem_shared/DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs +209 -0
  15. package/dist/packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs +248 -0
  16. package/dist/packem_shared/LogBuffer-B_Ezju_N.mjs +37 -0
  17. package/dist/packem_shared/MAIL_RETENTION-CPpgl-dX.mjs +104 -0
  18. package/dist/packem_shared/MAX_SQL_ROWS-dDcFE1YZ.mjs +29 -0
  19. package/dist/packem_shared/MIN_ADMIN_TOKEN_LENGTH-CCAvoFlr.mjs +1 -0
  20. package/dist/packem_shared/NotFoundError-CMuMZt81.mjs +10 -0
  21. package/dist/packem_shared/NotUniqueError-DZQtH02h.mjs +1835 -0
  22. package/dist/packem_shared/RANK_TIEBREAK-CXhdcA1o.mjs +91 -0
  23. package/dist/packem_shared/RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs +132 -0
  24. package/dist/packem_shared/ROOT_DO_SIZE_WARN_BYTES-DKwBF3Jp.mjs +4996 -0
  25. package/dist/packem_shared/ReactiveCache-1hDydFyv.mjs +232 -0
  26. package/dist/packem_shared/SCAN_DEP-DLJF8dsj.mjs +19 -0
  27. package/dist/packem_shared/SESSION_DO_TTL_DEFAULT-ilPZsVwu.mjs +180 -0
  28. package/dist/packem_shared/SHARD_REGISTRY_DO_NAME-BsAbi5Mn.mjs +146 -0
  29. package/dist/packem_shared/aggregateTableName-CxNqY1Sl.mjs +64 -0
  30. package/dist/packem_shared/applyOnDelete-BQ-8ZlZ1.mjs +175 -0
  31. package/dist/packem_shared/applySelect-BvZdFUBT.mjs +101 -0
  32. package/dist/packem_shared/armRestore-BJk53Ro8.mjs +55 -0
  33. package/dist/packem_shared/backfillAggregateIndexes-BZsOqDXP.mjs +81 -0
  34. package/dist/packem_shared/buildFtsMatch-BLEMawrp.mjs +38 -0
  35. package/dist/packem_shared/compileWhereSql-CXrhFA3G.mjs +127 -0
  36. package/dist/packem_shared/createSystemReader-8CzSZP9V.mjs +80 -0
  37. package/dist/packem_shared/ctx-db-idempotency-BdcNpvY4.mjs +108 -0
  38. package/dist/packem_shared/ctx-db-shapes-DVoeZpo-.mjs +53 -0
  39. package/dist/packem_shared/do-exec-5eQy5cEi.mjs +12 -0
  40. package/dist/packem_shared/do-sql-BCHCWtrD.mjs +87 -0
  41. package/dist/packem_shared/exportShardRows-DZEhUeyI.mjs +156 -0
  42. package/dist/packem_shared/hasTrigger-5N6_Fx0A.mjs +20 -0
  43. package/dist/packem_shared/renderSql-D6eUcn2N.mjs +16 -0
  44. package/dist/packem_shared/runShardMigrations-nIwoQeOK.mjs +105 -0
  45. package/dist/packem_shared/security-audit-CucgBice.mjs +158 -0
  46. package/dist/packem_shared/serialize-sql-BlRUoiQe.mjs +14 -0
  47. package/dist/packem_shared/serveRelationFanout-C6lDaesn.mjs +24 -0
  48. package/dist/packem_shared/stableStringify-CyHKJXre.mjs +30 -0
  49. package/dist/packem_shared/subscriptionListDeltas-ce84gpwL.mjs +111 -0
  50. package/package.json +41 -17
@@ -0,0 +1,108 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
3
+
4
+ const CLIENT_WATERMARK_TABLE = "__client_watermark";
5
+ const migrateClientWatermark = (sql$1) => {
6
+ runDrizzle(
7
+ sql$1,
8
+ sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(CLIENT_WATERMARK_TABLE)} (
9
+ identity TEXT NOT NULL,
10
+ client_id TEXT NOT NULL,
11
+ last_mutation_id INTEGER NOT NULL,
12
+ PRIMARY KEY (identity, client_id)
13
+ )`
14
+ );
15
+ };
16
+ const readClientWatermark = (sql$1, identity, clientId) => {
17
+ const rows = runDrizzle(
18
+ sql$1,
19
+ sql`SELECT last_mutation_id FROM ${sql.identifier(CLIENT_WATERMARK_TABLE)} WHERE identity = ${identity} AND client_id = ${clientId} LIMIT 1`
20
+ ).toArray();
21
+ return rows[0]?.last_mutation_id ?? 0;
22
+ };
23
+ const advanceClientWatermark = (sql$1, identity, clientId, mutationId) => {
24
+ runDrizzle(
25
+ sql$1,
26
+ sql`INSERT INTO ${sql.identifier(CLIENT_WATERMARK_TABLE)} (identity, client_id, last_mutation_id) VALUES (${identity}, ${clientId}, ${mutationId})
27
+ ON CONFLICT(identity, client_id) DO UPDATE SET last_mutation_id = MAX(last_mutation_id, excluded.last_mutation_id)`
28
+ );
29
+ };
30
+
31
+ const GLOBAL_SHAPE_SNAPSHOT_TABLE = "__global_shape_snapshot";
32
+ const migrateGlobalShapeSnapshot = (sql$1) => {
33
+ runDrizzle(
34
+ sql$1,
35
+ sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(GLOBAL_SHAPE_SNAPSHOT_TABLE)} (
36
+ connection_id TEXT NOT NULL,
37
+ sub_id TEXT NOT NULL,
38
+ members TEXT NOT NULL,
39
+ PRIMARY KEY (connection_id, sub_id)
40
+ )`
41
+ );
42
+ };
43
+ const readGlobalShapeSnapshot = (sql$1, connectionId, subId) => {
44
+ const rows = runDrizzle(
45
+ sql$1,
46
+ sql`SELECT members FROM ${sql.identifier(GLOBAL_SHAPE_SNAPSHOT_TABLE)} WHERE connection_id = ${connectionId} AND sub_id = ${subId} LIMIT 1`
47
+ ).toArray();
48
+ const raw = rows[0]?.members;
49
+ if (raw === void 0) {
50
+ return /* @__PURE__ */ new Map();
51
+ }
52
+ try {
53
+ const parsed = JSON.parse(raw);
54
+ if (parsed === null || typeof parsed !== "object") {
55
+ return /* @__PURE__ */ new Map();
56
+ }
57
+ return new Map(Object.entries(parsed));
58
+ } catch {
59
+ return /* @__PURE__ */ new Map();
60
+ }
61
+ };
62
+ const writeGlobalShapeSnapshot = (sql$1, connectionId, subId, snapshot) => {
63
+ const members = JSON.stringify(Object.fromEntries(snapshot));
64
+ runDrizzle(
65
+ sql$1,
66
+ sql`INSERT INTO ${sql.identifier(GLOBAL_SHAPE_SNAPSHOT_TABLE)} (connection_id, sub_id, members) VALUES (${connectionId}, ${subId}, ${members})
67
+ ON CONFLICT(connection_id, sub_id) DO UPDATE SET members = excluded.members`
68
+ );
69
+ };
70
+ const deleteGlobalShapeSnapshot = (sql$1, connectionId, subId) => {
71
+ runDrizzle(sql$1, sql`DELETE FROM ${sql.identifier(GLOBAL_SHAPE_SNAPSHOT_TABLE)} WHERE connection_id = ${connectionId} AND sub_id = ${subId}`);
72
+ };
73
+ const deleteGlobalShapeSnapshotsForConnection = (sql$1, connectionId) => {
74
+ runDrizzle(sql$1, sql`DELETE FROM ${sql.identifier(GLOBAL_SHAPE_SNAPSHOT_TABLE)} WHERE connection_id = ${connectionId}`);
75
+ };
76
+
77
+ const IDEMPOTENCY_TABLE = "__idempotency";
78
+ const migrateIdempotency = (sql$1) => {
79
+ runDrizzle(
80
+ sql$1,
81
+ sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(IDEMPOTENCY_TABLE)} (
82
+ identity TEXT NOT NULL,
83
+ mutation_id TEXT NOT NULL,
84
+ result_json TEXT NOT NULL,
85
+ ts REAL NOT NULL,
86
+ PRIMARY KEY (identity, mutation_id)
87
+ )`
88
+ );
89
+ };
90
+ const readIdempotent = (sql$1, identity, mutationId) => {
91
+ const rows = runDrizzle(
92
+ sql$1,
93
+ sql`SELECT result_json, ts FROM ${sql.identifier(IDEMPOTENCY_TABLE)} WHERE identity = ${identity} AND mutation_id = ${mutationId} LIMIT 1`
94
+ ).toArray();
95
+ const row = rows[0];
96
+ return row === void 0 ? void 0 : { resultJson: row.result_json, ts: row.ts };
97
+ };
98
+ const writeIdempotent = (sql$1, identity, mutationId, resultJson, ts) => {
99
+ runDrizzle(
100
+ sql$1,
101
+ sql`INSERT OR IGNORE INTO ${sql.identifier(IDEMPOTENCY_TABLE)} (identity, mutation_id, result_json, ts) VALUES (${identity}, ${mutationId}, ${resultJson}, ${ts})`
102
+ );
103
+ };
104
+ const trimIdempotent = (sql$1, olderThanTs) => {
105
+ runDrizzle(sql$1, sql`DELETE FROM ${sql.identifier(IDEMPOTENCY_TABLE)} WHERE ts < ${olderThanTs}`);
106
+ };
107
+
108
+ export { CLIENT_WATERMARK_TABLE as C, GLOBAL_SHAPE_SNAPSHOT_TABLE as G, IDEMPOTENCY_TABLE as I, migrateIdempotency as a, migrateGlobalShapeSnapshot as b, advanceClientWatermark as c, deleteGlobalShapeSnapshot as d, deleteGlobalShapeSnapshotsForConnection as e, readGlobalShapeSnapshot as f, readIdempotent as g, writeIdempotent as h, migrateClientWatermark as m, readClientWatermark as r, trimIdempotent as t, writeGlobalShapeSnapshot as w };
@@ -0,0 +1,53 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
3
+ import { D as DOC_COLUMN, r as rowToDocument, j as jsonPathSql } from './do-sql-BCHCWtrD.mjs';
4
+ import { compileWhereSql } from './compileWhereSql-CXrhFA3G.mjs';
5
+ import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
6
+
7
+ const shapeWhereStrategy = { fieldRef: jsonPathSql, serialize: serializeSqlValue };
8
+ const idInClause = (ids) => {
9
+ if (ids.length === 0) {
10
+ return void 0;
11
+ }
12
+ return sql`id IN (${sql.join(
13
+ ids.map((id) => sql`${id}`),
14
+ sql`, `
15
+ )})`;
16
+ };
17
+ const composeWhere = (effectiveWhere, idRestriction) => {
18
+ const conditions = [];
19
+ if (idRestriction) {
20
+ conditions.push(idRestriction);
21
+ }
22
+ const compiled = compileWhereSql(effectiveWhere, shapeWhereStrategy);
23
+ if (compiled) {
24
+ conditions.push(compiled);
25
+ }
26
+ if (conditions.length === 0) {
27
+ return sql``;
28
+ }
29
+ return sql` WHERE ${sql.join(conditions, sql` AND `)}`;
30
+ };
31
+ const selectShapeRows = (sql$1, table, effectiveWhere) => {
32
+ const whereClause = composeWhere(effectiveWhere, void 0);
33
+ const rows = runDrizzle(sql$1, sql`SELECT id, _creationTime, ${sql.identifier(DOC_COLUMN)} FROM ${sql.identifier(table)}${whereClause}`).toArray();
34
+ const result = [];
35
+ for (const row of rows) {
36
+ const doc = rowToDocument(row);
37
+ const { id } = row;
38
+ if (doc !== void 0 && typeof id === "string") {
39
+ result.push({ doc, id });
40
+ }
41
+ }
42
+ return result;
43
+ };
44
+ const selectShapeMemberIds = (sql$1, table, effectiveWhere, ids) => {
45
+ if (ids.length === 0) {
46
+ return /* @__PURE__ */ new Set();
47
+ }
48
+ const whereClause = composeWhere(effectiveWhere, idInClause(ids));
49
+ const rows = runDrizzle(sql$1, sql`SELECT id FROM ${sql.identifier(table)}${whereClause}`).toArray();
50
+ return new Set(rows.map((row) => row.id));
51
+ };
52
+
53
+ export { selectShapeRows as a, selectShapeMemberIds as s };
@@ -0,0 +1,12 @@
1
+ import { renderSql } from './renderSql-D6eUcn2N.mjs';
2
+
3
+ const runSql = (sql, query, ...params) => {
4
+ const runner = sql.exec;
5
+ return runner.call(sql, query, ...params);
6
+ };
7
+ const runDrizzle = (exec, query) => {
8
+ const { params, sql: text } = renderSql("sqlite", query);
9
+ return runSql(exec, text, ...params);
10
+ };
11
+
12
+ export { runDrizzle as r };
@@ -0,0 +1,87 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
3
+
4
+ const DOC_COLUMN = "__doc__";
5
+ const quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
6
+ const jsonPath = (field) => {
7
+ if (field === "_id" || field === "id") {
8
+ return "id";
9
+ }
10
+ if (field === "_creationTime") {
11
+ return "_creationTime";
12
+ }
13
+ return `json_extract(${DOC_COLUMN}, '$.${field.replaceAll("'", "''")}')`;
14
+ };
15
+ const jsonPathSql = (field) => sql.raw(jsonPath(field));
16
+ const qualifiedJsonPath = (table, field) => {
17
+ const qualified = quoteIdentifier(table);
18
+ if (field === "_id" || field === "id") {
19
+ return `${qualified}.id`;
20
+ }
21
+ if (field === "_creationTime") {
22
+ return `${qualified}._creationTime`;
23
+ }
24
+ return `json_extract(${qualified}.${DOC_COLUMN}, '$.${field.replaceAll("'", "''")}')`;
25
+ };
26
+ const qualifiedJsonPathSql = (table, field) => sql.raw(qualifiedJsonPath(table, field));
27
+ const createIndexSql = (name, table, columns, unique) => sql`CREATE ${unique ? sql`UNIQUE ` : sql``}INDEX IF NOT EXISTS ${sql.identifier(name)} ON ${sql.identifier(table)} (${columns})`;
28
+ const AGG_KEY = sql.identifier("__key__");
29
+ const AGG_VALUE = sql.identifier("__value__");
30
+ const AGG_COUNT = sql.identifier("__count__");
31
+ const aggUpsertSql = (aggTable, key, value, count, set) => sql`INSERT INTO ${sql.identifier(aggTable)} (${AGG_KEY}, ${AGG_VALUE}, ${AGG_COUNT}) VALUES (${key}, ${value}, ${count}) ON CONFLICT(${AGG_KEY}) DO UPDATE SET ${set}`;
32
+ const tableColumns = (definition) => {
33
+ const columns = [];
34
+ for (const [field, validator] of Object.entries(definition.shape)) {
35
+ const column = validator._meta?.column;
36
+ if (column) {
37
+ columns.push([field, column]);
38
+ }
39
+ }
40
+ return columns;
41
+ };
42
+ const rowToDocument = (row) => {
43
+ if (!row) {
44
+ return void 0;
45
+ }
46
+ const raw = row[DOC_COLUMN];
47
+ let parsed;
48
+ if (typeof raw === "string") {
49
+ parsed = JSON.parse(raw);
50
+ } else if (raw && typeof raw === "object") {
51
+ parsed = raw;
52
+ } else {
53
+ parsed = {};
54
+ }
55
+ const { id } = row;
56
+ if (typeof id === "string") {
57
+ parsed["_id"] = id;
58
+ }
59
+ const creationTime = row["_creationTime"];
60
+ if (typeof creationTime === "number") {
61
+ parsed["_creationTime"] = creationTime;
62
+ }
63
+ return parsed;
64
+ };
65
+ const ftsAvailabilityCache = /* @__PURE__ */ new WeakMap();
66
+ const isFtsAvailable = (sql$1) => {
67
+ const cached = ftsAvailabilityCache.get(sql$1);
68
+ if (cached !== void 0) {
69
+ return cached;
70
+ }
71
+ let available;
72
+ try {
73
+ runDrizzle(sql$1, sql`CREATE VIRTUAL TABLE IF NOT EXISTS ${sql.identifier("__lunora_fts_probe")} USING fts5(x)`);
74
+ available = true;
75
+ } catch {
76
+ available = false;
77
+ } finally {
78
+ try {
79
+ runDrizzle(sql$1, sql`DROP TABLE IF EXISTS ${sql.identifier("__lunora_fts_probe")}`);
80
+ } catch {
81
+ }
82
+ }
83
+ ftsAvailabilityCache.set(sql$1, available);
84
+ return available;
85
+ };
86
+
87
+ export { AGG_KEY as A, DOC_COLUMN as D, AGG_VALUE as a, AGG_COUNT as b, createIndexSql as c, aggUpsertSql as d, qualifiedJsonPathSql as e, isFtsAvailable as i, jsonPathSql as j, quoteIdentifier as q, rowToDocument as r, tableColumns as t };
@@ -0,0 +1,156 @@
1
+ const DEFAULT_BATCH_SIZE = 200;
2
+ const selectExportTables = (schema, requested) => {
3
+ const isShardLocal = (table) => {
4
+ const definition = schema.tables[table];
5
+ if (!definition) {
6
+ return false;
7
+ }
8
+ return definition.shardMode?.kind !== "global";
9
+ };
10
+ if (requested && requested.length > 0) {
11
+ const filtered = [];
12
+ for (const name of requested) {
13
+ if (isShardLocal(name)) {
14
+ filtered.push(name);
15
+ }
16
+ }
17
+ return filtered;
18
+ }
19
+ const result = [];
20
+ for (const name of Object.keys(schema.tables)) {
21
+ if (isShardLocal(name)) {
22
+ result.push(name);
23
+ }
24
+ }
25
+ return result;
26
+ };
27
+ const exportShardTable = async function* (writer, table, batchSize = DEFAULT_BATCH_SIZE) {
28
+ let cursor = null;
29
+ let done = false;
30
+ while (!done) {
31
+ const page = await writer.findMany(table, { cursor, limit: batchSize });
32
+ for (const record of page.page) {
33
+ yield { doc: record, table };
34
+ }
35
+ cursor = page.continueCursor;
36
+ done = page.isDone || cursor === null;
37
+ }
38
+ };
39
+ const exportShardRows = async function* (writer, schema, args) {
40
+ const tables = selectExportTables(schema, args.tables);
41
+ const batchSize = args.batchSize ?? DEFAULT_BATCH_SIZE;
42
+ for (const table of tables) {
43
+ yield* exportShardTable(writer, table, batchSize);
44
+ }
45
+ };
46
+ const FRAMEWORK_FIELDS = /* @__PURE__ */ new Set(["_creationTime", "_id"]);
47
+ const validateAgainstShape = (definition, payload) => {
48
+ for (const [field, validator] of Object.entries(definition.shape)) {
49
+ const candidate = payload[field];
50
+ if (candidate === void 0 && validator.kind === "optional") {
51
+ continue;
52
+ }
53
+ const parser = validator.parse;
54
+ if (typeof parser !== "function") {
55
+ continue;
56
+ }
57
+ try {
58
+ parser(candidate);
59
+ } catch (error) {
60
+ const message = error instanceof Error ? error.message : String(error);
61
+ return `field "${field}": ${message}`;
62
+ }
63
+ }
64
+ return void 0;
65
+ };
66
+ const validateImportRow = (schema, table, record) => {
67
+ const definition = schema.tables[table];
68
+ if (!definition) {
69
+ return `unknown table: ${table}`;
70
+ }
71
+ if (definition.shardMode?.kind === "global") {
72
+ return `table "${table}" is a global (.global()) table and is not importable through the shard import path`;
73
+ }
74
+ const payload = Object.fromEntries(Object.entries(record).filter(([key]) => !FRAMEWORK_FIELDS.has(key)));
75
+ for (const key of Object.keys(payload)) {
76
+ if (!(key in definition.shape)) {
77
+ return `unexpected field "${key}": not declared in table "${table}"`;
78
+ }
79
+ }
80
+ return validateAgainstShape(definition, payload);
81
+ };
82
+ const idAlreadyExists = async (writer, explicitId) => {
83
+ try {
84
+ const existing = await writer.get(explicitId);
85
+ return existing !== null;
86
+ } catch {
87
+ return false;
88
+ }
89
+ };
90
+ const importOneRow = async (writer, schema, row, line) => {
91
+ const { doc, table } = row;
92
+ if (typeof table !== "string" || table.length === 0) {
93
+ return { error: { code: "BAD_ROW", line, message: "row is missing `table`", table }, kind: "error" };
94
+ }
95
+ if (!doc || typeof doc !== "object" || Array.isArray(doc)) {
96
+ return { error: { code: "BAD_ROW", line, message: "row is missing or malformed `doc`", table }, kind: "error" };
97
+ }
98
+ const failure = validateImportRow(schema, table, doc);
99
+ if (failure !== void 0) {
100
+ return { error: { code: "VALIDATION_ERROR", line, message: failure, table }, kind: "error" };
101
+ }
102
+ const explicitId = typeof doc["_id"] === "string" ? doc["_id"] : void 0;
103
+ if (explicitId !== void 0 && await idAlreadyExists(writer, explicitId)) {
104
+ return { kind: "conflict" };
105
+ }
106
+ try {
107
+ await writer.insert(table, doc, { allowExplicitId: true });
108
+ return { kind: "inserted", table };
109
+ } catch (error) {
110
+ const code = error.code ?? "INSERT_FAILED";
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ return { error: { code, line, message, table }, kind: "error" };
113
+ }
114
+ };
115
+ const importShardRows = async (writer, schema, args) => {
116
+ const errors = [];
117
+ const inserted = {};
118
+ let conflicts = 0;
119
+ let line = (args.startLine ?? 1) - 1;
120
+ for (const row of args.rows) {
121
+ line += 1;
122
+ const outcome = await importOneRow(writer, schema, row, line);
123
+ if (outcome.kind === "error") {
124
+ errors.push(outcome.error);
125
+ } else if (outcome.kind === "conflict") {
126
+ conflicts += 1;
127
+ } else {
128
+ inserted[outcome.table] = (inserted[outcome.table] ?? 0) + 1;
129
+ }
130
+ }
131
+ return { conflicts, errors, inserted };
132
+ };
133
+ const parseExportShardArgs = (args) => {
134
+ const tables = Array.isArray(args["tables"]) ? args["tables"].filter((entry) => typeof entry === "string") : void 0;
135
+ const batchSize = typeof args["batchSize"] === "number" ? args["batchSize"] : void 0;
136
+ return { batchSize, tables };
137
+ };
138
+ const parseImportShardArgs = (args) => {
139
+ const rawRows = Array.isArray(args["rows"]) ? args["rows"] : [];
140
+ const rows = [];
141
+ for (const entry of rawRows) {
142
+ if (!entry || typeof entry !== "object") {
143
+ continue;
144
+ }
145
+ const candidate = entry;
146
+ if (typeof candidate.table !== "string" || !candidate.doc || typeof candidate.doc !== "object" || Array.isArray(candidate.doc)) {
147
+ rows.push({ doc: candidate.doc ?? {}, table: typeof candidate.table === "string" ? candidate.table : "" });
148
+ continue;
149
+ }
150
+ rows.push({ doc: candidate.doc, table: candidate.table });
151
+ }
152
+ const startLine = typeof args["startLine"] === "number" ? args["startLine"] : void 0;
153
+ return { rows, startLine };
154
+ };
155
+
156
+ export { exportShardRows, exportShardTable, importShardRows, parseExportShardArgs, parseImportShardArgs, selectExportTables, validateImportRow };
@@ -0,0 +1,20 @@
1
+ const runTriggers = async (options) => {
2
+ const definitions = options.schema.tables[options.tableName]?.triggerMap;
3
+ if (!definitions) {
4
+ return;
5
+ }
6
+ for (const definition of Object.values(definitions)) {
7
+ if (definition.timing === options.timing && definition.op === options.op) {
8
+ await definition.handler(options.ctx, options.event);
9
+ }
10
+ }
11
+ };
12
+ const hasTrigger = (schema, tableName, op) => {
13
+ const definitions = schema.tables[tableName]?.triggerMap;
14
+ if (!definitions) {
15
+ return false;
16
+ }
17
+ return Object.values(definitions).some((definition) => definition.op === op);
18
+ };
19
+
20
+ export { hasTrigger, runTriggers };
@@ -0,0 +1,16 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { MySqlDialect } from 'drizzle-orm/mysql-core';
3
+ import { PgDialect } from 'drizzle-orm/pg-core';
4
+ import { SQLiteSyncDialect } from 'drizzle-orm/sqlite-core';
5
+
6
+ const PG_DIALECT = new PgDialect();
7
+ const MYSQL_DIALECT = new MySqlDialect();
8
+ const SQLITE_DIALECT = new SQLiteSyncDialect();
9
+ const DIALECTS = { mysql: MYSQL_DIALECT, postgres: PG_DIALECT, sqlite: SQLITE_DIALECT };
10
+ const renderSql = (engine, query) => {
11
+ const { params, sql: text } = DIALECTS[engine].sqlToQuery(query);
12
+ return { params, sql: text };
13
+ };
14
+ const param = (value) => sql`${value}`;
15
+
16
+ export { param, renderSql };
@@ -0,0 +1,105 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { aggregateTableName } from './aggregateTableName-CxNqY1Sl.mjs';
3
+ import { migrateCdcLog, migrateCdcMeta } from './CDC_LOG_TABLE-DSycmnDf.mjs';
4
+ import { m as migrateClientWatermark, a as migrateIdempotency, b as migrateGlobalShapeSnapshot } from './ctx-db-idempotency-BdcNpvY4.mjs';
5
+ import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
6
+ import { D as DOC_COLUMN, j as jsonPathSql, c as createIndexSql, t as tableColumns, i as isFtsAvailable, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT } from './do-sql-BCHCWtrD.mjs';
7
+ import { sortColumnName, rankTableName } from './RANK_TIEBREAK-CXhdcA1o.mjs';
8
+ import { ftsTableName } from './buildFtsMatch-BLEMawrp.mjs';
9
+
10
+ const migrateSecondaryIndexes = (sql$1, tableName, definition) => {
11
+ for (const index of definition.indexes) {
12
+ const indexName = `${tableName}_${index.name}`;
13
+ const expressions = sql.join(
14
+ index.fields.map((field) => jsonPathSql(field)),
15
+ sql`, `
16
+ );
17
+ runDrizzle(sql$1, createIndexSql(indexName, tableName, expressions, index.unique ?? false));
18
+ }
19
+ for (const [field, column] of tableColumns(definition)) {
20
+ if (!column.unique) {
21
+ continue;
22
+ }
23
+ const indexName = `${tableName}_unique_${field}`;
24
+ runDrizzle(sql$1, createIndexSql(indexName, tableName, jsonPathSql(field), true));
25
+ }
26
+ };
27
+ const migrateSearchIndexes = (sql$1, tableName, definition) => {
28
+ if (!definition.searchIndexes || definition.searchIndexes.length === 0 || !isFtsAvailable(sql$1)) {
29
+ return;
30
+ }
31
+ for (const index of definition.searchIndexes) {
32
+ const ftName = ftsTableName(tableName, index.name);
33
+ runDrizzle(
34
+ sql$1,
35
+ sql`CREATE VIRTUAL TABLE IF NOT EXISTS ${sql.identifier(ftName)} USING fts5(${sql.identifier("__text__")}, ${sql.identifier("__id__")} UNINDEXED)`
36
+ );
37
+ }
38
+ };
39
+ const migrateAggregateIndexes = (sql$1, tableName, definition) => {
40
+ if (!definition.aggregateIndexes) {
41
+ return;
42
+ }
43
+ for (const index of definition.aggregateIndexes) {
44
+ const aggTable = aggregateTableName(tableName, index.name);
45
+ runDrizzle(
46
+ sql$1,
47
+ sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(aggTable)} (${AGG_KEY} TEXT PRIMARY KEY, ${AGG_VALUE} REAL, ${AGG_COUNT} INTEGER NOT NULL DEFAULT 0)`
48
+ );
49
+ const columns = runDrizzle(sql$1, sql`PRAGMA table_info(${sql.identifier(aggTable)})`).toArray();
50
+ if (!columns.some((column) => column.name === "__count__")) {
51
+ runDrizzle(sql$1, sql`ALTER TABLE ${sql.identifier(aggTable)} ADD COLUMN ${AGG_COUNT} INTEGER NOT NULL DEFAULT 0`);
52
+ }
53
+ }
54
+ };
55
+ const migrateRankIndexes = (sql$1, tableName, definition) => {
56
+ if (!definition.rankIndexes) {
57
+ return;
58
+ }
59
+ for (const index of definition.rankIndexes) {
60
+ const rankTable = rankTableName(tableName, index.name);
61
+ const sortColumns = index.sortBy.map((_, i) => sortColumnName(i));
62
+ const columnDdls = sortColumns.map((column) => sql`${sql.identifier(column)} BLOB`);
63
+ const columnPart = columnDdls.length > 0 ? sql`, ${sql.join(columnDdls, sql`, `)}` : sql``;
64
+ runDrizzle(
65
+ sql$1,
66
+ sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(rankTable)} (${sql.identifier("__id__")} TEXT PRIMARY KEY, ${sql.identifier("__partition__")} TEXT NOT NULL${columnPart})`
67
+ );
68
+ const orderedColumns = [sql`${sql.identifier("__partition__")} ASC`];
69
+ for (const [i, column] of sortColumns.entries()) {
70
+ const direction = index.sortBy[i]?.direction;
71
+ orderedColumns.push(sql`${sql.identifier(column)} ${sql.raw(direction === "desc" ? "DESC" : "ASC")}`);
72
+ }
73
+ orderedColumns.push(sql`${sql.identifier("__id__")} ASC`);
74
+ const btreeName = `${tableName}__rank_${index.name}__btree`;
75
+ runDrizzle(sql$1, createIndexSql(btreeName, rankTable, sql.join(orderedColumns, sql`, `), false));
76
+ }
77
+ };
78
+ const runShardMigrations = (sql$1, schema, options = {}) => {
79
+ for (const [tableName, definition] of Object.entries(schema.tables)) {
80
+ if (definition.shardMode?.kind === "global") {
81
+ continue;
82
+ }
83
+ runDrizzle(
84
+ sql$1,
85
+ sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(tableName)} (
86
+ id TEXT PRIMARY KEY,
87
+ _creationTime REAL NOT NULL,
88
+ ${sql.identifier(DOC_COLUMN)} TEXT NOT NULL
89
+ )`
90
+ );
91
+ migrateSecondaryIndexes(sql$1, tableName, definition);
92
+ migrateSearchIndexes(sql$1, tableName, definition);
93
+ migrateAggregateIndexes(sql$1, tableName, definition);
94
+ migrateRankIndexes(sql$1, tableName, definition);
95
+ }
96
+ if (options.cdc) {
97
+ migrateCdcLog(sql$1);
98
+ migrateCdcMeta(sql$1);
99
+ migrateClientWatermark(sql$1);
100
+ }
101
+ migrateIdempotency(sql$1);
102
+ migrateGlobalShapeSnapshot(sql$1);
103
+ };
104
+
105
+ export { runShardMigrations };