@onyx.dev/onyx-database 0.3.0 → 1.0.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/README.md +42 -1
- package/dist/gen/cli/generate.cjs +87 -14
- package/dist/gen/cli/generate.cjs.map +1 -1
- package/dist/index.cjs +103 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +102 -21
- package/dist/index.js.map +1 -1
- package/dist/schema/cli/schema.cjs +308 -15
- package/dist/schema/cli/schema.cjs.map +1 -1
- package/package.json +1 -1
|
@@ -842,6 +842,56 @@ var QueryResults = class extends Array {
|
|
|
842
842
|
}
|
|
843
843
|
};
|
|
844
844
|
|
|
845
|
+
// src/helpers/condition-normalizer.ts
|
|
846
|
+
function isQueryBuilderLike(value) {
|
|
847
|
+
return !!value && typeof value.toSerializableQueryObject === "function";
|
|
848
|
+
}
|
|
849
|
+
function normalizeCriteriaValue(value) {
|
|
850
|
+
if (Array.isArray(value)) {
|
|
851
|
+
let changed = false;
|
|
852
|
+
const normalized = value.map((item) => {
|
|
853
|
+
const result = normalizeCriteriaValue(item);
|
|
854
|
+
if (result.changed) changed = true;
|
|
855
|
+
return result.value;
|
|
856
|
+
});
|
|
857
|
+
if (!changed) {
|
|
858
|
+
for (let i = 0; i < normalized.length; i += 1) {
|
|
859
|
+
if (normalized[i] !== value[i]) {
|
|
860
|
+
changed = true;
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return { value: changed ? normalized : value, changed };
|
|
866
|
+
}
|
|
867
|
+
if (isQueryBuilderLike(value)) {
|
|
868
|
+
return { value: value.toSerializableQueryObject(), changed: true };
|
|
869
|
+
}
|
|
870
|
+
return { value, changed: false };
|
|
871
|
+
}
|
|
872
|
+
function normalizeConditionInternal(condition) {
|
|
873
|
+
if (condition.conditionType === "SingleCondition") {
|
|
874
|
+
const { value, changed: changed2 } = normalizeCriteriaValue(condition.criteria.value);
|
|
875
|
+
if (!changed2) return condition;
|
|
876
|
+
return {
|
|
877
|
+
...condition,
|
|
878
|
+
criteria: { ...condition.criteria, value }
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
let changed = false;
|
|
882
|
+
const normalizedConditions = condition.conditions.map((child) => {
|
|
883
|
+
const normalized = normalizeConditionInternal(child);
|
|
884
|
+
if (normalized !== child) changed = true;
|
|
885
|
+
return normalized;
|
|
886
|
+
});
|
|
887
|
+
if (!changed) return condition;
|
|
888
|
+
return { ...condition, conditions: normalizedConditions };
|
|
889
|
+
}
|
|
890
|
+
function normalizeCondition(condition) {
|
|
891
|
+
if (!condition) return condition;
|
|
892
|
+
return normalizeConditionInternal(condition);
|
|
893
|
+
}
|
|
894
|
+
|
|
845
895
|
// src/builders/cascade-relationship-builder.ts
|
|
846
896
|
var CascadeRelationshipBuilder = class {
|
|
847
897
|
graphName;
|
|
@@ -969,6 +1019,10 @@ function serializeDates(value) {
|
|
|
969
1019
|
}
|
|
970
1020
|
return value;
|
|
971
1021
|
}
|
|
1022
|
+
function stripEntityText(input) {
|
|
1023
|
+
const { entityText, ...rest } = input;
|
|
1024
|
+
return rest;
|
|
1025
|
+
}
|
|
972
1026
|
function normalizeSecretMetadata(input) {
|
|
973
1027
|
return { ...input, updatedAt: new Date(input.updatedAt) };
|
|
974
1028
|
}
|
|
@@ -982,7 +1036,7 @@ function normalizeDate(value) {
|
|
|
982
1036
|
return Number.isNaN(ts.getTime()) ? void 0 : ts;
|
|
983
1037
|
}
|
|
984
1038
|
function normalizeSchemaRevision(input, fallbackDatabaseId) {
|
|
985
|
-
const { meta, createdAt, publishedAt, revisionId, ...rest } = input;
|
|
1039
|
+
const { meta, createdAt, publishedAt, revisionId, entityText, ...rest } = input;
|
|
986
1040
|
const mergedMeta = {
|
|
987
1041
|
revisionId: meta?.revisionId ?? revisionId,
|
|
988
1042
|
createdAt: normalizeDate(meta?.createdAt ?? createdAt),
|
|
@@ -1153,15 +1207,23 @@ var OnyxDatabaseImpl = class {
|
|
|
1153
1207
|
const params = new URLSearchParams();
|
|
1154
1208
|
if (options?.publish) params.append("publish", "true");
|
|
1155
1209
|
const path2 = `/schemas/${encodeURIComponent(databaseId)}${params.size ? `?${params.toString()}` : ""}`;
|
|
1156
|
-
const body = { ...schema, databaseId: schema.databaseId ?? databaseId };
|
|
1157
|
-
const res = await http.request(
|
|
1210
|
+
const body = stripEntityText({ ...schema, databaseId: schema.databaseId ?? databaseId });
|
|
1211
|
+
const res = await http.request(
|
|
1212
|
+
"PUT",
|
|
1213
|
+
path2,
|
|
1214
|
+
serializeDates(body)
|
|
1215
|
+
);
|
|
1158
1216
|
return normalizeSchemaRevision(res, databaseId);
|
|
1159
1217
|
}
|
|
1160
1218
|
async validateSchema(schema) {
|
|
1161
1219
|
const { http, databaseId } = await this.ensureClient();
|
|
1162
1220
|
const path2 = `/schemas/${encodeURIComponent(databaseId)}/validate`;
|
|
1163
|
-
const body = { ...schema, databaseId: schema.databaseId ?? databaseId };
|
|
1164
|
-
const res = await http.request(
|
|
1221
|
+
const body = stripEntityText({ ...schema, databaseId: schema.databaseId ?? databaseId });
|
|
1222
|
+
const res = await http.request(
|
|
1223
|
+
"POST",
|
|
1224
|
+
path2,
|
|
1225
|
+
serializeDates(body)
|
|
1226
|
+
);
|
|
1165
1227
|
const normalizedSchema = res.schema ? normalizeSchemaRevision(res.schema, databaseId) : void 0;
|
|
1166
1228
|
return {
|
|
1167
1229
|
...res,
|
|
@@ -1323,11 +1385,14 @@ var QueryBuilderImpl = class {
|
|
|
1323
1385
|
if (!this.table) throw new Error("Table is not defined. Call from(<table>) first.");
|
|
1324
1386
|
return this.table;
|
|
1325
1387
|
}
|
|
1388
|
+
serializableConditions() {
|
|
1389
|
+
return normalizeCondition(this.conditions);
|
|
1390
|
+
}
|
|
1326
1391
|
toSelectQuery() {
|
|
1327
1392
|
return {
|
|
1328
1393
|
type: "SelectQuery",
|
|
1329
1394
|
fields: this.fields,
|
|
1330
|
-
conditions: this.
|
|
1395
|
+
conditions: this.serializableConditions(),
|
|
1331
1396
|
sort: this.sort,
|
|
1332
1397
|
limit: this.limitValue,
|
|
1333
1398
|
distinct: this.distinctValue,
|
|
@@ -1336,6 +1401,21 @@ var QueryBuilderImpl = class {
|
|
|
1336
1401
|
resolvers: this.resolvers
|
|
1337
1402
|
};
|
|
1338
1403
|
}
|
|
1404
|
+
toUpdateQuery() {
|
|
1405
|
+
return {
|
|
1406
|
+
type: "UpdateQuery",
|
|
1407
|
+
conditions: this.serializableConditions(),
|
|
1408
|
+
updates: this.updates ?? {},
|
|
1409
|
+
sort: this.sort,
|
|
1410
|
+
limit: this.limitValue,
|
|
1411
|
+
partition: this.partitionValue ?? null
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
toSerializableQueryObject() {
|
|
1415
|
+
const table = this.ensureTable();
|
|
1416
|
+
const payload = this.mode === "update" ? this.toUpdateQuery() : this.toSelectQuery();
|
|
1417
|
+
return { ...payload, table };
|
|
1418
|
+
}
|
|
1339
1419
|
from(table) {
|
|
1340
1420
|
this.table = table;
|
|
1341
1421
|
return this;
|
|
@@ -1471,14 +1551,7 @@ var QueryBuilderImpl = class {
|
|
|
1471
1551
|
async update() {
|
|
1472
1552
|
if (this.mode !== "update") throw new Error("Call setUpdates(...) before update().");
|
|
1473
1553
|
const table = this.ensureTable();
|
|
1474
|
-
const update =
|
|
1475
|
-
type: "UpdateQuery",
|
|
1476
|
-
conditions: this.conditions,
|
|
1477
|
-
updates: this.updates ?? {},
|
|
1478
|
-
sort: this.sort,
|
|
1479
|
-
limit: this.limitValue,
|
|
1480
|
-
partition: this.partitionValue ?? null
|
|
1481
|
-
};
|
|
1554
|
+
const update = this.toUpdateQuery();
|
|
1482
1555
|
return this.db._update(table, update, this.partitionValue);
|
|
1483
1556
|
}
|
|
1484
1557
|
onItemAdded(listener) {
|
|
@@ -1561,6 +1634,212 @@ var onyx = {
|
|
|
1561
1634
|
clearCacheConfig
|
|
1562
1635
|
};
|
|
1563
1636
|
|
|
1637
|
+
// schema/cli/diff.ts
|
|
1638
|
+
function mapByName(items) {
|
|
1639
|
+
const map = /* @__PURE__ */ new Map();
|
|
1640
|
+
for (const item of items ?? []) {
|
|
1641
|
+
if (!item?.name) continue;
|
|
1642
|
+
map.set(item.name, item);
|
|
1643
|
+
}
|
|
1644
|
+
return map;
|
|
1645
|
+
}
|
|
1646
|
+
function normalizeEntities(schema) {
|
|
1647
|
+
if (Array.isArray(schema.entities)) {
|
|
1648
|
+
return schema.entities ?? [];
|
|
1649
|
+
}
|
|
1650
|
+
const tables = schema.tables;
|
|
1651
|
+
if (!Array.isArray(tables)) return [];
|
|
1652
|
+
return tables.map((table) => ({
|
|
1653
|
+
name: table.name,
|
|
1654
|
+
attributes: table.attributes ?? []
|
|
1655
|
+
}));
|
|
1656
|
+
}
|
|
1657
|
+
function formatIdentifier(id) {
|
|
1658
|
+
if (!id) return "";
|
|
1659
|
+
const parts = [id.name ? `name=${id.name}` : null, id.generator ? `generator=${id.generator}` : null, id.type ? `type=${id.type}` : null].filter(Boolean);
|
|
1660
|
+
return parts.join(", ");
|
|
1661
|
+
}
|
|
1662
|
+
function describeIdentifierChange(api, local) {
|
|
1663
|
+
if (!api && !local) return null;
|
|
1664
|
+
if (!api && local) return "identifier removed";
|
|
1665
|
+
if (api && !local) return "identifier added";
|
|
1666
|
+
if (!api || !local) return null;
|
|
1667
|
+
if (api.name === local.name && api.generator === local.generator && api.type === local.type) {
|
|
1668
|
+
return null;
|
|
1669
|
+
}
|
|
1670
|
+
return `identifier: ${formatIdentifier(api) || "none"} -> ${formatIdentifier(local) || "none"}`;
|
|
1671
|
+
}
|
|
1672
|
+
function describePartitionChange(api, local) {
|
|
1673
|
+
const norm = (v) => v == null || v === "" ? "" : v;
|
|
1674
|
+
if (norm(api) === norm(local)) return null;
|
|
1675
|
+
return `partition: ${norm(api) || "none"} -> ${norm(local) || "none"}`;
|
|
1676
|
+
}
|
|
1677
|
+
function describeAttribute(attr) {
|
|
1678
|
+
const nullable = attr.isNullable ? "true" : "false";
|
|
1679
|
+
return `${attr.name} (${attr.type ?? "unknown"}, nullable: ${nullable})`;
|
|
1680
|
+
}
|
|
1681
|
+
function describeAttributeChange(api, local) {
|
|
1682
|
+
const diffs = [];
|
|
1683
|
+
if (api.type !== local.type) {
|
|
1684
|
+
diffs.push(`type ${api.type ?? "unknown"} -> ${local.type ?? "unknown"}`);
|
|
1685
|
+
}
|
|
1686
|
+
const apiNull = Boolean(api.isNullable);
|
|
1687
|
+
const localNull = Boolean(local.isNullable);
|
|
1688
|
+
if (apiNull !== localNull) {
|
|
1689
|
+
diffs.push(`nullable ${apiNull} -> ${localNull}`);
|
|
1690
|
+
}
|
|
1691
|
+
if (!diffs.length) return null;
|
|
1692
|
+
return `${local.name}: ${diffs.join("; ")}`;
|
|
1693
|
+
}
|
|
1694
|
+
function describeIndex(idx) {
|
|
1695
|
+
const parts = [`type: ${idx.type ?? "DEFAULT"}`];
|
|
1696
|
+
if (idx.minimumScore != null) parts.push(`minScore: ${idx.minimumScore}`);
|
|
1697
|
+
return `${idx.name} (${parts.join(", ")})`;
|
|
1698
|
+
}
|
|
1699
|
+
function describeIndexChange(api, local) {
|
|
1700
|
+
const diffs = [];
|
|
1701
|
+
if (api.type !== local.type) {
|
|
1702
|
+
diffs.push(`type ${api.type ?? "DEFAULT"} -> ${local.type ?? "DEFAULT"}`);
|
|
1703
|
+
}
|
|
1704
|
+
if (api.minimumScore !== local.minimumScore) {
|
|
1705
|
+
diffs.push(`minScore ${api.minimumScore ?? "none"} -> ${local.minimumScore ?? "none"}`);
|
|
1706
|
+
}
|
|
1707
|
+
if (!diffs.length) return null;
|
|
1708
|
+
return `${local.name}: ${diffs.join("; ")}`;
|
|
1709
|
+
}
|
|
1710
|
+
function describeResolverChange(api, local) {
|
|
1711
|
+
if (api.resolver === local.resolver) return null;
|
|
1712
|
+
return `${local.name}: resolver changed`;
|
|
1713
|
+
}
|
|
1714
|
+
function describeTrigger(trigger) {
|
|
1715
|
+
return `${trigger.name} (${trigger.event})`;
|
|
1716
|
+
}
|
|
1717
|
+
function describeTriggerChange(api, local) {
|
|
1718
|
+
const diffs = [];
|
|
1719
|
+
if (api.event !== local.event) {
|
|
1720
|
+
diffs.push(`event ${api.event ?? "none"} -> ${local.event ?? "none"}`);
|
|
1721
|
+
}
|
|
1722
|
+
if (api.trigger !== local.trigger) {
|
|
1723
|
+
diffs.push("trigger changed");
|
|
1724
|
+
}
|
|
1725
|
+
if (!diffs.length) return null;
|
|
1726
|
+
return `${local.name}: ${diffs.join("; ")}`;
|
|
1727
|
+
}
|
|
1728
|
+
function diffCollections(apiItems, localItems, describeAdd, describeChange) {
|
|
1729
|
+
const apiMap = mapByName(apiItems);
|
|
1730
|
+
const localMap = mapByName(localItems);
|
|
1731
|
+
const added = [];
|
|
1732
|
+
const removed = [];
|
|
1733
|
+
const changed = [];
|
|
1734
|
+
for (const [name, local] of localMap.entries()) {
|
|
1735
|
+
if (!apiMap.has(name)) {
|
|
1736
|
+
added.push(describeAdd(local));
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
if (describeChange) {
|
|
1740
|
+
const detail = describeChange(apiMap.get(name), local);
|
|
1741
|
+
if (detail) changed.push(detail);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
for (const name of apiMap.keys()) {
|
|
1745
|
+
if (!localMap.has(name)) removed.push(name);
|
|
1746
|
+
}
|
|
1747
|
+
return { added, removed, changed };
|
|
1748
|
+
}
|
|
1749
|
+
function computeSchemaDiff(apiSchema, localSchema) {
|
|
1750
|
+
const apiEntities = normalizeEntities(apiSchema);
|
|
1751
|
+
const localEntities = normalizeEntities(localSchema);
|
|
1752
|
+
const apiMap = mapByName(apiEntities);
|
|
1753
|
+
const localMap = mapByName(localEntities);
|
|
1754
|
+
const newTables = [];
|
|
1755
|
+
const removedTables = [];
|
|
1756
|
+
const changedTables = [];
|
|
1757
|
+
for (const [name, localEntity] of localMap.entries()) {
|
|
1758
|
+
if (!apiMap.has(name)) {
|
|
1759
|
+
newTables.push(name);
|
|
1760
|
+
continue;
|
|
1761
|
+
}
|
|
1762
|
+
const apiEntity = apiMap.get(name);
|
|
1763
|
+
const details = [];
|
|
1764
|
+
const partitionChange = describePartitionChange(apiEntity.partition, localEntity.partition);
|
|
1765
|
+
if (partitionChange) details.push(partitionChange);
|
|
1766
|
+
const idChange = describeIdentifierChange(apiEntity.identifier, localEntity.identifier);
|
|
1767
|
+
if (idChange) details.push(idChange);
|
|
1768
|
+
const attrDiff = diffCollections(apiEntity.attributes, localEntity.attributes, (attr) => `+ ${describeAttribute(attr)}`, describeAttributeChange);
|
|
1769
|
+
if (attrDiff.added.length || attrDiff.removed.length || attrDiff.changed.length) {
|
|
1770
|
+
details.push("attributes:");
|
|
1771
|
+
for (const a of attrDiff.added) details.push(` ${a}`);
|
|
1772
|
+
for (const c of attrDiff.changed) details.push(` ~ ${c}`);
|
|
1773
|
+
for (const r of attrDiff.removed) details.push(` - ${r}`);
|
|
1774
|
+
}
|
|
1775
|
+
const idxDiff = diffCollections(apiEntity.indexes, localEntity.indexes, (idx) => `+ ${describeIndex(idx)}`, describeIndexChange);
|
|
1776
|
+
if (idxDiff.added.length || idxDiff.removed.length || idxDiff.changed.length) {
|
|
1777
|
+
details.push("indexes:");
|
|
1778
|
+
for (const a of idxDiff.added) details.push(` ${a}`);
|
|
1779
|
+
for (const c of idxDiff.changed) details.push(` ~ ${c}`);
|
|
1780
|
+
for (const r of idxDiff.removed) details.push(` - ${r}`);
|
|
1781
|
+
}
|
|
1782
|
+
const resolverDiff = diffCollections(apiEntity.resolvers, localEntity.resolvers, (resolver) => `+ ${resolver.name}`, describeResolverChange);
|
|
1783
|
+
if (resolverDiff.added.length || resolverDiff.removed.length || resolverDiff.changed.length) {
|
|
1784
|
+
details.push("resolvers:");
|
|
1785
|
+
for (const a of resolverDiff.added) details.push(` ${a}`);
|
|
1786
|
+
for (const c of resolverDiff.changed) details.push(` ~ ${c}`);
|
|
1787
|
+
for (const r of resolverDiff.removed) details.push(` - ${r}`);
|
|
1788
|
+
}
|
|
1789
|
+
const triggerDiff = diffCollections(apiEntity.triggers, localEntity.triggers, (trigger) => `+ ${describeTrigger(trigger)}`, describeTriggerChange);
|
|
1790
|
+
if (triggerDiff.added.length || triggerDiff.removed.length || triggerDiff.changed.length) {
|
|
1791
|
+
details.push("triggers:");
|
|
1792
|
+
for (const a of triggerDiff.added) details.push(` ${a}`);
|
|
1793
|
+
for (const c of triggerDiff.changed) details.push(` ~ ${c}`);
|
|
1794
|
+
for (const r of triggerDiff.removed) details.push(` - ${r}`);
|
|
1795
|
+
}
|
|
1796
|
+
if (details.length) {
|
|
1797
|
+
changedTables.push({ name, details });
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
for (const name of apiMap.keys()) {
|
|
1801
|
+
if (!localMap.has(name)) removedTables.push(name);
|
|
1802
|
+
}
|
|
1803
|
+
newTables.sort();
|
|
1804
|
+
removedTables.sort();
|
|
1805
|
+
changedTables.sort((a, b) => a.name.localeCompare(b.name));
|
|
1806
|
+
return { newTables, removedTables, changedTables };
|
|
1807
|
+
}
|
|
1808
|
+
function formatSchemaDiff(diff, filePath) {
|
|
1809
|
+
const lines = [];
|
|
1810
|
+
const hasChanges = diff.newTables.length || diff.removedTables.length || diff.changedTables.length;
|
|
1811
|
+
if (!hasChanges) {
|
|
1812
|
+
return `No differences found between API schema and ${filePath ?? "local file"}.
|
|
1813
|
+
`;
|
|
1814
|
+
}
|
|
1815
|
+
if (filePath) lines.push(`Comparing API schema to ${filePath}`);
|
|
1816
|
+
lines.push("New Tables:");
|
|
1817
|
+
if (diff.newTables.length) {
|
|
1818
|
+
for (const t of diff.newTables) lines.push(` ${t}`);
|
|
1819
|
+
} else {
|
|
1820
|
+
lines.push(" (none)");
|
|
1821
|
+
}
|
|
1822
|
+
lines.push("Removed Tables:");
|
|
1823
|
+
if (diff.removedTables.length) {
|
|
1824
|
+
for (const t of diff.removedTables) lines.push(` ${t}`);
|
|
1825
|
+
} else {
|
|
1826
|
+
lines.push(" (none)");
|
|
1827
|
+
}
|
|
1828
|
+
lines.push("Changes:");
|
|
1829
|
+
if (diff.changedTables.length) {
|
|
1830
|
+
for (const table of diff.changedTables) {
|
|
1831
|
+
lines.push(` ${table.name}`);
|
|
1832
|
+
for (const detail of table.details) {
|
|
1833
|
+
lines.push(` ${detail}`);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
} else {
|
|
1837
|
+
lines.push(" (none)");
|
|
1838
|
+
}
|
|
1839
|
+
return `${lines.join("\n")}
|
|
1840
|
+
`;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1564
1843
|
// schema/cli/schema.ts
|
|
1565
1844
|
var DEFAULT_SCHEMA_PATH = "./onyx.schema.json";
|
|
1566
1845
|
function printHelp() {
|
|
@@ -1570,6 +1849,7 @@ Usage:
|
|
|
1570
1849
|
onyx-schema publish [file]
|
|
1571
1850
|
onyx-schema get [file] [--tables tableA,tableB]
|
|
1572
1851
|
onyx-schema validate [file]
|
|
1852
|
+
onyx-schema diff [file]
|
|
1573
1853
|
|
|
1574
1854
|
Options:
|
|
1575
1855
|
[file] Path to schema JSON (default: ./onyx.schema.json)
|
|
@@ -1585,7 +1865,7 @@ function parseTables(value) {
|
|
|
1585
1865
|
function parseArgs(argv) {
|
|
1586
1866
|
const cmd = (argv[2] ?? "").toLowerCase();
|
|
1587
1867
|
let command = "help";
|
|
1588
|
-
if (cmd === "publish" || cmd === "get" || cmd === "validate") {
|
|
1868
|
+
if (cmd === "publish" || cmd === "get" || cmd === "validate" || cmd === "diff") {
|
|
1589
1869
|
command = cmd;
|
|
1590
1870
|
}
|
|
1591
1871
|
let idx = 3;
|
|
@@ -1670,6 +1950,16 @@ ${formatSchemaErrors(result.errors)}`);
|
|
|
1670
1950
|
process__default.default.stdout.write(`Schema published for database ${revision.databaseId} from ${filePath}.
|
|
1671
1951
|
`);
|
|
1672
1952
|
}
|
|
1953
|
+
async function diffSchema(filePath) {
|
|
1954
|
+
const db = onyx.init();
|
|
1955
|
+
const [apiSchema, localSchema] = await Promise.all([
|
|
1956
|
+
db.getSchema(),
|
|
1957
|
+
readFileJson(filePath)
|
|
1958
|
+
]);
|
|
1959
|
+
const diff = computeSchemaDiff(apiSchema, localSchema);
|
|
1960
|
+
const output = formatSchemaDiff(diff, filePath);
|
|
1961
|
+
process__default.default.stdout.write(output);
|
|
1962
|
+
}
|
|
1673
1963
|
(async () => {
|
|
1674
1964
|
try {
|
|
1675
1965
|
const parsed = parseArgs(process__default.default.argv);
|
|
@@ -1683,6 +1973,9 @@ ${formatSchemaErrors(result.errors)}`);
|
|
|
1683
1973
|
case "validate":
|
|
1684
1974
|
await validateSchema(parsed.filePath);
|
|
1685
1975
|
break;
|
|
1976
|
+
case "diff":
|
|
1977
|
+
await diffSchema(parsed.filePath);
|
|
1978
|
+
break;
|
|
1686
1979
|
default:
|
|
1687
1980
|
printHelp();
|
|
1688
1981
|
return;
|