@korajs/core 1.0.0-beta.1 → 1.0.0-beta.11
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/bindings/index.cjs.map +1 -1
- package/dist/bindings/index.d.cts +23 -4
- package/dist/bindings/index.d.ts +23 -4
- package/dist/{build-scope-map-DtTr9C7A.d.cts → build-scope-map--0H8l6Tw.d.cts} +1 -1
- package/dist/{build-scope-map-DvOHbYjn.d.ts → build-scope-map-B3R_emUU.d.ts} +1 -1
- package/dist/{events-CqDkr1LN.d.cts → events-BPbYUbrE.d.cts} +93 -1
- package/dist/{events-CqDkr1LN.d.ts → events-BPbYUbrE.d.ts} +93 -1
- package/dist/index.cjs +129 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -6
- package/dist/index.d.ts +86 -6
- package/dist/index.js +126 -36
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/{operation-CFoY-ZmB.d.cts → operation-DbynlVcp.d.cts} +1 -1
- package/dist/{operation-BJtu18Fi.d.ts → operation-Dt0AtT8u.d.ts} +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
StorageError: () => StorageError,
|
|
47
47
|
SyncError: () => SyncError,
|
|
48
48
|
advanceVector: () => advanceVector,
|
|
49
|
+
applyAtomicOp: () => applyAtomicOp,
|
|
49
50
|
applyOperationTransforms: () => applyOperationTransforms,
|
|
50
51
|
base64ToBytes: () => base64ToBytes,
|
|
51
52
|
buildScopeMap: () => buildScopeMap,
|
|
@@ -94,6 +95,8 @@ __export(index_exports, {
|
|
|
94
95
|
migrate: () => migrate,
|
|
95
96
|
migrationStepsToSQL: () => migrationStepsToSQL,
|
|
96
97
|
op: () => op,
|
|
98
|
+
quoteIdent: () => quoteIdent,
|
|
99
|
+
replayOperationsForRecord: () => replayOperationsForRecord,
|
|
97
100
|
resolveAtomicOp: () => resolveAtomicOp,
|
|
98
101
|
revealSecret: () => revealSecret,
|
|
99
102
|
rollbackStepsToSQL: () => rollbackStepsToSQL,
|
|
@@ -967,32 +970,36 @@ var KORA_ATOMIC_OP = /* @__PURE__ */ Symbol.for("kora.atomic_op");
|
|
|
967
970
|
function isAtomicOp(value) {
|
|
968
971
|
return typeof value === "object" && value !== null && KORA_ATOMIC_OP in value && value[KORA_ATOMIC_OP] === true;
|
|
969
972
|
}
|
|
970
|
-
function
|
|
971
|
-
switch (
|
|
973
|
+
function applyAtomicOp(currentValue, atomicOp) {
|
|
974
|
+
switch (atomicOp.type) {
|
|
972
975
|
case "increment": {
|
|
973
976
|
const current = typeof currentValue === "number" ? currentValue : 0;
|
|
974
|
-
const operand =
|
|
977
|
+
const operand = atomicOp.value;
|
|
975
978
|
return current + operand;
|
|
976
979
|
}
|
|
977
980
|
case "max": {
|
|
978
981
|
const current = typeof currentValue === "number" ? currentValue : Number.NEGATIVE_INFINITY;
|
|
979
|
-
return Math.max(current,
|
|
982
|
+
return Math.max(current, atomicOp.value);
|
|
980
983
|
}
|
|
981
984
|
case "min": {
|
|
982
985
|
const current = typeof currentValue === "number" ? currentValue : Number.POSITIVE_INFINITY;
|
|
983
|
-
return Math.min(current,
|
|
986
|
+
return Math.min(current, atomicOp.value);
|
|
984
987
|
}
|
|
985
988
|
case "append": {
|
|
986
989
|
const current = Array.isArray(currentValue) ? [...currentValue] : [];
|
|
987
|
-
current.push(
|
|
990
|
+
current.push(atomicOp.value);
|
|
988
991
|
return current;
|
|
989
992
|
}
|
|
990
993
|
case "remove": {
|
|
991
994
|
if (!Array.isArray(currentValue)) return [];
|
|
992
|
-
|
|
995
|
+
const target = JSON.stringify(atomicOp.value);
|
|
996
|
+
return currentValue.filter((item) => JSON.stringify(item) !== target);
|
|
993
997
|
}
|
|
994
998
|
}
|
|
995
999
|
}
|
|
1000
|
+
function resolveAtomicOp(currentValue, sentinel) {
|
|
1001
|
+
return applyAtomicOp(currentValue, { type: sentinel.type, value: sentinel.value });
|
|
1002
|
+
}
|
|
996
1003
|
function createSentinel(type, value) {
|
|
997
1004
|
return Object.freeze({
|
|
998
1005
|
[KORA_ATOMIC_OP]: true,
|
|
@@ -1060,6 +1067,46 @@ function toAtomicOp(sentinel) {
|
|
|
1060
1067
|
return { type: sentinel.type, value: sentinel.value };
|
|
1061
1068
|
}
|
|
1062
1069
|
|
|
1070
|
+
// src/operations/replay-record.ts
|
|
1071
|
+
function replayOperationsForRecord(ops) {
|
|
1072
|
+
let record = null;
|
|
1073
|
+
let deleted = false;
|
|
1074
|
+
const lastWriterKind = {};
|
|
1075
|
+
for (const op2 of ops) {
|
|
1076
|
+
switch (op2.type) {
|
|
1077
|
+
case "insert":
|
|
1078
|
+
if (op2.data) {
|
|
1079
|
+
record = { ...op2.data };
|
|
1080
|
+
deleted = false;
|
|
1081
|
+
for (const field of Object.keys(op2.data)) {
|
|
1082
|
+
lastWriterKind[field] = "lww";
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
break;
|
|
1086
|
+
case "update":
|
|
1087
|
+
if (op2.data) {
|
|
1088
|
+
const next = { ...record ?? {} };
|
|
1089
|
+
for (const [field, value] of Object.entries(op2.data)) {
|
|
1090
|
+
const atomicOp = op2.atomicOps?.[field];
|
|
1091
|
+
if (atomicOp && lastWriterKind[field] === `atomic:${atomicOp.type}`) {
|
|
1092
|
+
next[field] = applyAtomicOp(next[field], atomicOp);
|
|
1093
|
+
} else {
|
|
1094
|
+
next[field] = value;
|
|
1095
|
+
}
|
|
1096
|
+
lastWriterKind[field] = atomicOp ? `atomic:${atomicOp.type}` : "lww";
|
|
1097
|
+
}
|
|
1098
|
+
record = next;
|
|
1099
|
+
deleted = false;
|
|
1100
|
+
}
|
|
1101
|
+
break;
|
|
1102
|
+
case "delete":
|
|
1103
|
+
deleted = true;
|
|
1104
|
+
break;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return deleted ? null : record;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1063
1110
|
// src/operations/op-data-binary.ts
|
|
1064
1111
|
function isKoraBytesValue(value) {
|
|
1065
1112
|
if (typeof value !== "object" || value === null) {
|
|
@@ -1310,7 +1357,7 @@ function validateStateMachineDefinition(collectionName, sm, fields) {
|
|
|
1310
1357
|
}
|
|
1311
1358
|
|
|
1312
1359
|
// src/schema/define.ts
|
|
1313
|
-
var COLLECTION_NAME_RE = /^[
|
|
1360
|
+
var COLLECTION_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
1314
1361
|
var FIELD_NAME_RE = /^[a-z][a-zA-Z0-9_]*$/;
|
|
1315
1362
|
var RESERVED_FIELDS = /* @__PURE__ */ new Set(["id", "_created_at", "_updated_at", "_version", "_deleted"]);
|
|
1316
1363
|
function defineSchema(input) {
|
|
@@ -1375,7 +1422,7 @@ function validateVersion(version) {
|
|
|
1375
1422
|
function validateCollectionName(name) {
|
|
1376
1423
|
if (!COLLECTION_NAME_RE.test(name)) {
|
|
1377
1424
|
throw new SchemaValidationError(
|
|
1378
|
-
`Collection name "${name}" is invalid. Must
|
|
1425
|
+
`Collection name "${name}" is invalid. Must start with a letter and contain only letters, numbers, and underscores.`,
|
|
1379
1426
|
{ collection: name }
|
|
1380
1427
|
);
|
|
1381
1428
|
}
|
|
@@ -1567,6 +1614,11 @@ function validateRelation(name, relation, collections) {
|
|
|
1567
1614
|
}
|
|
1568
1615
|
}
|
|
1569
1616
|
|
|
1617
|
+
// src/schema/quote-ident.ts
|
|
1618
|
+
function quoteIdent(name) {
|
|
1619
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1570
1622
|
// src/schema/sql-gen.ts
|
|
1571
1623
|
function generateSQL(collectionName, collection, relations) {
|
|
1572
1624
|
const statements = [];
|
|
@@ -1578,7 +1630,7 @@ function generateSQL(collectionName, collection, relations) {
|
|
|
1578
1630
|
if (relations) {
|
|
1579
1631
|
for (const rel of Object.values(relations)) {
|
|
1580
1632
|
if (rel.from === collectionName && rel.field === fieldName) {
|
|
1581
|
-
colDef += ` REFERENCES ${rel.to}(id)`;
|
|
1633
|
+
colDef += ` REFERENCES ${quoteIdent(rel.to)}(id)`;
|
|
1582
1634
|
fkFields.push(fieldName);
|
|
1583
1635
|
break;
|
|
1584
1636
|
}
|
|
@@ -1591,36 +1643,40 @@ function generateSQL(collectionName, collection, relations) {
|
|
|
1591
1643
|
columns.push("_version TEXT NOT NULL DEFAULT ''");
|
|
1592
1644
|
columns.push("_field_versions TEXT NOT NULL DEFAULT '{}'");
|
|
1593
1645
|
columns.push("_deleted INTEGER NOT NULL DEFAULT 0");
|
|
1594
|
-
statements.push(
|
|
1646
|
+
statements.push(
|
|
1647
|
+
`CREATE TABLE IF NOT EXISTS ${quoteIdent(collectionName)} (
|
|
1595
1648
|
${columns.join(",\n ")}
|
|
1596
|
-
)`
|
|
1649
|
+
)`
|
|
1650
|
+
);
|
|
1597
1651
|
for (const [fieldName, descriptor] of Object.entries(collection.fields)) {
|
|
1598
1652
|
const colDef = columnDefinition(fieldName, descriptor);
|
|
1599
|
-
statements.push(
|
|
1600
|
-
|
|
1653
|
+
statements.push(
|
|
1654
|
+
`--kora:safe-alter
|
|
1655
|
+
ALTER TABLE ${quoteIdent(collectionName)} ADD COLUMN ${colDef}`
|
|
1656
|
+
);
|
|
1601
1657
|
}
|
|
1602
1658
|
statements.push(
|
|
1603
1659
|
`--kora:safe-alter
|
|
1604
|
-
ALTER TABLE ${collectionName} ADD COLUMN _version TEXT NOT NULL DEFAULT ''`
|
|
1660
|
+
ALTER TABLE ${quoteIdent(collectionName)} ADD COLUMN _version TEXT NOT NULL DEFAULT ''`
|
|
1605
1661
|
);
|
|
1606
1662
|
statements.push(
|
|
1607
1663
|
`--kora:safe-alter
|
|
1608
|
-
ALTER TABLE ${collectionName} ADD COLUMN _field_versions TEXT NOT NULL DEFAULT '{}'`
|
|
1664
|
+
ALTER TABLE ${quoteIdent(collectionName)} ADD COLUMN _field_versions TEXT NOT NULL DEFAULT '{}'`
|
|
1609
1665
|
);
|
|
1610
1666
|
for (const indexField of collection.indexes) {
|
|
1611
1667
|
statements.push(
|
|
1612
|
-
`CREATE INDEX IF NOT EXISTS idx_${collectionName}_${indexField} ON ${collectionName} (${indexField})`
|
|
1668
|
+
`CREATE INDEX IF NOT EXISTS idx_${collectionName}_${indexField} ON ${quoteIdent(collectionName)} (${quoteIdent(indexField)})`
|
|
1613
1669
|
);
|
|
1614
1670
|
}
|
|
1615
1671
|
for (const fkField of fkFields) {
|
|
1616
1672
|
if (!indexedFields.has(fkField)) {
|
|
1617
1673
|
statements.push(
|
|
1618
|
-
`CREATE INDEX IF NOT EXISTS idx_${collectionName}_${fkField} ON ${collectionName} (${fkField})`
|
|
1674
|
+
`CREATE INDEX IF NOT EXISTS idx_${collectionName}_${fkField} ON ${quoteIdent(collectionName)} (${quoteIdent(fkField)})`
|
|
1619
1675
|
);
|
|
1620
1676
|
}
|
|
1621
1677
|
}
|
|
1622
1678
|
statements.push(
|
|
1623
|
-
`CREATE TABLE IF NOT EXISTS _kora_ops_${collectionName} (
|
|
1679
|
+
`CREATE TABLE IF NOT EXISTS ${quoteIdent(`_kora_ops_${collectionName}`)} (
|
|
1624
1680
|
id TEXT PRIMARY KEY NOT NULL,
|
|
1625
1681
|
node_id TEXT NOT NULL,
|
|
1626
1682
|
type TEXT NOT NULL,
|
|
@@ -1634,7 +1690,7 @@ ALTER TABLE ${collectionName} ADD COLUMN _field_versions TEXT NOT NULL DEFAULT '
|
|
|
1634
1690
|
)`
|
|
1635
1691
|
);
|
|
1636
1692
|
statements.push(
|
|
1637
|
-
`CREATE INDEX IF NOT EXISTS idx_kora_ops_${collectionName}_record_id ON _kora_ops_${collectionName} (record_id)`
|
|
1693
|
+
`CREATE INDEX IF NOT EXISTS idx_kora_ops_${collectionName}_record_id ON ${quoteIdent(`_kora_ops_${collectionName}`)} (record_id)`
|
|
1638
1694
|
);
|
|
1639
1695
|
return statements;
|
|
1640
1696
|
}
|
|
@@ -1652,6 +1708,9 @@ function generateFullDDL(schema) {
|
|
|
1652
1708
|
statements.push(
|
|
1653
1709
|
"CREATE TABLE IF NOT EXISTS _kora_sync_queue (\n id TEXT PRIMARY KEY NOT NULL,\n payload TEXT NOT NULL\n)"
|
|
1654
1710
|
);
|
|
1711
|
+
statements.push(
|
|
1712
|
+
"CREATE TABLE IF NOT EXISTS _kora_sync_rejected (\n operation_id TEXT PRIMARY KEY NOT NULL,\n collection TEXT NOT NULL,\n record_id TEXT NOT NULL,\n code TEXT NOT NULL,\n message TEXT NOT NULL,\n retriable INTEGER NOT NULL,\n rejected_at INTEGER NOT NULL\n)"
|
|
1713
|
+
);
|
|
1655
1714
|
statements.push(
|
|
1656
1715
|
"CREATE TABLE IF NOT EXISTS _kora_audit_traces (\n id TEXT PRIMARY KEY NOT NULL,\n recorded_at INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n collection TEXT NOT NULL,\n record_id TEXT NOT NULL,\n field TEXT NOT NULL,\n strategy TEXT NOT NULL,\n tier INTEGER NOT NULL,\n constraint_name TEXT,\n trace_json TEXT NOT NULL\n)"
|
|
1657
1716
|
);
|
|
@@ -1668,7 +1727,7 @@ function generateFullDDL(schema) {
|
|
|
1668
1727
|
}
|
|
1669
1728
|
function columnDefinition(fieldName, descriptor) {
|
|
1670
1729
|
const sqlType = mapFieldType(descriptor);
|
|
1671
|
-
const parts = [fieldName, sqlType];
|
|
1730
|
+
const parts = [quoteIdent(fieldName), sqlType];
|
|
1672
1731
|
if (descriptor.required && descriptor.defaultValue === void 0 && !descriptor.auto) {
|
|
1673
1732
|
parts.push("NOT NULL");
|
|
1674
1733
|
}
|
|
@@ -1677,7 +1736,7 @@ function columnDefinition(fieldName, descriptor) {
|
|
|
1677
1736
|
}
|
|
1678
1737
|
if (descriptor.kind === "enum" && descriptor.enumValues) {
|
|
1679
1738
|
const values = descriptor.enumValues.map((v) => `'${v}'`).join(", ");
|
|
1680
|
-
parts.push(`CHECK (${fieldName} IN (${values}))`);
|
|
1739
|
+
parts.push(`CHECK (${quoteIdent(fieldName)} IN (${values}))`);
|
|
1681
1740
|
}
|
|
1682
1741
|
return parts.join(" ");
|
|
1683
1742
|
}
|
|
@@ -2319,10 +2378,17 @@ function validateFieldValue(collection, fieldName, descriptor, value) {
|
|
|
2319
2378
|
break;
|
|
2320
2379
|
}
|
|
2321
2380
|
case "json": {
|
|
2322
|
-
|
|
2381
|
+
const nonJson = findNonJsonSerializable(value, fieldName);
|
|
2382
|
+
if (nonJson) {
|
|
2323
2383
|
throw new SchemaValidationError(
|
|
2324
|
-
`Field "${fieldName}" in collection "${collection}" must be JSON-serializable
|
|
2325
|
-
{
|
|
2384
|
+
`Field "${fieldName}" in collection "${collection}" must be JSON-serializable; found ${nonJson.receivedType} at "${nonJson.path}"`,
|
|
2385
|
+
{
|
|
2386
|
+
collection,
|
|
2387
|
+
field: fieldName,
|
|
2388
|
+
expectedType: "json",
|
|
2389
|
+
receivedType: nonJson.receivedType,
|
|
2390
|
+
path: nonJson.path
|
|
2391
|
+
}
|
|
2326
2392
|
);
|
|
2327
2393
|
}
|
|
2328
2394
|
break;
|
|
@@ -2359,21 +2425,41 @@ function isPlainObject(value) {
|
|
|
2359
2425
|
const proto = Object.getPrototypeOf(value);
|
|
2360
2426
|
return proto === null || proto === Object.prototype;
|
|
2361
2427
|
}
|
|
2362
|
-
function
|
|
2428
|
+
function findNonJsonSerializable(value, path, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2363
2429
|
if (value === null) {
|
|
2364
|
-
return
|
|
2430
|
+
return null;
|
|
2365
2431
|
}
|
|
2366
2432
|
const type = typeof value;
|
|
2367
2433
|
if (type === "string" || type === "number" || type === "boolean") {
|
|
2368
|
-
|
|
2434
|
+
if (type === "number" && !Number.isFinite(value)) {
|
|
2435
|
+
return { path, receivedType: describeType(value) };
|
|
2436
|
+
}
|
|
2437
|
+
return null;
|
|
2438
|
+
}
|
|
2439
|
+
if (type === "undefined" || type === "function" || type === "symbol" || type === "bigint") {
|
|
2440
|
+
return { path, receivedType: describeType(value) };
|
|
2369
2441
|
}
|
|
2370
2442
|
if (Array.isArray(value)) {
|
|
2371
|
-
|
|
2443
|
+
for (let index = 0; index < value.length; index++) {
|
|
2444
|
+
const invalid = findNonJsonSerializable(value[index], `${path}[${index}]`, seen);
|
|
2445
|
+
if (invalid) return invalid;
|
|
2446
|
+
}
|
|
2447
|
+
return null;
|
|
2372
2448
|
}
|
|
2373
2449
|
if (type === "object") {
|
|
2374
|
-
|
|
2450
|
+
const objectValue = value;
|
|
2451
|
+
if (seen.has(objectValue)) {
|
|
2452
|
+
return { path, receivedType: "circular object" };
|
|
2453
|
+
}
|
|
2454
|
+
seen.add(objectValue);
|
|
2455
|
+
for (const [key, nestedValue] of Object.entries(objectValue)) {
|
|
2456
|
+
const invalid = findNonJsonSerializable(nestedValue, `${path}.${key}`, seen);
|
|
2457
|
+
if (invalid) return invalid;
|
|
2458
|
+
}
|
|
2459
|
+
seen.delete(objectValue);
|
|
2460
|
+
return null;
|
|
2375
2461
|
}
|
|
2376
|
-
return
|
|
2462
|
+
return { path, receivedType: describeType(value) };
|
|
2377
2463
|
}
|
|
2378
2464
|
function describeType(value) {
|
|
2379
2465
|
if (value === null) {
|
|
@@ -2932,14 +3018,18 @@ function migrationStepsToSQL(steps) {
|
|
|
2932
3018
|
statements.push(addFieldSQL(step.collection, step.field, step.descriptor));
|
|
2933
3019
|
break;
|
|
2934
3020
|
case "removeField":
|
|
2935
|
-
statements.push(
|
|
3021
|
+
statements.push(
|
|
3022
|
+
`ALTER TABLE ${quoteIdent(step.collection)} DROP COLUMN ${quoteIdent(step.field)}`
|
|
3023
|
+
);
|
|
2936
3024
|
break;
|
|
2937
3025
|
case "renameField":
|
|
2938
|
-
statements.push(
|
|
3026
|
+
statements.push(
|
|
3027
|
+
`ALTER TABLE ${quoteIdent(step.collection)} RENAME COLUMN ${quoteIdent(step.from)} TO ${quoteIdent(step.to)}`
|
|
3028
|
+
);
|
|
2939
3029
|
break;
|
|
2940
3030
|
case "addIndex":
|
|
2941
3031
|
statements.push(
|
|
2942
|
-
`CREATE INDEX IF NOT EXISTS idx_${step.collection}_${step.field} ON ${step.collection} (${step.field})`
|
|
3032
|
+
`CREATE INDEX IF NOT EXISTS idx_${step.collection}_${step.field} ON ${quoteIdent(step.collection)} (${quoteIdent(step.field)})`
|
|
2943
3033
|
);
|
|
2944
3034
|
break;
|
|
2945
3035
|
case "removeIndex":
|
|
@@ -2957,13 +3047,13 @@ function rollbackStepsToSQL(migration) {
|
|
|
2957
3047
|
}
|
|
2958
3048
|
function addFieldSQL(collection, field, descriptor) {
|
|
2959
3049
|
const sqlType = mapFieldType2(descriptor);
|
|
2960
|
-
const parts = [`ALTER TABLE ${collection} ADD COLUMN ${field}`, sqlType];
|
|
3050
|
+
const parts = [`ALTER TABLE ${quoteIdent(collection)} ADD COLUMN ${quoteIdent(field)}`, sqlType];
|
|
2961
3051
|
if (descriptor.defaultValue !== void 0) {
|
|
2962
3052
|
parts.push(`DEFAULT ${sqlDefault2(descriptor.defaultValue)}`);
|
|
2963
3053
|
}
|
|
2964
3054
|
if (descriptor.kind === "enum" && descriptor.enumValues) {
|
|
2965
3055
|
const values = descriptor.enumValues.map((v) => `'${v}'`).join(", ");
|
|
2966
|
-
parts.push(`CHECK (${field} IN (${values}))`);
|
|
3056
|
+
parts.push(`CHECK (${quoteIdent(field)} IN (${values}))`);
|
|
2967
3057
|
}
|
|
2968
3058
|
return parts.join(" ");
|
|
2969
3059
|
}
|
|
@@ -3266,6 +3356,7 @@ function generateProtoDefinitions(schema) {
|
|
|
3266
3356
|
StorageError,
|
|
3267
3357
|
SyncError,
|
|
3268
3358
|
advanceVector,
|
|
3359
|
+
applyAtomicOp,
|
|
3269
3360
|
applyOperationTransforms,
|
|
3270
3361
|
base64ToBytes,
|
|
3271
3362
|
buildScopeMap,
|
|
@@ -3314,6 +3405,8 @@ function generateProtoDefinitions(schema) {
|
|
|
3314
3405
|
migrate,
|
|
3315
3406
|
migrationStepsToSQL,
|
|
3316
3407
|
op,
|
|
3408
|
+
quoteIdent,
|
|
3409
|
+
replayOperationsForRecord,
|
|
3317
3410
|
resolveAtomicOp,
|
|
3318
3411
|
revealSecret,
|
|
3319
3412
|
rollbackStepsToSQL,
|