@nicia-ai/typegraph 0.24.1 → 0.25.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/backend/postgres/index.cjs +178 -55
- package/dist/backend/postgres/index.cjs.map +1 -1
- package/dist/backend/postgres/index.d.cts +6 -7
- package/dist/backend/postgres/index.d.ts +6 -7
- package/dist/backend/postgres/index.js +151 -28
- package/dist/backend/postgres/index.js.map +1 -1
- package/dist/backend/sqlite/index.cjs +19 -17
- package/dist/backend/sqlite/index.d.cts +6 -7
- package/dist/backend/sqlite/index.d.ts +6 -7
- package/dist/backend/sqlite/index.js +9 -7
- package/dist/backend/sqlite/libsql.cjs +12 -10
- package/dist/backend/sqlite/libsql.cjs.map +1 -1
- package/dist/backend/sqlite/libsql.d.cts +4 -5
- package/dist/backend/sqlite/libsql.d.ts +4 -5
- package/dist/backend/sqlite/libsql.js +9 -7
- package/dist/backend/sqlite/libsql.js.map +1 -1
- package/dist/backend/sqlite/local.cjs +14 -12
- package/dist/backend/sqlite/local.cjs.map +1 -1
- package/dist/backend/sqlite/local.d.cts +4 -5
- package/dist/backend/sqlite/local.d.ts +4 -5
- package/dist/backend/sqlite/local.js +9 -7
- package/dist/backend/sqlite/local.js.map +1 -1
- package/dist/chunk-4BOWVUGQ.js +2029 -0
- package/dist/chunk-4BOWVUGQ.js.map +1 -0
- package/dist/{chunk-SUHW2UYL.cjs → chunk-7CDXX3QZ.cjs} +2 -2
- package/dist/chunk-7CDXX3QZ.cjs.map +1 -0
- package/dist/chunk-7V335GHG.cjs +112 -0
- package/dist/chunk-7V335GHG.cjs.map +1 -0
- package/dist/chunk-7W3KAMVQ.cjs +2678 -0
- package/dist/chunk-7W3KAMVQ.cjs.map +1 -0
- package/dist/chunk-CTHNVU6K.cjs +551 -0
- package/dist/chunk-CTHNVU6K.cjs.map +1 -0
- package/dist/chunk-D2GO3RBL.cjs +12 -0
- package/dist/chunk-D2GO3RBL.cjs.map +1 -0
- package/dist/{chunk-WFMTAEEN.js → chunk-DOTEN2FG.js} +81 -7
- package/dist/chunk-DOTEN2FG.js.map +1 -0
- package/dist/chunk-E5JZSEGJ.cjs +301 -0
- package/dist/chunk-E5JZSEGJ.cjs.map +1 -0
- package/dist/chunk-EG6TJ3I5.js +286 -0
- package/dist/chunk-EG6TJ3I5.js.map +1 -0
- package/dist/chunk-EJCDOA37.js +537 -0
- package/dist/chunk-EJCDOA37.js.map +1 -0
- package/dist/{chunk-UVZHTBZ5.cjs → chunk-EK6RJ373.cjs} +7 -150
- package/dist/chunk-EK6RJ373.cjs.map +1 -0
- package/dist/{chunk-GUTQTMOV.js → chunk-FPCOUJSL.js} +2 -2
- package/dist/chunk-FPCOUJSL.js.map +1 -0
- package/dist/{chunk-3JK66E3I.cjs → chunk-JTI5WT4P.cjs} +630 -59
- package/dist/chunk-JTI5WT4P.cjs.map +1 -0
- package/dist/chunk-LVCSL6A3.js +2626 -0
- package/dist/chunk-LVCSL6A3.js.map +1 -0
- package/dist/chunk-NHQWXSTS.js +10 -0
- package/dist/chunk-NHQWXSTS.js.map +1 -0
- package/dist/chunk-NZ5PMBTG.js +105 -0
- package/dist/chunk-NZ5PMBTG.js.map +1 -0
- package/dist/{chunk-5HVDOPZU.cjs → chunk-O2P3KAUT.cjs} +416 -93
- package/dist/chunk-O2P3KAUT.cjs.map +1 -0
- package/dist/{chunk-QOLTW7OZ.js → chunk-OJ6IQVZG.js} +151 -13
- package/dist/chunk-OJ6IQVZG.js.map +1 -0
- package/dist/{chunk-EYELZHKY.js → chunk-OOS2RKRH.js} +5 -140
- package/dist/chunk-OOS2RKRH.js.map +1 -0
- package/dist/chunk-RCAJZG67.cjs +2069 -0
- package/dist/chunk-RCAJZG67.cjs.map +1 -0
- package/dist/{chunk-O5PST6TB.cjs → chunk-W5MTHMTE.cjs} +83 -6
- package/dist/chunk-W5MTHMTE.cjs.map +1 -0
- package/dist/{chunk-EY4LBX3F.js → chunk-WI5VRP3X.js} +337 -26
- package/dist/chunk-WI5VRP3X.js.map +1 -0
- package/dist/chunk-WVQXAFP3.js +79 -0
- package/dist/chunk-WVQXAFP3.js.map +1 -0
- package/dist/chunk-X3244EKP.cjs +84 -0
- package/dist/chunk-X3244EKP.cjs.map +1 -0
- package/dist/{chunk-753F33CV.js → chunk-YZZBDCLV.js} +617 -44
- package/dist/chunk-YZZBDCLV.js.map +1 -0
- package/dist/{chunk-OVJ2BE5Q.cjs → chunk-ZEMNF3QK.cjs} +171 -33
- package/dist/chunk-ZEMNF3QK.cjs.map +1 -0
- package/dist/{ddl-B_H8JM-E.d.cts → ddl-B2jjLjpR.d.cts} +762 -99
- package/dist/{ddl-1tFIvt9V.d.ts → ddl-DpaeAKPp.d.ts} +762 -99
- package/dist/extension-types-D07e_NTw.d.cts +543 -0
- package/dist/extension-types-D07e_NTw.d.ts +543 -0
- package/dist/graph-extension/index.cjs +71 -0
- package/dist/graph-extension/index.cjs.map +1 -0
- package/dist/graph-extension/index.d.cts +278 -0
- package/dist/graph-extension/index.d.ts +278 -0
- package/dist/graph-extension/index.js +6 -0
- package/dist/graph-extension/index.js.map +1 -0
- package/dist/{index-DXkEXpNz.d.ts → index-CT6nvtxL.d.cts} +114 -5
- package/dist/{index-DXkEXpNz.d.cts → index-DQheiVQV.d.ts} +114 -5
- package/dist/index.cjs +2672 -901
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -10
- package/dist/index.d.ts +29 -10
- package/dist/index.js +2248 -598
- package/dist/index.js.map +1 -1
- package/dist/indexes/index.cjs +25 -23
- package/dist/indexes/index.d.cts +40 -22
- package/dist/indexes/index.d.ts +40 -22
- package/dist/indexes/index.js +5 -3
- package/dist/interchange/index.cjs +8 -7
- package/dist/interchange/index.cjs.map +1 -1
- package/dist/interchange/index.d.cts +5 -4
- package/dist/interchange/index.d.ts +5 -4
- package/dist/interchange/index.js +3 -2
- package/dist/interchange/index.js.map +1 -1
- package/dist/{manager-nIhmttD-.d.ts → manager-BKaPQbns.d.ts} +189 -6
- package/dist/{manager-Vkz28eAC.d.cts → manager-BpjBW1JK.d.cts} +189 -6
- package/dist/materialize-indexes-BB9N5uQl.d.cts +68 -0
- package/dist/materialize-indexes-BYpU2RKh.d.ts +68 -0
- package/dist/profiler/index.cjs +10 -8
- package/dist/profiler/index.cjs.map +1 -1
- package/dist/profiler/index.d.cts +8 -7
- package/dist/profiler/index.d.ts +8 -7
- package/dist/profiler/index.js +3 -1
- package/dist/profiler/index.js.map +1 -1
- package/dist/schema/index.cjs +43 -22
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +17 -8
- package/dist/schema/index.d.ts +17 -8
- package/dist/schema/index.js +9 -4
- package/dist/schema/index.js.map +1 -1
- package/dist/{sqlite-D0aceIe0.d.cts → sqlite-CU3j6rc7.d.ts} +837 -120
- package/dist/{sqlite-SUxbZqfy.d.ts → sqlite-Myo8e3Lr.d.cts} +837 -120
- package/dist/{store-U3i2tUch.d.ts → store-BAGuOHDh.d.cts} +659 -23
- package/dist/{store-CpvwTMxV.d.cts → store-De98Lod4.d.ts} +659 -23
- package/dist/types--0EslBx5.d.cts +2123 -0
- package/dist/{types-qYFZ9SqD.d.ts → types-BLmJq4wI.d.ts} +3 -2
- package/dist/types-BNWYZ-0-.d.ts +2123 -0
- package/dist/{types-yH4_p0XB.d.cts → types-CYga3lZp.d.cts} +3 -2
- package/dist/where-CluR73rs.d.ts +11 -0
- package/dist/where-m1uWsdua.d.cts +11 -0
- package/package.json +33 -73
- package/dist/ast-C8S37w1A.d.ts +0 -497
- package/dist/ast-dgLhLOg0.d.cts +0 -497
- package/dist/chunk-3JK66E3I.cjs.map +0 -1
- package/dist/chunk-3PPEHLGK.js +0 -1116
- package/dist/chunk-3PPEHLGK.js.map +0 -1
- package/dist/chunk-5HVDOPZU.cjs.map +0 -1
- package/dist/chunk-753F33CV.js.map +0 -1
- package/dist/chunk-EY4LBX3F.js.map +0 -1
- package/dist/chunk-EYELZHKY.js.map +0 -1
- package/dist/chunk-GFGVREHH.js +0 -1381
- package/dist/chunk-GFGVREHH.js.map +0 -1
- package/dist/chunk-GUTQTMOV.js.map +0 -1
- package/dist/chunk-LBORRUNJ.js +0 -135
- package/dist/chunk-LBORRUNJ.js.map +0 -1
- package/dist/chunk-O5PST6TB.cjs.map +0 -1
- package/dist/chunk-OLROXS2S.cjs +0 -147
- package/dist/chunk-OLROXS2S.cjs.map +0 -1
- package/dist/chunk-OVJ2BE5Q.cjs.map +0 -1
- package/dist/chunk-PAUN562Y.cjs +0 -1417
- package/dist/chunk-PAUN562Y.cjs.map +0 -1
- package/dist/chunk-PEE4EWXZ.cjs +0 -1131
- package/dist/chunk-PEE4EWXZ.cjs.map +0 -1
- package/dist/chunk-QOLTW7OZ.js.map +0 -1
- package/dist/chunk-SUHW2UYL.cjs.map +0 -1
- package/dist/chunk-UVZHTBZ5.cjs.map +0 -1
- package/dist/chunk-WFMTAEEN.js.map +0 -1
- package/dist/types-C-zfYDJB.d.ts +0 -159
- package/dist/types-CQx4iW5Y.d.cts +0 -159
- package/dist/types-Qk2l3IkQ.d.cts +0 -1254
- package/dist/types-Qk2l3IkQ.d.ts +0 -1254
|
@@ -0,0 +1,2678 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkE5JZSEGJ_cjs = require('./chunk-E5JZSEGJ.cjs');
|
|
4
|
+
var chunkRCAJZG67_cjs = require('./chunk-RCAJZG67.cjs');
|
|
5
|
+
var chunkCTHNVU6K_cjs = require('./chunk-CTHNVU6K.cjs');
|
|
6
|
+
var chunkEK6RJ373_cjs = require('./chunk-EK6RJ373.cjs');
|
|
7
|
+
var chunkX3244EKP_cjs = require('./chunk-X3244EKP.cjs');
|
|
8
|
+
var chunkW5MTHMTE_cjs = require('./chunk-W5MTHMTE.cjs');
|
|
9
|
+
var zod = require('zod');
|
|
10
|
+
|
|
11
|
+
// src/core/node.ts
|
|
12
|
+
function validateSchemaKeys(schema, name) {
|
|
13
|
+
chunkRCAJZG67_cjs.assertSchemaKeysAreFree(
|
|
14
|
+
"Node",
|
|
15
|
+
name,
|
|
16
|
+
Object.keys(schema.shape),
|
|
17
|
+
chunkRCAJZG67_cjs.RESERVED_NODE_KEYS
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function defineNode(name, options) {
|
|
21
|
+
validateSchemaKeys(options.schema, name);
|
|
22
|
+
if (options.annotations !== void 0) {
|
|
23
|
+
chunkRCAJZG67_cjs.assertJsonValue(options.annotations, "annotations", `Node "${name}"`);
|
|
24
|
+
}
|
|
25
|
+
return Object.freeze({
|
|
26
|
+
[chunkE5JZSEGJ_cjs.NODE_TYPE_BRAND]: true,
|
|
27
|
+
kind: name,
|
|
28
|
+
schema: options.schema,
|
|
29
|
+
description: options.description,
|
|
30
|
+
annotations: options.annotations
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
var EMPTY_SCHEMA = zod.z.object({});
|
|
34
|
+
function validateSchemaKeys2(schema, name) {
|
|
35
|
+
chunkRCAJZG67_cjs.assertSchemaKeysAreFree(
|
|
36
|
+
"Edge",
|
|
37
|
+
name,
|
|
38
|
+
Object.keys(schema.shape),
|
|
39
|
+
chunkRCAJZG67_cjs.RESERVED_EDGE_KEYS
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function defineEdge(name, options) {
|
|
43
|
+
const schema = options?.schema ?? EMPTY_SCHEMA;
|
|
44
|
+
validateSchemaKeys2(schema, name);
|
|
45
|
+
if (options?.annotations !== void 0) {
|
|
46
|
+
chunkRCAJZG67_cjs.assertJsonValue(options.annotations, "annotations", `Edge "${name}"`);
|
|
47
|
+
}
|
|
48
|
+
return Object.freeze({
|
|
49
|
+
[chunkE5JZSEGJ_cjs.EDGE_TYPE_BRAND]: true,
|
|
50
|
+
kind: name,
|
|
51
|
+
schema,
|
|
52
|
+
description: options?.description,
|
|
53
|
+
annotations: options?.annotations,
|
|
54
|
+
from: options?.from,
|
|
55
|
+
to: options?.to
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/ontology/types.ts
|
|
60
|
+
var META_EDGE_BRAND = "__metaEdge";
|
|
61
|
+
function isMetaEdge(value) {
|
|
62
|
+
return typeof value === "object" && value !== null && META_EDGE_BRAND in value && value[META_EDGE_BRAND] === true;
|
|
63
|
+
}
|
|
64
|
+
function getTypeName(typeOrIri) {
|
|
65
|
+
if (typeof typeOrIri === "string") {
|
|
66
|
+
return typeOrIri;
|
|
67
|
+
}
|
|
68
|
+
return typeOrIri.kind;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/ontology/core-meta-edges.ts
|
|
72
|
+
function createMetaEdge(name, properties) {
|
|
73
|
+
return Object.freeze({
|
|
74
|
+
[META_EDGE_BRAND]: true,
|
|
75
|
+
name,
|
|
76
|
+
properties: {
|
|
77
|
+
transitive: properties.transitive ?? false,
|
|
78
|
+
symmetric: properties.symmetric ?? false,
|
|
79
|
+
reflexive: properties.reflexive ?? false,
|
|
80
|
+
inverse: properties.inverse,
|
|
81
|
+
inference: properties.inference,
|
|
82
|
+
description: properties.description
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
var subClassOfMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_SUB_CLASS_OF, {
|
|
87
|
+
transitive: true,
|
|
88
|
+
inference: "subsumption",
|
|
89
|
+
description: "Type inheritance (Podcast subClassOf Media)"
|
|
90
|
+
});
|
|
91
|
+
function subClassOf(child, parent) {
|
|
92
|
+
return {
|
|
93
|
+
metaEdge: subClassOfMetaEdge,
|
|
94
|
+
from: child,
|
|
95
|
+
to: parent
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
var broaderMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_BROADER, {
|
|
99
|
+
transitive: true,
|
|
100
|
+
inverse: chunkRCAJZG67_cjs.META_EDGE_NARROWER,
|
|
101
|
+
inference: "hierarchy",
|
|
102
|
+
description: "Broader concept (ML broader AI)"
|
|
103
|
+
});
|
|
104
|
+
function broader(narrowerConcept, broaderConcept) {
|
|
105
|
+
return {
|
|
106
|
+
metaEdge: broaderMetaEdge,
|
|
107
|
+
from: narrowerConcept,
|
|
108
|
+
to: broaderConcept
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
var narrowerMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_NARROWER, {
|
|
112
|
+
transitive: true,
|
|
113
|
+
inverse: chunkRCAJZG67_cjs.META_EDGE_BROADER,
|
|
114
|
+
inference: "hierarchy",
|
|
115
|
+
description: "Narrower concept (AI narrower ML)"
|
|
116
|
+
});
|
|
117
|
+
function narrower(broaderConcept, narrowerConcept) {
|
|
118
|
+
return {
|
|
119
|
+
metaEdge: narrowerMetaEdge,
|
|
120
|
+
from: broaderConcept,
|
|
121
|
+
to: narrowerConcept
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
var relatedToMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_RELATED_TO, {
|
|
125
|
+
symmetric: true,
|
|
126
|
+
inference: "association",
|
|
127
|
+
description: "Non-hierarchical association"
|
|
128
|
+
});
|
|
129
|
+
function relatedTo(conceptA, conceptB) {
|
|
130
|
+
return {
|
|
131
|
+
metaEdge: relatedToMetaEdge,
|
|
132
|
+
from: conceptA,
|
|
133
|
+
to: conceptB
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
var equivalentToMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_EQUIVALENT_TO, {
|
|
137
|
+
symmetric: true,
|
|
138
|
+
transitive: true,
|
|
139
|
+
inference: "substitution",
|
|
140
|
+
description: "Same class, different representation"
|
|
141
|
+
});
|
|
142
|
+
function equivalentTo(kindA, kindBOrIri) {
|
|
143
|
+
return {
|
|
144
|
+
metaEdge: equivalentToMetaEdge,
|
|
145
|
+
from: kindA,
|
|
146
|
+
to: kindBOrIri
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
var sameAsMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_SAME_AS, {
|
|
150
|
+
symmetric: true,
|
|
151
|
+
transitive: true,
|
|
152
|
+
inference: "substitution",
|
|
153
|
+
description: "Same individual (for deduplication)"
|
|
154
|
+
});
|
|
155
|
+
function sameAs(kindA, kindBOrIri) {
|
|
156
|
+
return {
|
|
157
|
+
metaEdge: sameAsMetaEdge,
|
|
158
|
+
from: kindA,
|
|
159
|
+
to: kindBOrIri
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
var differentFromMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_DIFFERENT_FROM, {
|
|
163
|
+
symmetric: true,
|
|
164
|
+
inference: "constraint",
|
|
165
|
+
description: "Explicitly different individuals"
|
|
166
|
+
});
|
|
167
|
+
function differentFrom(kindA, kindB) {
|
|
168
|
+
return {
|
|
169
|
+
metaEdge: differentFromMetaEdge,
|
|
170
|
+
from: kindA,
|
|
171
|
+
to: kindB
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
var disjointWithMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_DISJOINT_WITH, {
|
|
175
|
+
symmetric: true,
|
|
176
|
+
inference: "constraint",
|
|
177
|
+
description: "Mutually exclusive types"
|
|
178
|
+
});
|
|
179
|
+
function disjointWith(kindA, kindB) {
|
|
180
|
+
return {
|
|
181
|
+
metaEdge: disjointWithMetaEdge,
|
|
182
|
+
from: kindA,
|
|
183
|
+
to: kindB
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
var partOfMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_PART_OF, {
|
|
187
|
+
transitive: true,
|
|
188
|
+
inverse: chunkRCAJZG67_cjs.META_EDGE_HAS_PART,
|
|
189
|
+
inference: "composition",
|
|
190
|
+
description: "X is part of Y"
|
|
191
|
+
});
|
|
192
|
+
function partOf(part, whole) {
|
|
193
|
+
return {
|
|
194
|
+
metaEdge: partOfMetaEdge,
|
|
195
|
+
from: part,
|
|
196
|
+
to: whole
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
var hasPartMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_HAS_PART, {
|
|
200
|
+
transitive: true,
|
|
201
|
+
inverse: chunkRCAJZG67_cjs.META_EDGE_PART_OF,
|
|
202
|
+
inference: "composition",
|
|
203
|
+
description: "Y has part X"
|
|
204
|
+
});
|
|
205
|
+
function hasPart(whole, part) {
|
|
206
|
+
return {
|
|
207
|
+
metaEdge: hasPartMetaEdge,
|
|
208
|
+
from: whole,
|
|
209
|
+
to: part
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
var inverseOfMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_INVERSE_OF, {
|
|
213
|
+
symmetric: true,
|
|
214
|
+
inference: "none",
|
|
215
|
+
description: "Edge A is inverse of edge B"
|
|
216
|
+
});
|
|
217
|
+
var impliesMetaEdge = createMetaEdge(chunkRCAJZG67_cjs.META_EDGE_IMPLIES, {
|
|
218
|
+
transitive: true,
|
|
219
|
+
inference: "none",
|
|
220
|
+
description: "Edge A implies edge B exists"
|
|
221
|
+
});
|
|
222
|
+
function inverseOf(edgeA, edgeB) {
|
|
223
|
+
return {
|
|
224
|
+
metaEdge: inverseOfMetaEdge,
|
|
225
|
+
from: edgeA,
|
|
226
|
+
to: edgeB
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function implies(edgeA, edgeB) {
|
|
230
|
+
return {
|
|
231
|
+
metaEdge: impliesMetaEdge,
|
|
232
|
+
from: edgeA,
|
|
233
|
+
to: edgeB
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
var core = {
|
|
237
|
+
// Meta-edges
|
|
238
|
+
subClassOfMetaEdge,
|
|
239
|
+
broaderMetaEdge,
|
|
240
|
+
narrowerMetaEdge,
|
|
241
|
+
relatedToMetaEdge,
|
|
242
|
+
equivalentToMetaEdge,
|
|
243
|
+
sameAsMetaEdge,
|
|
244
|
+
differentFromMetaEdge,
|
|
245
|
+
disjointWithMetaEdge,
|
|
246
|
+
partOfMetaEdge,
|
|
247
|
+
hasPartMetaEdge,
|
|
248
|
+
inverseOfMetaEdge,
|
|
249
|
+
impliesMetaEdge,
|
|
250
|
+
// Relation factories
|
|
251
|
+
subClassOf,
|
|
252
|
+
broader,
|
|
253
|
+
narrower,
|
|
254
|
+
relatedTo,
|
|
255
|
+
equivalentTo,
|
|
256
|
+
sameAs,
|
|
257
|
+
differentFrom,
|
|
258
|
+
disjointWith,
|
|
259
|
+
partOf,
|
|
260
|
+
hasPart,
|
|
261
|
+
inverseOf,
|
|
262
|
+
implies
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/schema/canonical.ts
|
|
266
|
+
function sortedReplacer(_key, value) {
|
|
267
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
268
|
+
const sorted = {};
|
|
269
|
+
for (const key of Object.keys(value).toSorted()) {
|
|
270
|
+
sorted[key] = value[key];
|
|
271
|
+
}
|
|
272
|
+
return sorted;
|
|
273
|
+
}
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
function canonicalEqual(a, b) {
|
|
277
|
+
return JSON.stringify(a, sortedReplacer) === JSON.stringify(b, sortedReplacer);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/schema/migration.ts
|
|
281
|
+
function computeSchemaDiff(before, after) {
|
|
282
|
+
const nodeChanges = diffNodes(before.nodes, after.nodes);
|
|
283
|
+
const edgeChanges = diffEdges(before.edges, after.edges);
|
|
284
|
+
const ontologyChanges = diffOntology(before.ontology, after.ontology);
|
|
285
|
+
const indexChanges = diffIndexes(before.indexes, after.indexes);
|
|
286
|
+
const extensionChange = diffExtension(before.extension, after.extension);
|
|
287
|
+
const deprecatedKindsChange = diffDeprecatedKinds(
|
|
288
|
+
before.deprecatedKinds,
|
|
289
|
+
after.deprecatedKinds
|
|
290
|
+
);
|
|
291
|
+
const allChanges = [
|
|
292
|
+
...nodeChanges,
|
|
293
|
+
...edgeChanges,
|
|
294
|
+
...ontologyChanges,
|
|
295
|
+
...indexChanges
|
|
296
|
+
];
|
|
297
|
+
const hasBreakingChanges = allChanges.some(
|
|
298
|
+
(change) => change.severity === "breaking"
|
|
299
|
+
);
|
|
300
|
+
const hasChanges = allChanges.length > 0 || extensionChange !== void 0 || deprecatedKindsChange !== void 0;
|
|
301
|
+
const summary = generateSummary(
|
|
302
|
+
nodeChanges,
|
|
303
|
+
edgeChanges,
|
|
304
|
+
ontologyChanges,
|
|
305
|
+
indexChanges,
|
|
306
|
+
extensionChange,
|
|
307
|
+
deprecatedKindsChange
|
|
308
|
+
);
|
|
309
|
+
return {
|
|
310
|
+
fromVersion: before.version,
|
|
311
|
+
toVersion: after.version,
|
|
312
|
+
nodes: nodeChanges,
|
|
313
|
+
edges: edgeChanges,
|
|
314
|
+
ontology: ontologyChanges,
|
|
315
|
+
indexes: indexChanges,
|
|
316
|
+
...extensionChange === void 0 ? {} : { extension: extensionChange },
|
|
317
|
+
...deprecatedKindsChange === void 0 ? {} : { deprecatedKinds: deprecatedKindsChange },
|
|
318
|
+
hasBreakingChanges,
|
|
319
|
+
isBackwardsCompatible: !hasBreakingChanges,
|
|
320
|
+
hasChanges,
|
|
321
|
+
summary
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function diffNodes(before, after) {
|
|
325
|
+
const changes = [];
|
|
326
|
+
const beforeNames = new Set(Object.keys(before));
|
|
327
|
+
const afterNames = new Set(Object.keys(after));
|
|
328
|
+
for (const name of beforeNames) {
|
|
329
|
+
if (!afterNames.has(name)) {
|
|
330
|
+
changes.push({
|
|
331
|
+
type: "removed",
|
|
332
|
+
kind: name,
|
|
333
|
+
severity: "breaking",
|
|
334
|
+
details: `Node kind "${name}" was removed`,
|
|
335
|
+
before: before[name]
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
for (const name of afterNames) {
|
|
340
|
+
if (!beforeNames.has(name)) {
|
|
341
|
+
changes.push({
|
|
342
|
+
type: "added",
|
|
343
|
+
kind: name,
|
|
344
|
+
severity: "safe",
|
|
345
|
+
details: `Node kind "${name}" was added`,
|
|
346
|
+
after: after[name]
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
for (const name of beforeNames) {
|
|
351
|
+
if (afterNames.has(name)) {
|
|
352
|
+
const nodeBefore = before[name];
|
|
353
|
+
const nodeAfter = after[name];
|
|
354
|
+
const nodeChanges = diffNodeDef(name, nodeBefore, nodeAfter);
|
|
355
|
+
changes.push(...nodeChanges);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return changes;
|
|
359
|
+
}
|
|
360
|
+
function diffNodeDef(name, before, after) {
|
|
361
|
+
const changes = [];
|
|
362
|
+
if (!canonicalEqual(before.properties, after.properties)) {
|
|
363
|
+
const beforeProps = before.properties.properties ?? {};
|
|
364
|
+
const afterProps = after.properties.properties ?? {};
|
|
365
|
+
const beforeRequired = new Set(before.properties.required);
|
|
366
|
+
const afterRequired = new Set(after.properties.required);
|
|
367
|
+
const addedProps = Object.keys(afterProps).filter(
|
|
368
|
+
(p) => !(p in beforeProps)
|
|
369
|
+
);
|
|
370
|
+
const removedProps = Object.keys(beforeProps).filter(
|
|
371
|
+
(p) => !(p in afterProps)
|
|
372
|
+
);
|
|
373
|
+
const newRequired = [...afterRequired].filter(
|
|
374
|
+
(p) => !beforeRequired.has(p)
|
|
375
|
+
);
|
|
376
|
+
const { severity, details } = computePropertyChangeSeverity(
|
|
377
|
+
name,
|
|
378
|
+
removedProps,
|
|
379
|
+
addedProps,
|
|
380
|
+
newRequired
|
|
381
|
+
);
|
|
382
|
+
changes.push({
|
|
383
|
+
type: "modified",
|
|
384
|
+
kind: name,
|
|
385
|
+
severity,
|
|
386
|
+
details,
|
|
387
|
+
before,
|
|
388
|
+
after
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
if (before.onDelete !== after.onDelete) {
|
|
392
|
+
changes.push({
|
|
393
|
+
type: "modified",
|
|
394
|
+
kind: name,
|
|
395
|
+
severity: "warning",
|
|
396
|
+
details: `onDelete changed from "${before.onDelete}" to "${after.onDelete}" for "${name}"`,
|
|
397
|
+
before,
|
|
398
|
+
after
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
if (!canonicalEqual(before.uniqueConstraints, after.uniqueConstraints)) {
|
|
402
|
+
changes.push({
|
|
403
|
+
type: "modified",
|
|
404
|
+
kind: name,
|
|
405
|
+
severity: "warning",
|
|
406
|
+
details: `Unique constraints changed for "${name}"`,
|
|
407
|
+
before,
|
|
408
|
+
after
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
if (annotationsChanged(before.annotations, after.annotations)) {
|
|
412
|
+
changes.push({
|
|
413
|
+
type: "modified",
|
|
414
|
+
kind: name,
|
|
415
|
+
severity: "safe",
|
|
416
|
+
details: `Annotations changed for "${name}"`,
|
|
417
|
+
before,
|
|
418
|
+
after
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return changes;
|
|
422
|
+
}
|
|
423
|
+
function computePropertyChangeSeverity(name, removedProps, addedProps, newRequired) {
|
|
424
|
+
if (removedProps.length > 0) {
|
|
425
|
+
return {
|
|
426
|
+
severity: "breaking",
|
|
427
|
+
details: `Properties removed from "${name}": ${removedProps.join(", ")}`
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
if (newRequired.length > 0) {
|
|
431
|
+
return {
|
|
432
|
+
severity: "breaking",
|
|
433
|
+
details: `New required properties in "${name}": ${newRequired.join(", ")}`
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
if (addedProps.length > 0) {
|
|
437
|
+
return {
|
|
438
|
+
severity: "safe",
|
|
439
|
+
details: `Properties added to "${name}": ${addedProps.join(", ")}`
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
severity: "safe",
|
|
444
|
+
details: `Properties changed in "${name}"`
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function diffEdges(before, after) {
|
|
448
|
+
const changes = [];
|
|
449
|
+
const beforeNames = new Set(Object.keys(before));
|
|
450
|
+
const afterNames = new Set(Object.keys(after));
|
|
451
|
+
for (const name of beforeNames) {
|
|
452
|
+
if (!afterNames.has(name)) {
|
|
453
|
+
changes.push({
|
|
454
|
+
type: "removed",
|
|
455
|
+
kind: name,
|
|
456
|
+
severity: "breaking",
|
|
457
|
+
details: `Edge kind "${name}" was removed`,
|
|
458
|
+
before: before[name]
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
for (const name of afterNames) {
|
|
463
|
+
if (!beforeNames.has(name)) {
|
|
464
|
+
changes.push({
|
|
465
|
+
type: "added",
|
|
466
|
+
kind: name,
|
|
467
|
+
severity: "safe",
|
|
468
|
+
details: `Edge kind "${name}" was added`,
|
|
469
|
+
after: after[name]
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
for (const name of beforeNames) {
|
|
474
|
+
if (afterNames.has(name)) {
|
|
475
|
+
const edgeBefore = before[name];
|
|
476
|
+
const edgeAfter = after[name];
|
|
477
|
+
const edgeChanges = diffEdgeDef(name, edgeBefore, edgeAfter);
|
|
478
|
+
changes.push(...edgeChanges);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return changes;
|
|
482
|
+
}
|
|
483
|
+
function diffEdgeDef(name, before, after) {
|
|
484
|
+
const changes = [];
|
|
485
|
+
if (!canonicalEqual(before.fromKinds, after.fromKinds)) {
|
|
486
|
+
changes.push({
|
|
487
|
+
type: "modified",
|
|
488
|
+
kind: name,
|
|
489
|
+
severity: "warning",
|
|
490
|
+
details: `fromKinds changed for "${name}"`,
|
|
491
|
+
before,
|
|
492
|
+
after
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
if (!canonicalEqual(before.toKinds, after.toKinds)) {
|
|
496
|
+
changes.push({
|
|
497
|
+
type: "modified",
|
|
498
|
+
kind: name,
|
|
499
|
+
severity: "warning",
|
|
500
|
+
details: `toKinds changed for "${name}"`,
|
|
501
|
+
before,
|
|
502
|
+
after
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
if (before.cardinality !== after.cardinality) {
|
|
506
|
+
changes.push({
|
|
507
|
+
type: "modified",
|
|
508
|
+
kind: name,
|
|
509
|
+
severity: "warning",
|
|
510
|
+
details: `Cardinality changed from "${before.cardinality}" to "${after.cardinality}" for "${name}"`,
|
|
511
|
+
before,
|
|
512
|
+
after
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
if (!canonicalEqual(before.properties, after.properties)) {
|
|
516
|
+
changes.push({
|
|
517
|
+
type: "modified",
|
|
518
|
+
kind: name,
|
|
519
|
+
severity: "safe",
|
|
520
|
+
details: `Properties changed for "${name}"`,
|
|
521
|
+
before,
|
|
522
|
+
after
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
if (annotationsChanged(before.annotations, after.annotations)) {
|
|
526
|
+
changes.push({
|
|
527
|
+
type: "modified",
|
|
528
|
+
kind: name,
|
|
529
|
+
severity: "safe",
|
|
530
|
+
details: `Annotations changed for "${name}"`,
|
|
531
|
+
before,
|
|
532
|
+
after
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
return changes;
|
|
536
|
+
}
|
|
537
|
+
function annotationsChanged(before, after) {
|
|
538
|
+
if (before === void 0 && after === void 0) return false;
|
|
539
|
+
if (before === void 0 || after === void 0) return true;
|
|
540
|
+
return !canonicalEqual(before, after);
|
|
541
|
+
}
|
|
542
|
+
function diffOntology(before, after) {
|
|
543
|
+
const changes = [];
|
|
544
|
+
const metaEdgesBefore = new Set(Object.keys(before.metaEdges));
|
|
545
|
+
const metaEdgesAfter = new Set(Object.keys(after.metaEdges));
|
|
546
|
+
for (const name of metaEdgesBefore) {
|
|
547
|
+
if (!metaEdgesAfter.has(name)) {
|
|
548
|
+
changes.push({
|
|
549
|
+
type: "removed",
|
|
550
|
+
entity: "metaEdge",
|
|
551
|
+
name,
|
|
552
|
+
severity: "breaking",
|
|
553
|
+
details: `Meta-edge "${name}" was removed`
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
for (const name of metaEdgesAfter) {
|
|
558
|
+
if (!metaEdgesBefore.has(name)) {
|
|
559
|
+
changes.push({
|
|
560
|
+
type: "added",
|
|
561
|
+
entity: "metaEdge",
|
|
562
|
+
name,
|
|
563
|
+
severity: "safe",
|
|
564
|
+
details: `Meta-edge "${name}" was added`
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const relationsBefore = new Set(
|
|
569
|
+
before.relations.map((r) => `${r.metaEdge}:${r.from}:${r.to}`)
|
|
570
|
+
);
|
|
571
|
+
const relationsAfter = new Set(
|
|
572
|
+
after.relations.map((r) => `${r.metaEdge}:${r.from}:${r.to}`)
|
|
573
|
+
);
|
|
574
|
+
for (const relationKey of relationsBefore) {
|
|
575
|
+
if (!relationsAfter.has(relationKey)) {
|
|
576
|
+
const [metaEdge, from, to] = relationKey.split(":");
|
|
577
|
+
changes.push({
|
|
578
|
+
type: "removed",
|
|
579
|
+
entity: "relation",
|
|
580
|
+
name: relationKey,
|
|
581
|
+
severity: "warning",
|
|
582
|
+
details: `Relation ${metaEdge}(${from}, ${to}) was removed`
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
for (const relationKey of relationsAfter) {
|
|
587
|
+
if (!relationsBefore.has(relationKey)) {
|
|
588
|
+
const [metaEdge, from, to] = relationKey.split(":");
|
|
589
|
+
changes.push({
|
|
590
|
+
type: "added",
|
|
591
|
+
entity: "relation",
|
|
592
|
+
name: relationKey,
|
|
593
|
+
severity: "safe",
|
|
594
|
+
details: `Relation ${metaEdge}(${from}, ${to}) was added`
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return changes;
|
|
599
|
+
}
|
|
600
|
+
function diffIndexes(before, after) {
|
|
601
|
+
const beforeIndexes = before ?? [];
|
|
602
|
+
const afterIndexes = after ?? [];
|
|
603
|
+
const beforeByName = /* @__PURE__ */ new Map();
|
|
604
|
+
for (const index of beforeIndexes) {
|
|
605
|
+
beforeByName.set(index.name, index);
|
|
606
|
+
}
|
|
607
|
+
const afterByName = /* @__PURE__ */ new Map();
|
|
608
|
+
for (const index of afterIndexes) {
|
|
609
|
+
afterByName.set(index.name, index);
|
|
610
|
+
}
|
|
611
|
+
const changes = [];
|
|
612
|
+
for (const [name, index] of beforeByName) {
|
|
613
|
+
if (!afterByName.has(name)) {
|
|
614
|
+
changes.push({
|
|
615
|
+
type: "removed",
|
|
616
|
+
name,
|
|
617
|
+
entity: index.entity,
|
|
618
|
+
severity: "safe",
|
|
619
|
+
details: `Index "${name}" was removed`,
|
|
620
|
+
before: index
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
for (const [name, index] of afterByName) {
|
|
625
|
+
if (!beforeByName.has(name)) {
|
|
626
|
+
changes.push({
|
|
627
|
+
type: "added",
|
|
628
|
+
name,
|
|
629
|
+
entity: index.entity,
|
|
630
|
+
severity: "safe",
|
|
631
|
+
details: `Index "${name}" was added`,
|
|
632
|
+
after: index
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
for (const [name, beforeIndex] of beforeByName) {
|
|
637
|
+
const afterIndex = afterByName.get(name);
|
|
638
|
+
if (!afterIndex) continue;
|
|
639
|
+
if (!canonicalEqual(beforeIndex, afterIndex)) {
|
|
640
|
+
changes.push({
|
|
641
|
+
type: "modified",
|
|
642
|
+
name,
|
|
643
|
+
entity: beforeIndex.entity,
|
|
644
|
+
severity: "safe",
|
|
645
|
+
details: `Index "${name}" was modified`,
|
|
646
|
+
before: beforeIndex,
|
|
647
|
+
after: afterIndex
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return changes;
|
|
652
|
+
}
|
|
653
|
+
function diffExtension(before, after) {
|
|
654
|
+
if (before === after) return void 0;
|
|
655
|
+
if (before === void 0) {
|
|
656
|
+
return {
|
|
657
|
+
type: "added",
|
|
658
|
+
severity: "safe",
|
|
659
|
+
details: "Graph extension document was added"
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
if (after === void 0) {
|
|
663
|
+
return {
|
|
664
|
+
type: "removed",
|
|
665
|
+
severity: "safe",
|
|
666
|
+
details: "Graph extension document was removed"
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
if (canonicalEqual(before, after)) return void 0;
|
|
670
|
+
return {
|
|
671
|
+
type: "modified",
|
|
672
|
+
severity: "safe",
|
|
673
|
+
details: "Graph extension document was modified"
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
function diffDeprecatedKinds(before, after) {
|
|
677
|
+
const beforeSet = new Set(before);
|
|
678
|
+
const afterSet = new Set(after);
|
|
679
|
+
const added = [];
|
|
680
|
+
const removed = [];
|
|
681
|
+
for (const name of afterSet) {
|
|
682
|
+
if (!beforeSet.has(name)) added.push(name);
|
|
683
|
+
}
|
|
684
|
+
for (const name of beforeSet) {
|
|
685
|
+
if (!afterSet.has(name)) removed.push(name);
|
|
686
|
+
}
|
|
687
|
+
if (added.length === 0 && removed.length === 0) return void 0;
|
|
688
|
+
added.sort();
|
|
689
|
+
removed.sort();
|
|
690
|
+
const parts = [];
|
|
691
|
+
if (added.length > 0) parts.push(`added ${added.join(", ")}`);
|
|
692
|
+
if (removed.length > 0) parts.push(`removed ${removed.join(", ")}`);
|
|
693
|
+
return {
|
|
694
|
+
added,
|
|
695
|
+
removed,
|
|
696
|
+
severity: "safe",
|
|
697
|
+
details: `Deprecated kinds: ${parts.join("; ")}`
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
function generateSummary(nodeChanges, edgeChanges, ontologyChanges, indexChanges, extensionChange, deprecatedKindsChange) {
|
|
701
|
+
const parts = [];
|
|
702
|
+
const nodeAdded = nodeChanges.filter((c) => c.type === "added").length;
|
|
703
|
+
const nodeRemoved = nodeChanges.filter((c) => c.type === "removed").length;
|
|
704
|
+
const nodeModified = nodeChanges.filter((c) => c.type === "modified").length;
|
|
705
|
+
if (nodeAdded > 0 || nodeRemoved > 0 || nodeModified > 0) {
|
|
706
|
+
parts.push(
|
|
707
|
+
`Nodes: ${nodeAdded} added, ${nodeRemoved} removed, ${nodeModified} modified`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
const edgeAdded = edgeChanges.filter((c) => c.type === "added").length;
|
|
711
|
+
const edgeRemoved = edgeChanges.filter((c) => c.type === "removed").length;
|
|
712
|
+
const edgeModified = edgeChanges.filter((c) => c.type === "modified").length;
|
|
713
|
+
if (edgeAdded > 0 || edgeRemoved > 0 || edgeModified > 0) {
|
|
714
|
+
parts.push(
|
|
715
|
+
`Edges: ${edgeAdded} added, ${edgeRemoved} removed, ${edgeModified} modified`
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
const ontologyAdded = ontologyChanges.filter(
|
|
719
|
+
(c) => c.type === "added"
|
|
720
|
+
).length;
|
|
721
|
+
const ontologyRemoved = ontologyChanges.filter(
|
|
722
|
+
(c) => c.type === "removed"
|
|
723
|
+
).length;
|
|
724
|
+
if (ontologyAdded > 0 || ontologyRemoved > 0) {
|
|
725
|
+
parts.push(`Ontology: ${ontologyAdded} added, ${ontologyRemoved} removed`);
|
|
726
|
+
}
|
|
727
|
+
const indexAdded = indexChanges.filter((c) => c.type === "added").length;
|
|
728
|
+
const indexRemoved = indexChanges.filter((c) => c.type === "removed").length;
|
|
729
|
+
const indexModified = indexChanges.filter(
|
|
730
|
+
(c) => c.type === "modified"
|
|
731
|
+
).length;
|
|
732
|
+
if (indexAdded > 0 || indexRemoved > 0 || indexModified > 0) {
|
|
733
|
+
parts.push(
|
|
734
|
+
`Indexes: ${indexAdded} added, ${indexRemoved} removed, ${indexModified} modified`
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
if (extensionChange !== void 0) {
|
|
738
|
+
parts.push(`Graph extension document: ${extensionChange.type}`);
|
|
739
|
+
}
|
|
740
|
+
if (deprecatedKindsChange !== void 0) {
|
|
741
|
+
const { added, removed } = deprecatedKindsChange;
|
|
742
|
+
parts.push(
|
|
743
|
+
`Deprecated kinds: ${added.length} added, ${removed.length} removed`
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
if (parts.length === 0) {
|
|
747
|
+
return "No changes";
|
|
748
|
+
}
|
|
749
|
+
return parts.join("; ");
|
|
750
|
+
}
|
|
751
|
+
function isBackwardsCompatible(diff) {
|
|
752
|
+
return !diff.hasBreakingChanges;
|
|
753
|
+
}
|
|
754
|
+
function getMigrationActions(diff) {
|
|
755
|
+
const actions = [];
|
|
756
|
+
for (const change of diff.nodes) {
|
|
757
|
+
if (change.type === "removed") {
|
|
758
|
+
actions.push(`DELETE data for removed node kind "${change.kind}"`);
|
|
759
|
+
}
|
|
760
|
+
if (change.severity === "breaking" && change.type === "modified") {
|
|
761
|
+
actions.push(
|
|
762
|
+
`MIGRATE data for node kind "${change.kind}": ${change.details}`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
for (const change of diff.edges) {
|
|
767
|
+
if (change.type === "removed") {
|
|
768
|
+
actions.push(`DELETE data for removed edge kind "${change.kind}"`);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return actions;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// src/registry/kind-registry.ts
|
|
775
|
+
var KindRegistry = class {
|
|
776
|
+
// === Node & Edge Kinds ===
|
|
777
|
+
nodeKinds;
|
|
778
|
+
edgeKinds;
|
|
779
|
+
// === Subsumption (subClassOf) ===
|
|
780
|
+
// Transitive closure for inheritance
|
|
781
|
+
subClassAncestors;
|
|
782
|
+
subClassDescendants;
|
|
783
|
+
// === Hierarchy (broader/narrower) ===
|
|
784
|
+
// Transitive closure for concept hierarchy (separate from subClassOf!)
|
|
785
|
+
broaderClosure;
|
|
786
|
+
narrowerClosure;
|
|
787
|
+
// === Equivalence ===
|
|
788
|
+
equivalenceSets;
|
|
789
|
+
iriToKind;
|
|
790
|
+
// === Constraints ===
|
|
791
|
+
disjointPairs;
|
|
792
|
+
// Normalized pairs: "Organization|Person"
|
|
793
|
+
// === Composition ===
|
|
794
|
+
partOfClosure;
|
|
795
|
+
hasPartClosure;
|
|
796
|
+
// === Edge Relationships ===
|
|
797
|
+
edgeInverses;
|
|
798
|
+
edgeImplicationsClosure;
|
|
799
|
+
edgeImplyingClosure;
|
|
800
|
+
constructor(nodeKinds, edgeKinds, closures) {
|
|
801
|
+
this.nodeKinds = nodeKinds;
|
|
802
|
+
this.edgeKinds = edgeKinds;
|
|
803
|
+
this.subClassAncestors = closures.subClassAncestors;
|
|
804
|
+
this.subClassDescendants = closures.subClassDescendants;
|
|
805
|
+
this.broaderClosure = closures.broaderClosure;
|
|
806
|
+
this.narrowerClosure = closures.narrowerClosure;
|
|
807
|
+
this.equivalenceSets = closures.equivalenceSets;
|
|
808
|
+
this.iriToKind = closures.iriToKind;
|
|
809
|
+
this.disjointPairs = closures.disjointPairs;
|
|
810
|
+
this.partOfClosure = closures.partOfClosure;
|
|
811
|
+
this.hasPartClosure = closures.hasPartClosure;
|
|
812
|
+
this.edgeInverses = closures.edgeInverses;
|
|
813
|
+
this.edgeImplicationsClosure = closures.edgeImplicationsClosure;
|
|
814
|
+
this.edgeImplyingClosure = closures.edgeImplyingClosure;
|
|
815
|
+
}
|
|
816
|
+
// === Subsumption Methods ===
|
|
817
|
+
/**
|
|
818
|
+
* Checks if child is a subclass of parent (directly or transitively).
|
|
819
|
+
*/
|
|
820
|
+
isSubClassOf(child, parent) {
|
|
821
|
+
return chunkRCAJZG67_cjs.isReachable(this.subClassAncestors, child, parent);
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Expands a kind to include all its subclasses.
|
|
825
|
+
* Returns [kind, ...subclasses].
|
|
826
|
+
*/
|
|
827
|
+
expandSubClasses(kind) {
|
|
828
|
+
const descendants = this.subClassDescendants.get(kind) ?? /* @__PURE__ */ new Set();
|
|
829
|
+
return [kind, ...descendants];
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Gets all ancestors of a kind (via subClassOf).
|
|
833
|
+
*/
|
|
834
|
+
getAncestors(kind) {
|
|
835
|
+
return this.subClassAncestors.get(kind) ?? /* @__PURE__ */ new Set();
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Gets all descendants of a kind (via subClassOf).
|
|
839
|
+
*/
|
|
840
|
+
getDescendants(kind) {
|
|
841
|
+
return this.subClassDescendants.get(kind) ?? /* @__PURE__ */ new Set();
|
|
842
|
+
}
|
|
843
|
+
// === Hierarchy Methods ===
|
|
844
|
+
/**
|
|
845
|
+
* Checks if narrowerConcept is narrower than broaderConcept.
|
|
846
|
+
*/
|
|
847
|
+
isNarrowerThan(narrowerConcept, broaderConcept) {
|
|
848
|
+
return chunkRCAJZG67_cjs.isReachable(this.broaderClosure, narrowerConcept, broaderConcept);
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Checks if broaderConcept is broader than narrowerConcept.
|
|
852
|
+
*/
|
|
853
|
+
isBroaderThan(broaderConcept, narrowerConcept) {
|
|
854
|
+
return chunkRCAJZG67_cjs.isReachable(this.narrowerClosure, broaderConcept, narrowerConcept);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Expands to include all narrower concepts.
|
|
858
|
+
*/
|
|
859
|
+
expandNarrower(kind) {
|
|
860
|
+
const narrower2 = this.narrowerClosure.get(kind) ?? /* @__PURE__ */ new Set();
|
|
861
|
+
return [kind, ...narrower2];
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Expands to include all broader concepts.
|
|
865
|
+
*/
|
|
866
|
+
expandBroader(kind) {
|
|
867
|
+
const broader2 = this.broaderClosure.get(kind) ?? /* @__PURE__ */ new Set();
|
|
868
|
+
return [kind, ...broader2];
|
|
869
|
+
}
|
|
870
|
+
// === Equivalence Methods ===
|
|
871
|
+
/**
|
|
872
|
+
* Checks if two kinds are equivalent.
|
|
873
|
+
*/
|
|
874
|
+
areEquivalent(a, b) {
|
|
875
|
+
const equivalents = this.equivalenceSets.get(a);
|
|
876
|
+
return equivalents?.has(b) ?? false;
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Gets all equivalents of a kind (including external IRIs).
|
|
880
|
+
*/
|
|
881
|
+
getEquivalents(kind) {
|
|
882
|
+
const equivalents = this.equivalenceSets.get(kind);
|
|
883
|
+
return equivalents ? [...equivalents] : [];
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Resolves an external IRI to an internal kind name.
|
|
887
|
+
*/
|
|
888
|
+
resolveIri(iri) {
|
|
889
|
+
return this.iriToKind.get(iri);
|
|
890
|
+
}
|
|
891
|
+
// === Constraint Methods ===
|
|
892
|
+
/**
|
|
893
|
+
* Checks if two kinds are disjoint.
|
|
894
|
+
*/
|
|
895
|
+
areDisjoint(a, b) {
|
|
896
|
+
const normalizedPair = a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
897
|
+
return this.disjointPairs.has(normalizedPair);
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Gets all kinds that are disjoint with the given kind.
|
|
901
|
+
*/
|
|
902
|
+
getDisjointKinds(kind) {
|
|
903
|
+
const result = [];
|
|
904
|
+
for (const pair of this.disjointPairs) {
|
|
905
|
+
const parts = pair.split("|");
|
|
906
|
+
const firstKind = parts[0];
|
|
907
|
+
const secondKind = parts[1];
|
|
908
|
+
if (firstKind === kind) result.push(secondKind);
|
|
909
|
+
else if (secondKind === kind) result.push(firstKind);
|
|
910
|
+
}
|
|
911
|
+
return result;
|
|
912
|
+
}
|
|
913
|
+
// === Composition Methods ===
|
|
914
|
+
/**
|
|
915
|
+
* Checks if part is part of whole (directly or transitively).
|
|
916
|
+
*/
|
|
917
|
+
isPartOf(part, whole) {
|
|
918
|
+
return chunkRCAJZG67_cjs.isReachable(this.partOfClosure, part, whole);
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Gets all wholes that contain this part.
|
|
922
|
+
*/
|
|
923
|
+
getWholes(part) {
|
|
924
|
+
const wholes = this.partOfClosure.get(part);
|
|
925
|
+
return wholes ? [...wholes] : [];
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Gets all parts of this whole.
|
|
929
|
+
*/
|
|
930
|
+
getParts(whole) {
|
|
931
|
+
const parts = this.hasPartClosure.get(whole);
|
|
932
|
+
return parts ? [...parts] : [];
|
|
933
|
+
}
|
|
934
|
+
// === Edge Relationship Methods ===
|
|
935
|
+
/**
|
|
936
|
+
* Gets the inverse edge kind for a given edge kind.
|
|
937
|
+
* If edgeA inverseOf edgeB, then getInverseEdge("edgeA") returns "edgeB".
|
|
938
|
+
*/
|
|
939
|
+
getInverseEdge(edgeKind) {
|
|
940
|
+
return this.edgeInverses.get(edgeKind);
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Gets all edges implied by a given edge (transitively).
|
|
944
|
+
* If A implies B and B implies C, then getImpliedEdges("A") returns ["B", "C"].
|
|
945
|
+
*/
|
|
946
|
+
getImpliedEdges(edgeKind) {
|
|
947
|
+
const implied = this.edgeImplicationsClosure.get(edgeKind);
|
|
948
|
+
return implied ? [...implied] : [];
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Gets all edges that imply a given edge (transitively).
|
|
952
|
+
* If A implies B and B implies C, then getImplyingEdges("C") returns ["A", "B"].
|
|
953
|
+
* Used for query-time expansion: when querying for C, also include A and B edges.
|
|
954
|
+
*/
|
|
955
|
+
getImplyingEdges(edgeKind) {
|
|
956
|
+
const implying = this.edgeImplyingClosure.get(edgeKind);
|
|
957
|
+
return implying ? [...implying] : [];
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Expands an edge kind to include all edges that imply it.
|
|
961
|
+
* Returns [edgeKind, ...implyingEdges].
|
|
962
|
+
*/
|
|
963
|
+
expandImplyingEdges(edgeKind) {
|
|
964
|
+
const implying = this.edgeImplyingClosure.get(edgeKind) ?? /* @__PURE__ */ new Set();
|
|
965
|
+
return [edgeKind, ...implying];
|
|
966
|
+
}
|
|
967
|
+
// === Edge Endpoint Validation ===
|
|
968
|
+
/**
|
|
969
|
+
* Checks if a concrete kind is assignable to a target kind.
|
|
970
|
+
* Uses subsumption: Company is assignable to Organization if Company subClassOf Organization.
|
|
971
|
+
*/
|
|
972
|
+
isAssignableTo(concreteKind, targetKind) {
|
|
973
|
+
if (concreteKind === targetKind) return true;
|
|
974
|
+
return this.isSubClassOf(concreteKind, targetKind);
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Validates that a kind exists in the registry.
|
|
978
|
+
*/
|
|
979
|
+
hasNodeType(name) {
|
|
980
|
+
return this.nodeKinds.has(name);
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Validates that an edge kind exists in the registry.
|
|
984
|
+
*/
|
|
985
|
+
hasEdgeType(name) {
|
|
986
|
+
return this.edgeKinds.has(name);
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Gets a node kind by name.
|
|
990
|
+
*/
|
|
991
|
+
getNodeType(name) {
|
|
992
|
+
return this.nodeKinds.get(name);
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Gets an edge kind by name.
|
|
996
|
+
*/
|
|
997
|
+
getEdgeType(name) {
|
|
998
|
+
return this.edgeKinds.get(name);
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
function createEmptyClosures() {
|
|
1002
|
+
return {
|
|
1003
|
+
subClassAncestors: /* @__PURE__ */ new Map(),
|
|
1004
|
+
subClassDescendants: /* @__PURE__ */ new Map(),
|
|
1005
|
+
broaderClosure: /* @__PURE__ */ new Map(),
|
|
1006
|
+
narrowerClosure: /* @__PURE__ */ new Map(),
|
|
1007
|
+
equivalenceSets: /* @__PURE__ */ new Map(),
|
|
1008
|
+
iriToKind: /* @__PURE__ */ new Map(),
|
|
1009
|
+
disjointPairs: /* @__PURE__ */ new Set(),
|
|
1010
|
+
partOfClosure: /* @__PURE__ */ new Map(),
|
|
1011
|
+
hasPartClosure: /* @__PURE__ */ new Map(),
|
|
1012
|
+
edgeInverses: /* @__PURE__ */ new Map(),
|
|
1013
|
+
edgeImplicationsClosure: /* @__PURE__ */ new Map(),
|
|
1014
|
+
edgeImplyingClosure: /* @__PURE__ */ new Map()
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
function computeClosuresFromOntology(ontology) {
|
|
1018
|
+
const subClassRelations = [];
|
|
1019
|
+
const broaderRelations = [];
|
|
1020
|
+
const equivalentRelations = [];
|
|
1021
|
+
const disjointRelations = [];
|
|
1022
|
+
const partOfRelations = [];
|
|
1023
|
+
const inverseOfRelations = [];
|
|
1024
|
+
const impliesRelations = [];
|
|
1025
|
+
for (const relation of ontology) {
|
|
1026
|
+
const fromName = getKindName(relation.from);
|
|
1027
|
+
const toName = getKindName(relation.to);
|
|
1028
|
+
switch (relation.metaEdge.name) {
|
|
1029
|
+
case chunkRCAJZG67_cjs.META_EDGE_SUB_CLASS_OF: {
|
|
1030
|
+
subClassRelations.push([fromName, toName]);
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
case chunkRCAJZG67_cjs.META_EDGE_BROADER: {
|
|
1034
|
+
broaderRelations.push([fromName, toName]);
|
|
1035
|
+
break;
|
|
1036
|
+
}
|
|
1037
|
+
case chunkRCAJZG67_cjs.META_EDGE_NARROWER: {
|
|
1038
|
+
broaderRelations.push([toName, fromName]);
|
|
1039
|
+
break;
|
|
1040
|
+
}
|
|
1041
|
+
case chunkRCAJZG67_cjs.META_EDGE_EQUIVALENT_TO:
|
|
1042
|
+
case chunkRCAJZG67_cjs.META_EDGE_SAME_AS: {
|
|
1043
|
+
equivalentRelations.push([fromName, toName]);
|
|
1044
|
+
break;
|
|
1045
|
+
}
|
|
1046
|
+
case chunkRCAJZG67_cjs.META_EDGE_DISJOINT_WITH: {
|
|
1047
|
+
disjointRelations.push([fromName, toName]);
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
case chunkRCAJZG67_cjs.META_EDGE_PART_OF: {
|
|
1051
|
+
partOfRelations.push([fromName, toName]);
|
|
1052
|
+
break;
|
|
1053
|
+
}
|
|
1054
|
+
case chunkRCAJZG67_cjs.META_EDGE_HAS_PART: {
|
|
1055
|
+
partOfRelations.push([toName, fromName]);
|
|
1056
|
+
break;
|
|
1057
|
+
}
|
|
1058
|
+
case chunkRCAJZG67_cjs.META_EDGE_INVERSE_OF: {
|
|
1059
|
+
inverseOfRelations.push([fromName, toName]);
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
case chunkRCAJZG67_cjs.META_EDGE_IMPLIES: {
|
|
1063
|
+
impliesRelations.push([fromName, toName]);
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
const subClassAncestors = chunkRCAJZG67_cjs.computeTransitiveClosure(subClassRelations);
|
|
1069
|
+
const subClassDescendants = chunkRCAJZG67_cjs.invertClosure(subClassAncestors);
|
|
1070
|
+
const broaderClosure = chunkRCAJZG67_cjs.computeTransitiveClosure(broaderRelations);
|
|
1071
|
+
const narrowerClosure = chunkRCAJZG67_cjs.invertClosure(broaderClosure);
|
|
1072
|
+
const equivalenceSets = computeEquivalenceSets(equivalentRelations);
|
|
1073
|
+
const iriToKind = computeIriMapping(equivalentRelations);
|
|
1074
|
+
const disjointPairs = computeDisjointPairs(disjointRelations);
|
|
1075
|
+
const partOfClosure = chunkRCAJZG67_cjs.computeTransitiveClosure(partOfRelations);
|
|
1076
|
+
const hasPartClosure = chunkRCAJZG67_cjs.invertClosure(partOfClosure);
|
|
1077
|
+
const edgeInverses = computeEdgeInverses(inverseOfRelations);
|
|
1078
|
+
const edgeImplicationsClosure = chunkRCAJZG67_cjs.computeTransitiveClosure(impliesRelations);
|
|
1079
|
+
const edgeImplyingClosure = chunkRCAJZG67_cjs.invertClosure(edgeImplicationsClosure);
|
|
1080
|
+
return {
|
|
1081
|
+
subClassAncestors,
|
|
1082
|
+
subClassDescendants,
|
|
1083
|
+
broaderClosure,
|
|
1084
|
+
narrowerClosure,
|
|
1085
|
+
equivalenceSets,
|
|
1086
|
+
iriToKind,
|
|
1087
|
+
disjointPairs,
|
|
1088
|
+
partOfClosure,
|
|
1089
|
+
hasPartClosure,
|
|
1090
|
+
edgeInverses,
|
|
1091
|
+
edgeImplicationsClosure,
|
|
1092
|
+
edgeImplyingClosure
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
function getKindName(kindOrIri) {
|
|
1096
|
+
if (typeof kindOrIri === "string") {
|
|
1097
|
+
return kindOrIri;
|
|
1098
|
+
}
|
|
1099
|
+
return kindOrIri.kind;
|
|
1100
|
+
}
|
|
1101
|
+
function isExternalIri(value) {
|
|
1102
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
1103
|
+
}
|
|
1104
|
+
function computeEquivalenceSets(relations) {
|
|
1105
|
+
const parent = /* @__PURE__ */ new Map();
|
|
1106
|
+
function find(x) {
|
|
1107
|
+
if (!parent.has(x)) {
|
|
1108
|
+
parent.set(x, x);
|
|
1109
|
+
return x;
|
|
1110
|
+
}
|
|
1111
|
+
const parentNode = parent.get(x);
|
|
1112
|
+
if (parentNode === x) return x;
|
|
1113
|
+
const root = find(parentNode);
|
|
1114
|
+
parent.set(x, root);
|
|
1115
|
+
return root;
|
|
1116
|
+
}
|
|
1117
|
+
function union(a, b) {
|
|
1118
|
+
const rootA = find(a);
|
|
1119
|
+
const rootB = find(b);
|
|
1120
|
+
if (rootA !== rootB) {
|
|
1121
|
+
parent.set(rootA, rootB);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
for (const [a, b] of relations) {
|
|
1125
|
+
union(a, b);
|
|
1126
|
+
}
|
|
1127
|
+
const classes = /* @__PURE__ */ new Map();
|
|
1128
|
+
for (const key of parent.keys()) {
|
|
1129
|
+
const root = find(key);
|
|
1130
|
+
const existing = classes.get(root) ?? /* @__PURE__ */ new Set();
|
|
1131
|
+
existing.add(key);
|
|
1132
|
+
classes.set(root, existing);
|
|
1133
|
+
}
|
|
1134
|
+
const result = /* @__PURE__ */ new Map();
|
|
1135
|
+
for (const members of classes.values()) {
|
|
1136
|
+
for (const member of members) {
|
|
1137
|
+
const others = new Set(members);
|
|
1138
|
+
others.delete(member);
|
|
1139
|
+
result.set(member, others);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
return result;
|
|
1143
|
+
}
|
|
1144
|
+
function computeIriMapping(relations) {
|
|
1145
|
+
const result = /* @__PURE__ */ new Map();
|
|
1146
|
+
for (const [a, b] of relations) {
|
|
1147
|
+
if (isExternalIri(a) && !isExternalIri(b)) {
|
|
1148
|
+
result.set(a, b);
|
|
1149
|
+
} else if (isExternalIri(b) && !isExternalIri(a)) {
|
|
1150
|
+
result.set(b, a);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return result;
|
|
1154
|
+
}
|
|
1155
|
+
function computeDisjointPairs(relations) {
|
|
1156
|
+
const result = /* @__PURE__ */ new Set();
|
|
1157
|
+
for (const [a, b] of relations) {
|
|
1158
|
+
const normalized = a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
1159
|
+
result.add(normalized);
|
|
1160
|
+
}
|
|
1161
|
+
return result;
|
|
1162
|
+
}
|
|
1163
|
+
function computeEdgeInverses(relations) {
|
|
1164
|
+
const result = /* @__PURE__ */ new Map();
|
|
1165
|
+
for (const [a, b] of relations) {
|
|
1166
|
+
result.set(a, b);
|
|
1167
|
+
result.set(b, a);
|
|
1168
|
+
}
|
|
1169
|
+
return result;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// src/schema/serializer.ts
|
|
1173
|
+
function serializeSchema(graph, version) {
|
|
1174
|
+
const nodes = serializeNodes(graph);
|
|
1175
|
+
const edges = serializeEdges(graph);
|
|
1176
|
+
const ontology = serializeOntology(graph.ontology);
|
|
1177
|
+
const indexes = serializeIndexes(graph.indexes);
|
|
1178
|
+
const extension = canonicalExtension(graph.extension);
|
|
1179
|
+
const deprecatedKinds = serializeDeprecatedKinds(graph.deprecatedKinds);
|
|
1180
|
+
return {
|
|
1181
|
+
graphId: graph.id,
|
|
1182
|
+
version,
|
|
1183
|
+
generatedAt: chunkE5JZSEGJ_cjs.nowIso(),
|
|
1184
|
+
nodes,
|
|
1185
|
+
edges,
|
|
1186
|
+
ontology,
|
|
1187
|
+
defaults: {
|
|
1188
|
+
onNodeDelete: graph.defaults.onNodeDelete,
|
|
1189
|
+
temporalMode: graph.defaults.temporalMode
|
|
1190
|
+
},
|
|
1191
|
+
// `serializeIndexes` collapses both absent and empty inputs to
|
|
1192
|
+
// `undefined` (see the helper's docstring); omit the field entirely
|
|
1193
|
+
// in that case so legacy graphs hash byte-identically to the
|
|
1194
|
+
// pre-`indexes` form.
|
|
1195
|
+
...indexes === void 0 ? {} : { indexes },
|
|
1196
|
+
// The graph extension is the durable source the loader uses to
|
|
1197
|
+
// rebuild extension-kind Zod validators on restart. Omitted on
|
|
1198
|
+
// graphs that have never been extended so legacy schemas hash
|
|
1199
|
+
// byte-identically.
|
|
1200
|
+
...extension === void 0 ? {} : { extension },
|
|
1201
|
+
// Soft-deprecated kind names. Omitted when empty so legacy
|
|
1202
|
+
// schemas hash byte-identically; sorted for canonical-form
|
|
1203
|
+
// stability across insertion-order differences.
|
|
1204
|
+
...deprecatedKinds === void 0 ? {} : { deprecatedKinds }
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function serializeDeprecatedKinds(set) {
|
|
1208
|
+
if (set === void 0 || set.size === 0) return void 0;
|
|
1209
|
+
return [...set].toSorted();
|
|
1210
|
+
}
|
|
1211
|
+
function canonicalExtension(document) {
|
|
1212
|
+
if (document === void 0) return void 0;
|
|
1213
|
+
if (document.version === void 0) return document;
|
|
1214
|
+
if (document.version !== chunkRCAJZG67_cjs.LEGACY_GRAPH_EXTENSION_VERSION) return document;
|
|
1215
|
+
const { version: _omit, ...rest } = document;
|
|
1216
|
+
return rest;
|
|
1217
|
+
}
|
|
1218
|
+
function canonicalAnnotations(annotations) {
|
|
1219
|
+
if (annotations === void 0) return void 0;
|
|
1220
|
+
if (Object.keys(annotations).length === 0) return void 0;
|
|
1221
|
+
return annotations;
|
|
1222
|
+
}
|
|
1223
|
+
function serializeIndexes(indexes) {
|
|
1224
|
+
if (indexes === void 0 || indexes.length === 0) return void 0;
|
|
1225
|
+
return indexes.toSorted(
|
|
1226
|
+
(a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
1227
|
+
).map((index) => serializeIndexDeclaration(index));
|
|
1228
|
+
}
|
|
1229
|
+
function serializeIndexDeclaration(declaration) {
|
|
1230
|
+
if (declaration.entity === "node") {
|
|
1231
|
+
return serializeNodeIndexDeclaration(declaration);
|
|
1232
|
+
}
|
|
1233
|
+
if (declaration.entity === "edge") {
|
|
1234
|
+
return serializeEdgeIndexDeclaration(declaration);
|
|
1235
|
+
}
|
|
1236
|
+
return serializeVectorIndexDeclaration(declaration);
|
|
1237
|
+
}
|
|
1238
|
+
function serializeVectorIndexDeclaration(declaration) {
|
|
1239
|
+
return {
|
|
1240
|
+
entity: "vector",
|
|
1241
|
+
kind: declaration.kind,
|
|
1242
|
+
name: declaration.name,
|
|
1243
|
+
fieldPath: declaration.fieldPath,
|
|
1244
|
+
dimensions: declaration.dimensions,
|
|
1245
|
+
metric: declaration.metric,
|
|
1246
|
+
indexType: declaration.indexType,
|
|
1247
|
+
indexParams: declaration.indexParams,
|
|
1248
|
+
...declaration.origin === "runtime" ? { origin: "runtime" } : {}
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
function serializeNodeIndexDeclaration(declaration) {
|
|
1252
|
+
return {
|
|
1253
|
+
entity: "node",
|
|
1254
|
+
kind: declaration.kind,
|
|
1255
|
+
name: declaration.name,
|
|
1256
|
+
fields: declaration.fields,
|
|
1257
|
+
fieldValueTypes: declaration.fieldValueTypes,
|
|
1258
|
+
coveringFields: declaration.coveringFields,
|
|
1259
|
+
coveringFieldValueTypes: declaration.coveringFieldValueTypes,
|
|
1260
|
+
unique: declaration.unique,
|
|
1261
|
+
scope: declaration.scope,
|
|
1262
|
+
where: declaration.where,
|
|
1263
|
+
// `origin: "compile-time"` is the default and is omitted from the
|
|
1264
|
+
// canonical form (absence == compile-time). Only `runtime` is
|
|
1265
|
+
// emitted explicitly so the restart loader can route the declaration
|
|
1266
|
+
// through the runtime compiler.
|
|
1267
|
+
...declaration.origin === "runtime" ? { origin: "runtime" } : {}
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
function serializeEdgeIndexDeclaration(declaration) {
|
|
1271
|
+
return {
|
|
1272
|
+
entity: "edge",
|
|
1273
|
+
kind: declaration.kind,
|
|
1274
|
+
name: declaration.name,
|
|
1275
|
+
direction: declaration.direction,
|
|
1276
|
+
fields: declaration.fields,
|
|
1277
|
+
fieldValueTypes: declaration.fieldValueTypes,
|
|
1278
|
+
coveringFields: declaration.coveringFields,
|
|
1279
|
+
coveringFieldValueTypes: declaration.coveringFieldValueTypes,
|
|
1280
|
+
unique: declaration.unique,
|
|
1281
|
+
scope: declaration.scope,
|
|
1282
|
+
where: declaration.where,
|
|
1283
|
+
...declaration.origin === "runtime" ? { origin: "runtime" } : {}
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
function serializeNodes(graph) {
|
|
1287
|
+
const result = {};
|
|
1288
|
+
for (const kindName of chunkE5JZSEGJ_cjs.getNodeKinds(graph)) {
|
|
1289
|
+
const registration = graph.nodes[kindName];
|
|
1290
|
+
if (registration === void 0) continue;
|
|
1291
|
+
result[kindName] = serializeNodeDef(registration);
|
|
1292
|
+
}
|
|
1293
|
+
return result;
|
|
1294
|
+
}
|
|
1295
|
+
function serializeNodeDef(registration) {
|
|
1296
|
+
const node = registration.type;
|
|
1297
|
+
const annotations = canonicalAnnotations(node.annotations);
|
|
1298
|
+
return {
|
|
1299
|
+
kind: node.kind,
|
|
1300
|
+
properties: serializeZodSchema(node.schema),
|
|
1301
|
+
uniqueConstraints: serializeUniqueConstraints(registration.unique ?? []),
|
|
1302
|
+
onDelete: registration.onDelete ?? "restrict",
|
|
1303
|
+
description: node.description,
|
|
1304
|
+
...annotations === void 0 ? {} : { annotations }
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
function serializeUniqueConstraints(constraints) {
|
|
1308
|
+
return constraints.map((constraint) => ({
|
|
1309
|
+
name: constraint.name,
|
|
1310
|
+
fields: [...constraint.fields],
|
|
1311
|
+
where: constraint.where ? serializeWherePredicate(constraint.where) : void 0,
|
|
1312
|
+
scope: constraint.scope,
|
|
1313
|
+
collation: constraint.collation
|
|
1314
|
+
}));
|
|
1315
|
+
}
|
|
1316
|
+
function serializeWherePredicate(whereFunction) {
|
|
1317
|
+
const builder = new Proxy(
|
|
1318
|
+
{},
|
|
1319
|
+
{
|
|
1320
|
+
get(_target, field) {
|
|
1321
|
+
return {
|
|
1322
|
+
isNull: () => ({
|
|
1323
|
+
__type: "unique_predicate",
|
|
1324
|
+
field,
|
|
1325
|
+
op: "isNull"
|
|
1326
|
+
}),
|
|
1327
|
+
isNotNull: () => ({
|
|
1328
|
+
__type: "unique_predicate",
|
|
1329
|
+
field,
|
|
1330
|
+
op: "isNotNull"
|
|
1331
|
+
})
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
);
|
|
1336
|
+
const predicate = whereFunction(builder);
|
|
1337
|
+
return JSON.stringify({ field: predicate.field, op: predicate.op });
|
|
1338
|
+
}
|
|
1339
|
+
function deserializeWherePredicate(serialized) {
|
|
1340
|
+
const parsed = JSON.parse(serialized);
|
|
1341
|
+
return (builder) => {
|
|
1342
|
+
const fieldBuilder = builder[parsed.field];
|
|
1343
|
+
if (!fieldBuilder) {
|
|
1344
|
+
throw new Error(`Unknown field in where predicate: ${parsed.field}`);
|
|
1345
|
+
}
|
|
1346
|
+
const result = parsed.op === "isNull" ? fieldBuilder.isNull() : fieldBuilder.isNotNull();
|
|
1347
|
+
return {
|
|
1348
|
+
__type: "unique_predicate",
|
|
1349
|
+
field: result.field,
|
|
1350
|
+
op: result.op
|
|
1351
|
+
};
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
function serializeEdges(graph) {
|
|
1355
|
+
const result = {};
|
|
1356
|
+
for (const kindName of chunkE5JZSEGJ_cjs.getEdgeKinds(graph)) {
|
|
1357
|
+
const registration = graph.edges[kindName];
|
|
1358
|
+
if (registration === void 0) continue;
|
|
1359
|
+
result[kindName] = serializeEdgeDef(registration);
|
|
1360
|
+
}
|
|
1361
|
+
return result;
|
|
1362
|
+
}
|
|
1363
|
+
function serializeEdgeDef(registration) {
|
|
1364
|
+
const edge = registration.type;
|
|
1365
|
+
const annotations = canonicalAnnotations(edge.annotations);
|
|
1366
|
+
return {
|
|
1367
|
+
kind: edge.kind,
|
|
1368
|
+
fromKinds: registration.from.map((node) => node.kind),
|
|
1369
|
+
toKinds: registration.to.map((node) => node.kind),
|
|
1370
|
+
properties: serializeZodSchema(edge.schema),
|
|
1371
|
+
cardinality: registration.cardinality ?? "many",
|
|
1372
|
+
endpointExistence: registration.endpointExistence ?? "notDeleted",
|
|
1373
|
+
description: edge.description,
|
|
1374
|
+
...annotations === void 0 ? {} : { annotations }
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
function serializeOntology(relations) {
|
|
1378
|
+
const metaEdgeMap = /* @__PURE__ */ new Map();
|
|
1379
|
+
for (const relation of relations) {
|
|
1380
|
+
const metaEdge = relation.metaEdge;
|
|
1381
|
+
if (!metaEdgeMap.has(metaEdge.name)) {
|
|
1382
|
+
metaEdgeMap.set(metaEdge.name, metaEdge);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
const metaEdges = {};
|
|
1386
|
+
for (const [name, metaEdge] of metaEdgeMap) {
|
|
1387
|
+
metaEdges[name] = serializeMetaEdge(metaEdge);
|
|
1388
|
+
}
|
|
1389
|
+
const serializedRelations = relations.map(
|
|
1390
|
+
(relation) => serializeOntologyRelation(relation)
|
|
1391
|
+
);
|
|
1392
|
+
const closures = serializeClosures(relations);
|
|
1393
|
+
return {
|
|
1394
|
+
metaEdges,
|
|
1395
|
+
relations: serializedRelations,
|
|
1396
|
+
closures
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
function serializeMetaEdge(metaEdge) {
|
|
1400
|
+
return {
|
|
1401
|
+
name: metaEdge.name,
|
|
1402
|
+
transitive: metaEdge.properties.transitive,
|
|
1403
|
+
symmetric: metaEdge.properties.symmetric,
|
|
1404
|
+
reflexive: metaEdge.properties.reflexive,
|
|
1405
|
+
inverse: metaEdge.properties.inverse,
|
|
1406
|
+
inference: metaEdge.properties.inference,
|
|
1407
|
+
description: metaEdge.properties.description
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
function serializeOntologyRelation(relation) {
|
|
1411
|
+
return {
|
|
1412
|
+
metaEdge: relation.metaEdge.name,
|
|
1413
|
+
from: getTypeName(relation.from),
|
|
1414
|
+
to: getTypeName(relation.to)
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
function serializeClosures(relations) {
|
|
1418
|
+
if (relations.length === 0) {
|
|
1419
|
+
return {
|
|
1420
|
+
subClassAncestors: {},
|
|
1421
|
+
subClassDescendants: {},
|
|
1422
|
+
broaderClosure: {},
|
|
1423
|
+
narrowerClosure: {},
|
|
1424
|
+
equivalenceSets: {},
|
|
1425
|
+
disjointPairs: [],
|
|
1426
|
+
partOfClosure: {},
|
|
1427
|
+
hasPartClosure: {},
|
|
1428
|
+
iriToKind: {},
|
|
1429
|
+
edgeInverses: {},
|
|
1430
|
+
edgeImplicationsClosure: {},
|
|
1431
|
+
edgeImplyingClosure: {}
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
const computed = computeClosuresFromOntology(relations);
|
|
1435
|
+
return {
|
|
1436
|
+
subClassAncestors: mapToRecord(computed.subClassAncestors),
|
|
1437
|
+
subClassDescendants: mapToRecord(computed.subClassDescendants),
|
|
1438
|
+
broaderClosure: mapToRecord(computed.broaderClosure),
|
|
1439
|
+
narrowerClosure: mapToRecord(computed.narrowerClosure),
|
|
1440
|
+
equivalenceSets: mapToRecord(computed.equivalenceSets),
|
|
1441
|
+
disjointPairs: [...computed.disjointPairs],
|
|
1442
|
+
partOfClosure: mapToRecord(computed.partOfClosure),
|
|
1443
|
+
hasPartClosure: mapToRecord(computed.hasPartClosure),
|
|
1444
|
+
iriToKind: mapToSimpleRecord(computed.iriToKind),
|
|
1445
|
+
edgeInverses: mapToSimpleRecord(computed.edgeInverses),
|
|
1446
|
+
edgeImplicationsClosure: mapToRecord(computed.edgeImplicationsClosure),
|
|
1447
|
+
edgeImplyingClosure: mapToRecord(computed.edgeImplyingClosure)
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function mapToRecord(map) {
|
|
1451
|
+
const result = {};
|
|
1452
|
+
for (const [key, values] of map) {
|
|
1453
|
+
result[key] = [...values];
|
|
1454
|
+
}
|
|
1455
|
+
return result;
|
|
1456
|
+
}
|
|
1457
|
+
function mapToSimpleRecord(map) {
|
|
1458
|
+
const result = {};
|
|
1459
|
+
for (const [key, value] of map) {
|
|
1460
|
+
result[key] = value;
|
|
1461
|
+
}
|
|
1462
|
+
return result;
|
|
1463
|
+
}
|
|
1464
|
+
var SCHEMA_PROPERTIES_CACHE = /* @__PURE__ */ new WeakMap();
|
|
1465
|
+
function serializeSchemaProperties(schema) {
|
|
1466
|
+
const cached = SCHEMA_PROPERTIES_CACHE.get(schema);
|
|
1467
|
+
if (cached !== void 0) return cached;
|
|
1468
|
+
const computed = serializeZodSchema(schema);
|
|
1469
|
+
SCHEMA_PROPERTIES_CACHE.set(schema, computed);
|
|
1470
|
+
return computed;
|
|
1471
|
+
}
|
|
1472
|
+
function serializeZodSchema(schema) {
|
|
1473
|
+
try {
|
|
1474
|
+
const jsonSchema = zod.z.toJSONSchema(schema);
|
|
1475
|
+
return jsonSchema;
|
|
1476
|
+
} catch {
|
|
1477
|
+
return { type: "object" };
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
var SCHEMA_HASH_CACHE = /* @__PURE__ */ new WeakMap();
|
|
1481
|
+
async function getSchemaHash(graph, version) {
|
|
1482
|
+
const perGraph = SCHEMA_HASH_CACHE.get(graph);
|
|
1483
|
+
const cached = perGraph?.get(version);
|
|
1484
|
+
if (cached !== void 0) return cached;
|
|
1485
|
+
const hash = await computeSchemaHash(serializeSchema(graph, version));
|
|
1486
|
+
if (perGraph === void 0) {
|
|
1487
|
+
SCHEMA_HASH_CACHE.set(graph, /* @__PURE__ */ new Map([[version, hash]]));
|
|
1488
|
+
} else {
|
|
1489
|
+
perGraph.set(version, hash);
|
|
1490
|
+
}
|
|
1491
|
+
return hash;
|
|
1492
|
+
}
|
|
1493
|
+
async function computeSchemaHash(schema) {
|
|
1494
|
+
const hashable = {
|
|
1495
|
+
graphId: schema.graphId,
|
|
1496
|
+
nodes: schema.nodes,
|
|
1497
|
+
edges: schema.edges,
|
|
1498
|
+
ontology: schema.ontology,
|
|
1499
|
+
defaults: schema.defaults,
|
|
1500
|
+
...schema.indexes === void 0 ? {} : { indexes: schema.indexes },
|
|
1501
|
+
...schema.extension === void 0 ? {} : { extension: schema.extension },
|
|
1502
|
+
...schema.deprecatedKinds === void 0 ? {} : { deprecatedKinds: schema.deprecatedKinds }
|
|
1503
|
+
};
|
|
1504
|
+
const json = JSON.stringify(hashable, sortedReplacer);
|
|
1505
|
+
return chunkCTHNVU6K_cjs.sha256Hex(json);
|
|
1506
|
+
}
|
|
1507
|
+
var COMPILE_NODE_CACHE = /* @__PURE__ */ new Map();
|
|
1508
|
+
var COMPILE_EDGE_SCHEMA_CACHE = /* @__PURE__ */ new WeakMap();
|
|
1509
|
+
function compileGraphExtension(document) {
|
|
1510
|
+
const nodes = [];
|
|
1511
|
+
const nodeTypeByName = /* @__PURE__ */ new Map();
|
|
1512
|
+
for (const [kindName, nodeDocument] of Object.entries(document.nodes ?? {})) {
|
|
1513
|
+
const compiled = compileNodeCached(kindName, nodeDocument);
|
|
1514
|
+
nodes.push(compiled);
|
|
1515
|
+
nodeTypeByName.set(kindName, compiled.type);
|
|
1516
|
+
}
|
|
1517
|
+
const edges = [];
|
|
1518
|
+
for (const [kindName, edgeDocument] of Object.entries(document.edges ?? {})) {
|
|
1519
|
+
const compiled = compileEdge(kindName, edgeDocument, nodeTypeByName);
|
|
1520
|
+
edges.push(compiled);
|
|
1521
|
+
}
|
|
1522
|
+
const ontology = [];
|
|
1523
|
+
for (const relation of document.ontology ?? []) {
|
|
1524
|
+
ontology.push(compileOntologyRelation(relation, nodeTypeByName));
|
|
1525
|
+
}
|
|
1526
|
+
return Object.freeze({
|
|
1527
|
+
nodes: Object.freeze(nodes),
|
|
1528
|
+
edges: Object.freeze(edges),
|
|
1529
|
+
ontology: Object.freeze(ontology),
|
|
1530
|
+
// Indexes pass through — the merge step resolves the kind name
|
|
1531
|
+
// against graph-extension-or-compile-time NodeType / EdgeType and builds
|
|
1532
|
+
// the final `IndexDeclaration` via `defineNodeIndex` /
|
|
1533
|
+
// `defineEdgeIndex`.
|
|
1534
|
+
indexes: Object.freeze([...document.indexes ?? []])
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
function compileNodeCached(kindName, document) {
|
|
1538
|
+
const perName = COMPILE_NODE_CACHE.get(kindName);
|
|
1539
|
+
const cached = perName?.get(document);
|
|
1540
|
+
if (cached !== void 0) return cached;
|
|
1541
|
+
const computed = compileNode(kindName, document);
|
|
1542
|
+
if (perName === void 0) {
|
|
1543
|
+
COMPILE_NODE_CACHE.set(kindName, new WeakMap([[document, computed]]));
|
|
1544
|
+
} else {
|
|
1545
|
+
perName.set(document, computed);
|
|
1546
|
+
}
|
|
1547
|
+
return computed;
|
|
1548
|
+
}
|
|
1549
|
+
function compileNode(kindName, document) {
|
|
1550
|
+
const schema = buildObjectSchema(document.properties);
|
|
1551
|
+
const type = defineNode(
|
|
1552
|
+
kindName,
|
|
1553
|
+
chunkRCAJZG67_cjs.compactUndefined({
|
|
1554
|
+
schema,
|
|
1555
|
+
description: document.description,
|
|
1556
|
+
annotations: document.annotations
|
|
1557
|
+
})
|
|
1558
|
+
);
|
|
1559
|
+
const unique = (document.unique ?? []).map(
|
|
1560
|
+
(constraint) => compileUniqueConstraint(constraint)
|
|
1561
|
+
);
|
|
1562
|
+
return Object.freeze({ type, unique: Object.freeze(unique) });
|
|
1563
|
+
}
|
|
1564
|
+
function compileEdge(kindName, document, nodeTypeByName) {
|
|
1565
|
+
let schema = COMPILE_EDGE_SCHEMA_CACHE.get(document);
|
|
1566
|
+
if (schema === void 0) {
|
|
1567
|
+
schema = buildObjectSchema(document.properties ?? {});
|
|
1568
|
+
COMPILE_EDGE_SCHEMA_CACHE.set(document, schema);
|
|
1569
|
+
}
|
|
1570
|
+
const from = document.from.map(
|
|
1571
|
+
(name) => nodeTypeByName.get(name) ?? name
|
|
1572
|
+
);
|
|
1573
|
+
const to = document.to.map(
|
|
1574
|
+
(name) => nodeTypeByName.get(name) ?? name
|
|
1575
|
+
);
|
|
1576
|
+
return Object.freeze(
|
|
1577
|
+
chunkRCAJZG67_cjs.compactUndefined({
|
|
1578
|
+
kindName,
|
|
1579
|
+
schema,
|
|
1580
|
+
description: document.description,
|
|
1581
|
+
annotations: document.annotations,
|
|
1582
|
+
from: Object.freeze(from),
|
|
1583
|
+
to: Object.freeze(to)
|
|
1584
|
+
})
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
function buildObjectSchema(properties) {
|
|
1588
|
+
const shape = {};
|
|
1589
|
+
for (const [propertyName, propertyType] of Object.entries(properties)) {
|
|
1590
|
+
shape[propertyName] = applyOptional(
|
|
1591
|
+
compileProperty(propertyType),
|
|
1592
|
+
propertyType
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
return zod.z.object(shape);
|
|
1596
|
+
}
|
|
1597
|
+
function compileProperty(property) {
|
|
1598
|
+
switch (property.type) {
|
|
1599
|
+
case "string": {
|
|
1600
|
+
return compileStringProperty(property);
|
|
1601
|
+
}
|
|
1602
|
+
case "number": {
|
|
1603
|
+
return compileNumberProperty(property);
|
|
1604
|
+
}
|
|
1605
|
+
case "boolean": {
|
|
1606
|
+
return zod.z.boolean();
|
|
1607
|
+
}
|
|
1608
|
+
case "enum": {
|
|
1609
|
+
return compileEnumProperty(property);
|
|
1610
|
+
}
|
|
1611
|
+
case "array": {
|
|
1612
|
+
return compileArrayProperty(property);
|
|
1613
|
+
}
|
|
1614
|
+
case "object": {
|
|
1615
|
+
return compileObjectProperty(property);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
function compileStringProperty(property) {
|
|
1620
|
+
if (property.searchable !== void 0) {
|
|
1621
|
+
return applyStringRefinements(chunkEK6RJ373_cjs.searchable(property.searchable), property);
|
|
1622
|
+
}
|
|
1623
|
+
if (property.format === void 0) {
|
|
1624
|
+
return applyStringRefinements(zod.z.string(), property);
|
|
1625
|
+
}
|
|
1626
|
+
switch (property.format) {
|
|
1627
|
+
case "datetime": {
|
|
1628
|
+
return zod.z.iso.datetime();
|
|
1629
|
+
}
|
|
1630
|
+
case "date": {
|
|
1631
|
+
return zod.z.iso.date();
|
|
1632
|
+
}
|
|
1633
|
+
case "uri": {
|
|
1634
|
+
return zod.z.url();
|
|
1635
|
+
}
|
|
1636
|
+
case "email": {
|
|
1637
|
+
return zod.z.email();
|
|
1638
|
+
}
|
|
1639
|
+
case "uuid": {
|
|
1640
|
+
return zod.z.uuid();
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
function applyStringRefinements(base, property) {
|
|
1645
|
+
let schema = base;
|
|
1646
|
+
if (property.minLength !== void 0) schema = schema.min(property.minLength);
|
|
1647
|
+
if (property.maxLength !== void 0) schema = schema.max(property.maxLength);
|
|
1648
|
+
if (property.pattern !== void 0) {
|
|
1649
|
+
schema = schema.regex(new RegExp(property.pattern));
|
|
1650
|
+
}
|
|
1651
|
+
return schema;
|
|
1652
|
+
}
|
|
1653
|
+
function compileNumberProperty(property) {
|
|
1654
|
+
let schema = zod.z.number();
|
|
1655
|
+
if (property.int === true) {
|
|
1656
|
+
schema = schema.int();
|
|
1657
|
+
}
|
|
1658
|
+
if (property.min !== void 0) {
|
|
1659
|
+
schema = schema.min(property.min);
|
|
1660
|
+
}
|
|
1661
|
+
if (property.max !== void 0) {
|
|
1662
|
+
schema = schema.max(property.max);
|
|
1663
|
+
}
|
|
1664
|
+
return schema;
|
|
1665
|
+
}
|
|
1666
|
+
function compileEnumProperty(property) {
|
|
1667
|
+
return zod.z.enum(property.values);
|
|
1668
|
+
}
|
|
1669
|
+
function compileArrayProperty(property) {
|
|
1670
|
+
if (property.embedding !== void 0) {
|
|
1671
|
+
return chunkX3244EKP_cjs.embedding(property.embedding.dimensions);
|
|
1672
|
+
}
|
|
1673
|
+
const inner = compilePropertyForArrayItem(property.items);
|
|
1674
|
+
return zod.z.array(inner);
|
|
1675
|
+
}
|
|
1676
|
+
function compilePropertyForArrayItem(item) {
|
|
1677
|
+
return applyOptional(compileProperty(item), item);
|
|
1678
|
+
}
|
|
1679
|
+
function compileObjectProperty(property) {
|
|
1680
|
+
return buildObjectSchema(property.properties);
|
|
1681
|
+
}
|
|
1682
|
+
function applyOptional(schema, property) {
|
|
1683
|
+
return property.optional === true ? schema.optional() : schema;
|
|
1684
|
+
}
|
|
1685
|
+
function compileUniqueConstraint(document) {
|
|
1686
|
+
const base = {
|
|
1687
|
+
name: document.name,
|
|
1688
|
+
fields: document.fields,
|
|
1689
|
+
scope: document.scope ?? "kind",
|
|
1690
|
+
collation: document.collation ?? "binary"
|
|
1691
|
+
};
|
|
1692
|
+
if (document.where === void 0) {
|
|
1693
|
+
return base;
|
|
1694
|
+
}
|
|
1695
|
+
return {
|
|
1696
|
+
...base,
|
|
1697
|
+
where: makeWherePredicate(document.where.field, document.where.op)
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
function makeWherePredicate(field, op) {
|
|
1701
|
+
return (props) => {
|
|
1702
|
+
const builder = props[field];
|
|
1703
|
+
if (builder === void 0) {
|
|
1704
|
+
return { __type: "unique_predicate", field, op };
|
|
1705
|
+
}
|
|
1706
|
+
const result = op === "isNull" ? builder.isNull() : builder.isNotNull();
|
|
1707
|
+
return result;
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
var META_EDGE_BY_NAME = Object.fromEntries(
|
|
1711
|
+
chunkRCAJZG67_cjs.ALL_META_EDGE_NAMES.map((name) => [name, core[`${name}MetaEdge`]])
|
|
1712
|
+
);
|
|
1713
|
+
function compileOntologyRelation(relation, nodeTypeByName) {
|
|
1714
|
+
const metaEdge = META_EDGE_BY_NAME[relation.metaEdge];
|
|
1715
|
+
const fromNode = nodeTypeByName.get(relation.from);
|
|
1716
|
+
const toNode = nodeTypeByName.get(relation.to);
|
|
1717
|
+
return {
|
|
1718
|
+
metaEdge,
|
|
1719
|
+
from: fromNode ?? relation.from,
|
|
1720
|
+
to: toNode ?? relation.to
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// src/graph-extension/ontology-keys.ts
|
|
1725
|
+
function graphExtensionOntologyKey(entry) {
|
|
1726
|
+
return `${entry.metaEdge}|${entry.from}|${entry.to}`;
|
|
1727
|
+
}
|
|
1728
|
+
function compileTimeOntologyKey(relation) {
|
|
1729
|
+
return `${relation.metaEdge.name}|${getTypeName(relation.from)}|${getTypeName(relation.to)}`;
|
|
1730
|
+
}
|
|
1731
|
+
function buildGraphExtensionOntologyKeySet(document) {
|
|
1732
|
+
return new Set(
|
|
1733
|
+
(document?.ontology ?? []).map((entry) => graphExtensionOntologyKey(entry))
|
|
1734
|
+
);
|
|
1735
|
+
}
|
|
1736
|
+
function extensionKindNames(document) {
|
|
1737
|
+
return {
|
|
1738
|
+
nodes: new Set(Object.keys(document?.nodes ?? {})),
|
|
1739
|
+
edges: new Set(Object.keys(document?.edges ?? {}))
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// src/graph-extension/merge.ts
|
|
1744
|
+
function mergeGraphExtension(graph, document) {
|
|
1745
|
+
const existingDocument = graph.extension ?? Object.freeze({});
|
|
1746
|
+
const unionDocument = unionDocuments(existingDocument, document);
|
|
1747
|
+
if (graph.extension !== void 0 && canonicalEqual(unionDocument, existingDocument)) {
|
|
1748
|
+
return graph;
|
|
1749
|
+
}
|
|
1750
|
+
const validatedUnion = chunkRCAJZG67_cjs.unwrap(chunkRCAJZG67_cjs.validateGraphExtension(unionDocument));
|
|
1751
|
+
const compiled = compileGraphExtension(validatedUnion);
|
|
1752
|
+
const { nodes: runtimeNodeNames, edges: runtimeEdgeNames } = extensionKindNames(existingDocument);
|
|
1753
|
+
const nodeKinds = /* @__PURE__ */ new Map();
|
|
1754
|
+
for (const registration of Object.values(graph.nodes)) {
|
|
1755
|
+
if (runtimeNodeNames.has(registration.type.kind)) continue;
|
|
1756
|
+
nodeKinds.set(registration.type.kind, registration.type);
|
|
1757
|
+
}
|
|
1758
|
+
for (const node of compiled.nodes) {
|
|
1759
|
+
assertNoCollision(
|
|
1760
|
+
node.type.kind,
|
|
1761
|
+
"node",
|
|
1762
|
+
nodeKinds.has(node.type.kind),
|
|
1763
|
+
graph.id
|
|
1764
|
+
);
|
|
1765
|
+
nodeKinds.set(node.type.kind, node.type);
|
|
1766
|
+
}
|
|
1767
|
+
const mergedNodes = {};
|
|
1768
|
+
for (const [name, registration] of Object.entries(graph.nodes)) {
|
|
1769
|
+
if (runtimeNodeNames.has(name)) continue;
|
|
1770
|
+
mergedNodes[name] = registration;
|
|
1771
|
+
}
|
|
1772
|
+
for (const node of compiled.nodes) {
|
|
1773
|
+
mergedNodes[node.type.kind] = {
|
|
1774
|
+
type: node.type,
|
|
1775
|
+
...node.unique.length === 0 ? {} : { unique: [...node.unique] }
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
const mergedEdges = {};
|
|
1779
|
+
for (const [name, registration] of Object.entries(graph.edges)) {
|
|
1780
|
+
if (runtimeEdgeNames.has(name)) continue;
|
|
1781
|
+
mergedEdges[name] = registration;
|
|
1782
|
+
}
|
|
1783
|
+
for (const edge of compiled.edges) {
|
|
1784
|
+
assertNoCollision(
|
|
1785
|
+
edge.kindName,
|
|
1786
|
+
"edge",
|
|
1787
|
+
mergedEdges[edge.kindName] !== void 0,
|
|
1788
|
+
graph.id
|
|
1789
|
+
);
|
|
1790
|
+
const from = resolveEndpoints(edge.from, nodeKinds, {
|
|
1791
|
+
graphId: graph.id,
|
|
1792
|
+
edgeKind: edge.kindName,
|
|
1793
|
+
side: "from"
|
|
1794
|
+
});
|
|
1795
|
+
const to = resolveEndpoints(edge.to, nodeKinds, {
|
|
1796
|
+
graphId: graph.id,
|
|
1797
|
+
edgeKind: edge.kindName,
|
|
1798
|
+
side: "to"
|
|
1799
|
+
});
|
|
1800
|
+
const type = defineEdge(
|
|
1801
|
+
edge.kindName,
|
|
1802
|
+
chunkRCAJZG67_cjs.compactUndefined({
|
|
1803
|
+
schema: edge.schema,
|
|
1804
|
+
description: edge.description,
|
|
1805
|
+
annotations: edge.annotations,
|
|
1806
|
+
from,
|
|
1807
|
+
to
|
|
1808
|
+
})
|
|
1809
|
+
);
|
|
1810
|
+
mergedEdges[edge.kindName] = { type, from, to };
|
|
1811
|
+
}
|
|
1812
|
+
const runtimeOntologyKeys = buildGraphExtensionOntologyKeySet(existingDocument);
|
|
1813
|
+
const compileTimeOntology = graph.ontology.filter(
|
|
1814
|
+
(relation) => !runtimeOntologyKeys.has(compileTimeOntologyKey(relation))
|
|
1815
|
+
);
|
|
1816
|
+
const mergedOntology = [
|
|
1817
|
+
...compileTimeOntology,
|
|
1818
|
+
...compiled.ontology.map(
|
|
1819
|
+
(relation) => resolveOntologyEndpoints(relation, nodeKinds)
|
|
1820
|
+
)
|
|
1821
|
+
];
|
|
1822
|
+
const runtimeVectorIndexes = deriveGraphExtensionVectorIndexes(compiled.nodes);
|
|
1823
|
+
const runtimeRelationalIndexes = compileGraphExtensionRelationalIndexes(
|
|
1824
|
+
compiled.indexes,
|
|
1825
|
+
nodeKinds,
|
|
1826
|
+
mergedEdges,
|
|
1827
|
+
graph.id
|
|
1828
|
+
);
|
|
1829
|
+
const mergedIndexes = mergeIndexesWithGraphExtension(
|
|
1830
|
+
graph.indexes,
|
|
1831
|
+
[...runtimeVectorIndexes, ...runtimeRelationalIndexes],
|
|
1832
|
+
graph.id
|
|
1833
|
+
);
|
|
1834
|
+
return Object.freeze({
|
|
1835
|
+
...graph,
|
|
1836
|
+
nodes: mergedNodes,
|
|
1837
|
+
edges: mergedEdges,
|
|
1838
|
+
ontology: mergedOntology,
|
|
1839
|
+
indexes: mergedIndexes,
|
|
1840
|
+
extension: validatedUnion
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
function deriveGraphExtensionVectorIndexes(compiledNodes) {
|
|
1844
|
+
if (compiledNodes.length === 0) return [];
|
|
1845
|
+
const registrations = {};
|
|
1846
|
+
for (const compiled of compiledNodes) {
|
|
1847
|
+
registrations[compiled.type.kind] = {
|
|
1848
|
+
type: compiled.type,
|
|
1849
|
+
...compiled.unique.length === 0 ? {} : { unique: [...compiled.unique] }
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
return chunkE5JZSEGJ_cjs.autoDeriveVectorIndexes(registrations).map(
|
|
1853
|
+
(index) => Object.freeze({ ...index, origin: "runtime" })
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
function mergeIndexesWithGraphExtension(existing, runtimeIndexes, graphId) {
|
|
1857
|
+
if (existing === void 0 && runtimeIndexes.length === 0) {
|
|
1858
|
+
return void 0;
|
|
1859
|
+
}
|
|
1860
|
+
const compileTimeIndexes = (existing ?? []).filter(
|
|
1861
|
+
(index) => index.origin !== "runtime"
|
|
1862
|
+
);
|
|
1863
|
+
if (runtimeIndexes.length === 0) return compileTimeIndexes;
|
|
1864
|
+
const runtimeVectors = runtimeIndexes.filter(
|
|
1865
|
+
(index) => index.entity === "vector"
|
|
1866
|
+
);
|
|
1867
|
+
const runtimeRelational = runtimeIndexes.filter(
|
|
1868
|
+
(index) => index.entity !== "vector"
|
|
1869
|
+
);
|
|
1870
|
+
const vectorMerged = chunkE5JZSEGJ_cjs.mergeVectorIndexes(compileTimeIndexes, runtimeVectors);
|
|
1871
|
+
const merged = [...vectorMerged, ...runtimeRelational];
|
|
1872
|
+
assertUniqueIndexNames(merged, graphId);
|
|
1873
|
+
return merged;
|
|
1874
|
+
}
|
|
1875
|
+
function assertUniqueIndexNames(indexes, graphId) {
|
|
1876
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1877
|
+
for (const index of indexes) {
|
|
1878
|
+
if (!seen.has(index.name)) {
|
|
1879
|
+
seen.add(index.name);
|
|
1880
|
+
continue;
|
|
1881
|
+
}
|
|
1882
|
+
throw new chunkW5MTHMTE_cjs.ConfigurationError(
|
|
1883
|
+
`Duplicate index name "${index.name}" after merging graph extension into graph "${graphId}". Index names must be unique within a graph.`,
|
|
1884
|
+
{ graphId, indexName: index.name, code: "DUPLICATE_INDEX_NAME" },
|
|
1885
|
+
{
|
|
1886
|
+
suggestion: "Give the graph-extension index a unique `name`, or remove the duplicate declaration."
|
|
1887
|
+
}
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
function compileGraphExtensionRelationalIndexes(documents, nodeKinds, mergedEdges, graphId) {
|
|
1892
|
+
if (documents.length === 0) return [];
|
|
1893
|
+
const result = [];
|
|
1894
|
+
for (const document of documents) {
|
|
1895
|
+
if (document.entity === "node") {
|
|
1896
|
+
const node = nodeKinds.get(document.kind);
|
|
1897
|
+
if (node === void 0) {
|
|
1898
|
+
throw new chunkW5MTHMTE_cjs.KindNotFoundError(document.kind, "node", {
|
|
1899
|
+
graphId,
|
|
1900
|
+
suggestion: "Declare the kind under `nodes` in this graph extension, or remove the index from `indexes`."
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
const declaration2 = chunkCTHNVU6K_cjs.defineNodeIndex(
|
|
1904
|
+
node,
|
|
1905
|
+
toNodeIndexConfig(document)
|
|
1906
|
+
);
|
|
1907
|
+
result.push(Object.freeze({ ...declaration2, origin: "runtime" }));
|
|
1908
|
+
continue;
|
|
1909
|
+
}
|
|
1910
|
+
const edgeRegistration = mergedEdges[document.kind];
|
|
1911
|
+
if (edgeRegistration === void 0) {
|
|
1912
|
+
throw new chunkW5MTHMTE_cjs.KindNotFoundError(document.kind, "edge", {
|
|
1913
|
+
graphId,
|
|
1914
|
+
suggestion: "Declare the edge under `edges` in this graph extension, or remove the index from `indexes`."
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
const declaration = chunkCTHNVU6K_cjs.defineEdgeIndex(
|
|
1918
|
+
edgeRegistration.type,
|
|
1919
|
+
toEdgeIndexConfig(document)
|
|
1920
|
+
);
|
|
1921
|
+
result.push(Object.freeze({ ...declaration, origin: "runtime" }));
|
|
1922
|
+
}
|
|
1923
|
+
return result;
|
|
1924
|
+
}
|
|
1925
|
+
function buildWhereCallback(where) {
|
|
1926
|
+
return (props) => {
|
|
1927
|
+
const builder = props[where.field];
|
|
1928
|
+
if (builder === void 0) {
|
|
1929
|
+
throw new chunkW5MTHMTE_cjs.ConfigurationError(
|
|
1930
|
+
`Graph-extension index \`where\` references unknown field "${where.field}".`,
|
|
1931
|
+
{ field: where.field, code: "EXTENSION_INDEX_WHERE_UNKNOWN_FIELD" }
|
|
1932
|
+
);
|
|
1933
|
+
}
|
|
1934
|
+
return where.op === "isNull" ? builder.isNull() : builder.isNotNull();
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
function toNodeIndexConfig(document) {
|
|
1938
|
+
return chunkRCAJZG67_cjs.compactUndefined({
|
|
1939
|
+
fields: document.fields,
|
|
1940
|
+
coveringFields: document.coveringFields,
|
|
1941
|
+
unique: document.unique,
|
|
1942
|
+
name: document.name,
|
|
1943
|
+
scope: document.scope,
|
|
1944
|
+
where: document.where === void 0 ? void 0 : buildWhereCallback(document.where)
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
function toEdgeIndexConfig(document) {
|
|
1948
|
+
return chunkRCAJZG67_cjs.compactUndefined({
|
|
1949
|
+
fields: document.fields,
|
|
1950
|
+
coveringFields: document.coveringFields,
|
|
1951
|
+
unique: document.unique,
|
|
1952
|
+
name: document.name,
|
|
1953
|
+
scope: document.scope,
|
|
1954
|
+
direction: document.direction,
|
|
1955
|
+
where: document.where === void 0 ? void 0 : buildWhereCallback(document.where)
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
function unionDocuments(existing, next) {
|
|
1959
|
+
if (isEmptyExtension(existing)) {
|
|
1960
|
+
return next;
|
|
1961
|
+
}
|
|
1962
|
+
const nodes = existing.nodes === void 0 && next.nodes === void 0 ? void 0 : { ...existing.nodes, ...next.nodes };
|
|
1963
|
+
const edges = existing.edges === void 0 && next.edges === void 0 ? void 0 : { ...existing.edges, ...next.edges };
|
|
1964
|
+
const ontology = existing.ontology === void 0 && next.ontology === void 0 ? void 0 : dedupBy(
|
|
1965
|
+
[...existing.ontology ?? [], ...next.ontology ?? []],
|
|
1966
|
+
graphExtensionOntologyKey
|
|
1967
|
+
);
|
|
1968
|
+
const indexes = existing.indexes === void 0 && next.indexes === void 0 ? void 0 : dedupBy(
|
|
1969
|
+
[...existing.indexes ?? [], ...next.indexes ?? []],
|
|
1970
|
+
indexCompositeKey,
|
|
1971
|
+
"last"
|
|
1972
|
+
);
|
|
1973
|
+
const version = next.version ?? existing.version;
|
|
1974
|
+
return Object.freeze({
|
|
1975
|
+
...version === void 0 ? {} : { version },
|
|
1976
|
+
...nodes === void 0 ? {} : { nodes },
|
|
1977
|
+
...edges === void 0 ? {} : { edges },
|
|
1978
|
+
...ontology === void 0 ? {} : { ontology },
|
|
1979
|
+
...indexes === void 0 ? {} : { indexes }
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1982
|
+
function dedupBy(items, keyFunction, strategy = "first") {
|
|
1983
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1984
|
+
const order = [];
|
|
1985
|
+
for (const item of items) {
|
|
1986
|
+
const key = keyFunction(item);
|
|
1987
|
+
if (!seen.has(key)) {
|
|
1988
|
+
order.push(key);
|
|
1989
|
+
seen.set(key, item);
|
|
1990
|
+
} else if (strategy === "last") {
|
|
1991
|
+
seen.set(key, item);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
return order.map((key) => seen.get(key));
|
|
1995
|
+
}
|
|
1996
|
+
function indexCompositeKey(entry) {
|
|
1997
|
+
return `${entry.entity}|${entry.kind}|${entry.name ?? ""}|${entry.fields.join(",")}`;
|
|
1998
|
+
}
|
|
1999
|
+
function isEmptyExtension(extension) {
|
|
2000
|
+
return extension.nodes === void 0 && extension.edges === void 0 && extension.ontology === void 0 && extension.indexes === void 0;
|
|
2001
|
+
}
|
|
2002
|
+
function assertNoCollision(kindName, entity, collides, graphId) {
|
|
2003
|
+
if (!collides) return;
|
|
2004
|
+
throw new chunkRCAJZG67_cjs.KindCollisionError(kindName, entity, graphId);
|
|
2005
|
+
}
|
|
2006
|
+
function resolveEndpoints(entries, nodeKinds, context) {
|
|
2007
|
+
return entries.map((entry) => {
|
|
2008
|
+
if (typeof entry !== "string") return entry;
|
|
2009
|
+
const resolved = nodeKinds.get(entry);
|
|
2010
|
+
if (resolved === void 0) {
|
|
2011
|
+
throw new chunkRCAJZG67_cjs.GraphExtensionUnresolvedEndpointError(
|
|
2012
|
+
context.edgeKind,
|
|
2013
|
+
context.side,
|
|
2014
|
+
entry,
|
|
2015
|
+
context.graphId
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
return resolved;
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
function resolveOntologyEndpoints(relation, nodeKinds) {
|
|
2022
|
+
const from = typeof relation.from === "string" ? nodeKinds.get(relation.from) ?? relation.from : relation.from;
|
|
2023
|
+
const to = typeof relation.to === "string" ? nodeKinds.get(relation.to) ?? relation.to : relation.to;
|
|
2024
|
+
return { ...relation, from, to };
|
|
2025
|
+
}
|
|
2026
|
+
var deleteBehaviorZod = zod.z.enum(["restrict", "cascade", "disconnect"]);
|
|
2027
|
+
var cardinalityZod = zod.z.enum(["many", "one", "unique", "oneActive"]);
|
|
2028
|
+
var endpointExistenceZod = zod.z.enum(["notDeleted", "currentlyValid", "ever"]);
|
|
2029
|
+
var temporalModeZod = zod.z.enum([
|
|
2030
|
+
"current",
|
|
2031
|
+
"asOf",
|
|
2032
|
+
"includeEnded",
|
|
2033
|
+
"includeTombstones"
|
|
2034
|
+
]);
|
|
2035
|
+
var uniquenessScopeZod = zod.z.enum(["kind", "kindWithSubClasses"]);
|
|
2036
|
+
var collationZod = zod.z.enum(["binary", "caseInsensitive"]);
|
|
2037
|
+
var inferenceTypeZod = zod.z.enum([
|
|
2038
|
+
"subsumption",
|
|
2039
|
+
"hierarchy",
|
|
2040
|
+
"substitution",
|
|
2041
|
+
"constraint",
|
|
2042
|
+
"composition",
|
|
2043
|
+
"association",
|
|
2044
|
+
"none"
|
|
2045
|
+
]);
|
|
2046
|
+
var indexScopeZod = zod.z.enum(["graphAndKind", "graph", "none"]);
|
|
2047
|
+
var indexOriginZod = zod.z.enum(["compile-time", "runtime"]);
|
|
2048
|
+
var edgeIndexDirectionZod = zod.z.enum(["out", "in", "none"]);
|
|
2049
|
+
var valueTypeZod = zod.z.enum([
|
|
2050
|
+
"string",
|
|
2051
|
+
"number",
|
|
2052
|
+
"boolean",
|
|
2053
|
+
"date",
|
|
2054
|
+
"array",
|
|
2055
|
+
"object",
|
|
2056
|
+
"embedding",
|
|
2057
|
+
"unknown"
|
|
2058
|
+
]);
|
|
2059
|
+
var valueTypeOrUndefinedZod = valueTypeZod.optional();
|
|
2060
|
+
var systemColumnNameZod = zod.z.enum([
|
|
2061
|
+
"graph_id",
|
|
2062
|
+
"kind",
|
|
2063
|
+
"id",
|
|
2064
|
+
"from_kind",
|
|
2065
|
+
"from_id",
|
|
2066
|
+
"to_kind",
|
|
2067
|
+
"to_id",
|
|
2068
|
+
"deleted_at",
|
|
2069
|
+
"valid_from",
|
|
2070
|
+
"valid_to",
|
|
2071
|
+
"created_at",
|
|
2072
|
+
"updated_at",
|
|
2073
|
+
"version"
|
|
2074
|
+
]);
|
|
2075
|
+
var indexWhereOperandZod = zod.z.discriminatedUnion("__type", [
|
|
2076
|
+
zod.z.object({
|
|
2077
|
+
__type: zod.z.literal("index_operand_system"),
|
|
2078
|
+
column: systemColumnNameZod,
|
|
2079
|
+
valueType: valueTypeOrUndefinedZod
|
|
2080
|
+
}),
|
|
2081
|
+
zod.z.object({
|
|
2082
|
+
__type: zod.z.literal("index_operand_prop"),
|
|
2083
|
+
field: zod.z.string(),
|
|
2084
|
+
valueType: valueTypeOrUndefinedZod
|
|
2085
|
+
})
|
|
2086
|
+
]);
|
|
2087
|
+
var indexWhereLiteralZod = zod.z.object({
|
|
2088
|
+
__type: zod.z.literal("index_where_literal"),
|
|
2089
|
+
value: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean()]),
|
|
2090
|
+
valueType: valueTypeZod
|
|
2091
|
+
});
|
|
2092
|
+
var indexWhereOpZod = zod.z.enum([
|
|
2093
|
+
"eq",
|
|
2094
|
+
"neq",
|
|
2095
|
+
"gt",
|
|
2096
|
+
"gte",
|
|
2097
|
+
"lt",
|
|
2098
|
+
"lte",
|
|
2099
|
+
"in",
|
|
2100
|
+
"notIn"
|
|
2101
|
+
]);
|
|
2102
|
+
var indexWhereExpressionZod = zod.z.lazy(
|
|
2103
|
+
() => zod.z.discriminatedUnion("__type", [
|
|
2104
|
+
zod.z.object({
|
|
2105
|
+
__type: zod.z.literal("index_where_and"),
|
|
2106
|
+
predicates: zod.z.array(indexWhereExpressionZod)
|
|
2107
|
+
}),
|
|
2108
|
+
zod.z.object({
|
|
2109
|
+
__type: zod.z.literal("index_where_or"),
|
|
2110
|
+
predicates: zod.z.array(indexWhereExpressionZod)
|
|
2111
|
+
}),
|
|
2112
|
+
zod.z.object({
|
|
2113
|
+
__type: zod.z.literal("index_where_not"),
|
|
2114
|
+
predicate: indexWhereExpressionZod
|
|
2115
|
+
}),
|
|
2116
|
+
zod.z.object({
|
|
2117
|
+
__type: zod.z.literal("index_where_comparison"),
|
|
2118
|
+
left: indexWhereOperandZod,
|
|
2119
|
+
op: indexWhereOpZod,
|
|
2120
|
+
right: zod.z.union([indexWhereLiteralZod, zod.z.array(indexWhereLiteralZod)])
|
|
2121
|
+
}),
|
|
2122
|
+
zod.z.object({
|
|
2123
|
+
__type: zod.z.literal("index_where_null_check"),
|
|
2124
|
+
operand: indexWhereOperandZod,
|
|
2125
|
+
op: zod.z.enum(["isNull", "isNotNull"])
|
|
2126
|
+
})
|
|
2127
|
+
])
|
|
2128
|
+
);
|
|
2129
|
+
var jsonPointerZod = zod.z.custom(
|
|
2130
|
+
(value) => typeof value === "string",
|
|
2131
|
+
{ message: "Expected a JSON pointer string" }
|
|
2132
|
+
);
|
|
2133
|
+
var indexDeclarationCommonShape = {
|
|
2134
|
+
name: zod.z.string(),
|
|
2135
|
+
// `origin` is optional. `"compile-time"` is the default and is omitted
|
|
2136
|
+
// from canonical form so legacy graphs without indexes hash
|
|
2137
|
+
// byte-identically. Consumers that need a concrete value should
|
|
2138
|
+
// coalesce `index.origin ?? "compile-time"`.
|
|
2139
|
+
origin: indexOriginZod.optional(),
|
|
2140
|
+
fields: zod.z.array(jsonPointerZod),
|
|
2141
|
+
fieldValueTypes: zod.z.array(valueTypeOrUndefinedZod),
|
|
2142
|
+
coveringFields: zod.z.array(jsonPointerZod),
|
|
2143
|
+
coveringFieldValueTypes: zod.z.array(valueTypeOrUndefinedZod),
|
|
2144
|
+
unique: zod.z.boolean(),
|
|
2145
|
+
scope: indexScopeZod,
|
|
2146
|
+
where: indexWhereExpressionZod.optional()
|
|
2147
|
+
};
|
|
2148
|
+
var nodeIndexDeclarationZod = zod.z.object({
|
|
2149
|
+
entity: zod.z.literal("node"),
|
|
2150
|
+
kind: zod.z.string(),
|
|
2151
|
+
...indexDeclarationCommonShape
|
|
2152
|
+
}).loose();
|
|
2153
|
+
var edgeIndexDeclarationZod = zod.z.object({
|
|
2154
|
+
entity: zod.z.literal("edge"),
|
|
2155
|
+
kind: zod.z.string(),
|
|
2156
|
+
direction: edgeIndexDirectionZod,
|
|
2157
|
+
...indexDeclarationCommonShape
|
|
2158
|
+
}).loose();
|
|
2159
|
+
var vectorIndexMetricZod = zod.z.enum(["cosine", "l2", "inner_product"]);
|
|
2160
|
+
var vectorIndexImplementationZod = zod.z.enum(["hnsw", "ivfflat", "none"]);
|
|
2161
|
+
var vectorIndexParamsZod = zod.z.object({
|
|
2162
|
+
m: zod.z.number(),
|
|
2163
|
+
efConstruction: zod.z.number(),
|
|
2164
|
+
lists: zod.z.number().optional()
|
|
2165
|
+
}).loose();
|
|
2166
|
+
var vectorIndexDeclarationZod = zod.z.object({
|
|
2167
|
+
entity: zod.z.literal("vector"),
|
|
2168
|
+
name: zod.z.string(),
|
|
2169
|
+
origin: indexOriginZod.optional(),
|
|
2170
|
+
kind: zod.z.string(),
|
|
2171
|
+
fieldPath: zod.z.string(),
|
|
2172
|
+
dimensions: zod.z.number(),
|
|
2173
|
+
metric: vectorIndexMetricZod,
|
|
2174
|
+
indexType: vectorIndexImplementationZod,
|
|
2175
|
+
indexParams: vectorIndexParamsZod
|
|
2176
|
+
}).loose();
|
|
2177
|
+
var indexDeclarationZod = zod.z.discriminatedUnion("entity", [
|
|
2178
|
+
nodeIndexDeclarationZod,
|
|
2179
|
+
edgeIndexDeclarationZod,
|
|
2180
|
+
vectorIndexDeclarationZod
|
|
2181
|
+
]);
|
|
2182
|
+
var runtimePropertyZod = zod.z.record(zod.z.string(), zod.z.unknown());
|
|
2183
|
+
var runtimeNodeDocumentZod = zod.z.object({
|
|
2184
|
+
description: zod.z.string().optional(),
|
|
2185
|
+
annotations: zod.z.record(zod.z.string(), zod.z.json()).optional(),
|
|
2186
|
+
properties: zod.z.record(zod.z.string(), runtimePropertyZod),
|
|
2187
|
+
unique: zod.z.array(zod.z.object({}).loose()).optional()
|
|
2188
|
+
}).loose();
|
|
2189
|
+
var runtimeEdgeDocumentZod = zod.z.object({
|
|
2190
|
+
description: zod.z.string().optional(),
|
|
2191
|
+
annotations: zod.z.record(zod.z.string(), zod.z.json()).optional(),
|
|
2192
|
+
from: zod.z.array(zod.z.string()),
|
|
2193
|
+
to: zod.z.array(zod.z.string()),
|
|
2194
|
+
properties: zod.z.record(zod.z.string(), runtimePropertyZod).optional()
|
|
2195
|
+
}).loose();
|
|
2196
|
+
var runtimeOntologyRelationZod = zod.z.object({
|
|
2197
|
+
metaEdge: zod.z.string(),
|
|
2198
|
+
from: zod.z.string(),
|
|
2199
|
+
to: zod.z.string()
|
|
2200
|
+
}).loose();
|
|
2201
|
+
var runtimeIndexDocumentZod = zod.z.object({
|
|
2202
|
+
entity: zod.z.string(),
|
|
2203
|
+
kind: zod.z.string(),
|
|
2204
|
+
name: zod.z.string().optional(),
|
|
2205
|
+
fields: zod.z.array(zod.z.string()).optional(),
|
|
2206
|
+
coveringFields: zod.z.array(zod.z.string()).optional(),
|
|
2207
|
+
unique: zod.z.boolean().optional(),
|
|
2208
|
+
scope: zod.z.string().optional(),
|
|
2209
|
+
direction: zod.z.string().optional(),
|
|
2210
|
+
where: zod.z.object({ field: zod.z.string(), op: zod.z.string() }).loose().optional()
|
|
2211
|
+
}).loose();
|
|
2212
|
+
var graphExtensionZod = zod.z.object({
|
|
2213
|
+
// Version is parsed loosely here so the persistence boundary
|
|
2214
|
+
// never rejects a stored document — the runtime validator owns
|
|
2215
|
+
// the version check and produces actionable errors. Documents
|
|
2216
|
+
// that pre-date the field round-trip as `version: undefined`.
|
|
2217
|
+
version: zod.z.number().optional(),
|
|
2218
|
+
nodes: zod.z.record(zod.z.string(), runtimeNodeDocumentZod).optional(),
|
|
2219
|
+
edges: zod.z.record(zod.z.string(), runtimeEdgeDocumentZod).optional(),
|
|
2220
|
+
ontology: zod.z.array(runtimeOntologyRelationZod).optional(),
|
|
2221
|
+
indexes: zod.z.array(runtimeIndexDocumentZod).optional()
|
|
2222
|
+
}).loose();
|
|
2223
|
+
function checkRecordKeyMatchesField(field, section) {
|
|
2224
|
+
return (record, ctx) => {
|
|
2225
|
+
for (const [key, value] of Object.entries(record)) {
|
|
2226
|
+
const embedded = value[field];
|
|
2227
|
+
if (typeof embedded === "string" && embedded !== key) {
|
|
2228
|
+
ctx.addIssue({
|
|
2229
|
+
code: "custom",
|
|
2230
|
+
path: [key, field],
|
|
2231
|
+
message: `Record key "${key}" does not match ${field} "${embedded}" in ${section}`
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
};
|
|
2236
|
+
}
|
|
2237
|
+
var serializedSchemaZod = zod.z.object({
|
|
2238
|
+
graphId: zod.z.string(),
|
|
2239
|
+
version: zod.z.number(),
|
|
2240
|
+
generatedAt: zod.z.string(),
|
|
2241
|
+
nodes: zod.z.record(
|
|
2242
|
+
zod.z.string(),
|
|
2243
|
+
zod.z.object({
|
|
2244
|
+
kind: zod.z.string(),
|
|
2245
|
+
properties: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
2246
|
+
uniqueConstraints: zod.z.array(
|
|
2247
|
+
zod.z.object({
|
|
2248
|
+
name: zod.z.string(),
|
|
2249
|
+
fields: zod.z.array(zod.z.string()),
|
|
2250
|
+
where: zod.z.string().optional(),
|
|
2251
|
+
scope: uniquenessScopeZod,
|
|
2252
|
+
collation: collationZod
|
|
2253
|
+
}).loose()
|
|
2254
|
+
),
|
|
2255
|
+
onDelete: deleteBehaviorZod,
|
|
2256
|
+
description: zod.z.string().optional(),
|
|
2257
|
+
annotations: zod.z.record(zod.z.string(), zod.z.json()).optional()
|
|
2258
|
+
}).loose()
|
|
2259
|
+
).superRefine(checkRecordKeyMatchesField("kind", "nodes")),
|
|
2260
|
+
edges: zod.z.record(
|
|
2261
|
+
zod.z.string(),
|
|
2262
|
+
zod.z.object({
|
|
2263
|
+
kind: zod.z.string(),
|
|
2264
|
+
fromKinds: zod.z.array(zod.z.string()),
|
|
2265
|
+
toKinds: zod.z.array(zod.z.string()),
|
|
2266
|
+
properties: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
2267
|
+
cardinality: cardinalityZod,
|
|
2268
|
+
endpointExistence: endpointExistenceZod,
|
|
2269
|
+
description: zod.z.string().optional(),
|
|
2270
|
+
annotations: zod.z.record(zod.z.string(), zod.z.json()).optional()
|
|
2271
|
+
}).loose()
|
|
2272
|
+
).superRefine(checkRecordKeyMatchesField("kind", "edges")),
|
|
2273
|
+
ontology: zod.z.object({
|
|
2274
|
+
metaEdges: zod.z.record(
|
|
2275
|
+
zod.z.string(),
|
|
2276
|
+
zod.z.object({
|
|
2277
|
+
name: zod.z.string(),
|
|
2278
|
+
transitive: zod.z.boolean(),
|
|
2279
|
+
symmetric: zod.z.boolean(),
|
|
2280
|
+
reflexive: zod.z.boolean(),
|
|
2281
|
+
inference: inferenceTypeZod,
|
|
2282
|
+
inverse: zod.z.string().optional(),
|
|
2283
|
+
description: zod.z.string().optional()
|
|
2284
|
+
}).loose()
|
|
2285
|
+
).superRefine(checkRecordKeyMatchesField("name", "ontology.metaEdges")),
|
|
2286
|
+
relations: zod.z.array(
|
|
2287
|
+
zod.z.object({
|
|
2288
|
+
metaEdge: zod.z.string(),
|
|
2289
|
+
from: zod.z.string(),
|
|
2290
|
+
to: zod.z.string()
|
|
2291
|
+
}).loose()
|
|
2292
|
+
),
|
|
2293
|
+
closures: zod.z.object({
|
|
2294
|
+
subClassAncestors: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2295
|
+
subClassDescendants: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2296
|
+
broaderClosure: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2297
|
+
narrowerClosure: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2298
|
+
equivalenceSets: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2299
|
+
disjointPairs: zod.z.array(zod.z.string()),
|
|
2300
|
+
partOfClosure: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2301
|
+
hasPartClosure: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2302
|
+
iriToKind: zod.z.record(zod.z.string(), zod.z.string()),
|
|
2303
|
+
edgeInverses: zod.z.record(zod.z.string(), zod.z.string()),
|
|
2304
|
+
edgeImplicationsClosure: zod.z.record(zod.z.string(), zod.z.array(zod.z.string())),
|
|
2305
|
+
edgeImplyingClosure: zod.z.record(zod.z.string(), zod.z.array(zod.z.string()))
|
|
2306
|
+
}).loose()
|
|
2307
|
+
}).loose(),
|
|
2308
|
+
defaults: zod.z.object({
|
|
2309
|
+
onNodeDelete: deleteBehaviorZod,
|
|
2310
|
+
temporalMode: temporalModeZod
|
|
2311
|
+
}).loose(),
|
|
2312
|
+
/**
|
|
2313
|
+
* Index declarations attached to the graph.
|
|
2314
|
+
*
|
|
2315
|
+
* Optional: graphs that never declared the slice omit the field
|
|
2316
|
+
* entirely so their canonical-form hash is byte-identical to graphs
|
|
2317
|
+
* authored before `indexes` existed.
|
|
2318
|
+
*/
|
|
2319
|
+
indexes: zod.z.array(indexDeclarationZod).optional(),
|
|
2320
|
+
/**
|
|
2321
|
+
* Graph extension persisted alongside the compiled `nodes` / `edges`
|
|
2322
|
+
* / `ontology` slices. The loader rebuilds extension-kind Zod
|
|
2323
|
+
* validators from this value (the only durable source); legacy
|
|
2324
|
+
* graphs omit the field and hash byte-identically to before
|
|
2325
|
+
* extensions existed.
|
|
2326
|
+
*
|
|
2327
|
+
* `.loose()` on the inner shape accepts forward-compatible additions
|
|
2328
|
+
* without breaking older readers.
|
|
2329
|
+
*/
|
|
2330
|
+
extension: graphExtensionZod.optional(),
|
|
2331
|
+
/**
|
|
2332
|
+
* Names of node and edge kinds the operator has soft-deprecated via
|
|
2333
|
+
* `store.deprecateKinds(...)`. Surfaces in introspection so consumers
|
|
2334
|
+
* (codegen, UI tooling, lints) can route around them. Does not affect
|
|
2335
|
+
* reads, writes, or queries.
|
|
2336
|
+
*
|
|
2337
|
+
* Omitted when empty so legacy schemas hash byte-identically.
|
|
2338
|
+
*/
|
|
2339
|
+
deprecatedKinds: zod.z.array(zod.z.string()).optional()
|
|
2340
|
+
});
|
|
2341
|
+
|
|
2342
|
+
// src/schema/manager.ts
|
|
2343
|
+
var PARSE_CACHE_LIMIT = 100;
|
|
2344
|
+
var PARSE_CACHE = /* @__PURE__ */ new Map();
|
|
2345
|
+
function parseSerializedSchema(json) {
|
|
2346
|
+
const cached = PARSE_CACHE.get(json);
|
|
2347
|
+
if (cached !== void 0) {
|
|
2348
|
+
PARSE_CACHE.delete(json);
|
|
2349
|
+
PARSE_CACHE.set(json, cached);
|
|
2350
|
+
return cached;
|
|
2351
|
+
}
|
|
2352
|
+
let parsed;
|
|
2353
|
+
try {
|
|
2354
|
+
parsed = JSON.parse(json);
|
|
2355
|
+
} catch {
|
|
2356
|
+
throw new chunkW5MTHMTE_cjs.DatabaseOperationError(
|
|
2357
|
+
"Stored schema document is not valid JSON",
|
|
2358
|
+
{ operation: "select", entity: "schema" }
|
|
2359
|
+
);
|
|
2360
|
+
}
|
|
2361
|
+
const result = serializedSchemaZod.safeParse(parsed);
|
|
2362
|
+
if (!result.success) {
|
|
2363
|
+
const issues = result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
|
|
2364
|
+
throw new chunkW5MTHMTE_cjs.DatabaseOperationError(
|
|
2365
|
+
`Stored schema document is malformed: ${issues}`,
|
|
2366
|
+
{ operation: "select", entity: "schema" }
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
const validated = chunkRCAJZG67_cjs.freezeDeep(result.data);
|
|
2370
|
+
if (PARSE_CACHE.size >= PARSE_CACHE_LIMIT) {
|
|
2371
|
+
const oldest = PARSE_CACHE.keys().next().value;
|
|
2372
|
+
if (oldest !== void 0) PARSE_CACHE.delete(oldest);
|
|
2373
|
+
}
|
|
2374
|
+
PARSE_CACHE.set(json, validated);
|
|
2375
|
+
return validated;
|
|
2376
|
+
}
|
|
2377
|
+
var MISSING_TABLE_PATTERNS = [
|
|
2378
|
+
"no such table",
|
|
2379
|
+
// SQLite
|
|
2380
|
+
"does not exist",
|
|
2381
|
+
// PostgreSQL ("relation ... does not exist")
|
|
2382
|
+
"SQLITE_ERROR"
|
|
2383
|
+
// D1 / Durable Objects error code
|
|
2384
|
+
];
|
|
2385
|
+
function isMissingTableError(error) {
|
|
2386
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2387
|
+
return MISSING_TABLE_PATTERNS.some((pattern) => message.includes(pattern));
|
|
2388
|
+
}
|
|
2389
|
+
async function loadActiveSchemaWithBootstrap(backend, graphId) {
|
|
2390
|
+
try {
|
|
2391
|
+
return await backend.getActiveSchema(graphId);
|
|
2392
|
+
} catch (error) {
|
|
2393
|
+
if (backend.bootstrapTables && isMissingTableError(error)) {
|
|
2394
|
+
await backend.bootstrapTables();
|
|
2395
|
+
return await backend.getActiveSchema(graphId);
|
|
2396
|
+
}
|
|
2397
|
+
throw error;
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
async function loadAndMergeGraphExtensionDocument(backend, graph) {
|
|
2401
|
+
const activeRow = await loadActiveSchemaWithBootstrap(backend, graph.id);
|
|
2402
|
+
if (activeRow === void 0) {
|
|
2403
|
+
return { graph, activeRow: void 0, storedSchema: void 0 };
|
|
2404
|
+
}
|
|
2405
|
+
const storedSchema = parseSerializedSchema(activeRow.schema_doc);
|
|
2406
|
+
const merged = storedSchema.extension === void 0 ? graph : mergeGraphExtension(graph, storedSchema.extension);
|
|
2407
|
+
return {
|
|
2408
|
+
graph: applyDeprecatedKinds(merged, storedSchema.deprecatedKinds),
|
|
2409
|
+
activeRow,
|
|
2410
|
+
storedSchema
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
function applyDeprecatedKinds(graph, names) {
|
|
2414
|
+
const current = graph.deprecatedKinds;
|
|
2415
|
+
if (names === current) return graph;
|
|
2416
|
+
const nextSet = names === void 0 ? /* @__PURE__ */ new Set() : names instanceof Set ? names : new Set(names);
|
|
2417
|
+
if (nextSet.size === 0 && current.size === 0) return graph;
|
|
2418
|
+
if (nextSet.size === current.size && [...nextSet].every((name) => current.has(name))) {
|
|
2419
|
+
return graph;
|
|
2420
|
+
}
|
|
2421
|
+
return Object.freeze({
|
|
2422
|
+
...graph,
|
|
2423
|
+
deprecatedKinds: Object.freeze(new Set(nextSet))
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
async function ensureSchema(backend, graph, options) {
|
|
2427
|
+
const autoMigrate = options?.autoMigrate ?? true;
|
|
2428
|
+
const throwOnBreaking = options?.throwOnBreaking ?? true;
|
|
2429
|
+
const preloaded = options?.preloaded;
|
|
2430
|
+
const activeSchema = preloaded === void 0 ? await loadActiveSchemaWithBootstrap(backend, graph.id) : preloaded.activeRow;
|
|
2431
|
+
if (activeSchema === void 0) {
|
|
2432
|
+
const result = await initializeSchema(backend, graph);
|
|
2433
|
+
return {
|
|
2434
|
+
status: "initialized",
|
|
2435
|
+
version: result.version,
|
|
2436
|
+
committedRow: result
|
|
2437
|
+
};
|
|
2438
|
+
}
|
|
2439
|
+
const storedHash = activeSchema.schema_hash;
|
|
2440
|
+
const currentHash = await getSchemaHash(graph, activeSchema.version + 1);
|
|
2441
|
+
if (storedHash === currentHash) {
|
|
2442
|
+
return { status: "unchanged", version: activeSchema.version };
|
|
2443
|
+
}
|
|
2444
|
+
const storedSchema = preloaded?.storedSchema ?? parseSerializedSchema(activeSchema.schema_doc);
|
|
2445
|
+
const currentSchema = serializeSchema(graph, activeSchema.version + 1);
|
|
2446
|
+
const diff = computeSchemaDiff(storedSchema, currentSchema);
|
|
2447
|
+
if (!diff.hasChanges) {
|
|
2448
|
+
return { status: "unchanged", version: activeSchema.version };
|
|
2449
|
+
}
|
|
2450
|
+
if (isBackwardsCompatible(diff)) {
|
|
2451
|
+
if (autoMigrate) {
|
|
2452
|
+
const hookContext = {
|
|
2453
|
+
graphId: graph.id,
|
|
2454
|
+
fromVersion: activeSchema.version,
|
|
2455
|
+
toVersion: activeSchema.version + 1,
|
|
2456
|
+
diff
|
|
2457
|
+
};
|
|
2458
|
+
await options?.onBeforeMigrate?.(hookContext);
|
|
2459
|
+
const committedRow = await commitNewSchemaVersion(
|
|
2460
|
+
backend,
|
|
2461
|
+
graph,
|
|
2462
|
+
activeSchema.version
|
|
2463
|
+
);
|
|
2464
|
+
await options?.onAfterMigrate?.(hookContext);
|
|
2465
|
+
return {
|
|
2466
|
+
status: "migrated",
|
|
2467
|
+
fromVersion: activeSchema.version,
|
|
2468
|
+
toVersion: committedRow.version,
|
|
2469
|
+
diff,
|
|
2470
|
+
committedRow
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
return {
|
|
2474
|
+
status: "pending",
|
|
2475
|
+
version: activeSchema.version,
|
|
2476
|
+
diff
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
const actions = getMigrationActions(diff);
|
|
2480
|
+
if (throwOnBreaking) {
|
|
2481
|
+
throw new chunkW5MTHMTE_cjs.MigrationError(
|
|
2482
|
+
`Schema migration required: ${diff.summary}. ${actions.length} migration action(s) needed. Use getSchemaChanges() to review, then migrateSchema() to apply.`,
|
|
2483
|
+
{
|
|
2484
|
+
graphId: graph.id,
|
|
2485
|
+
fromVersion: activeSchema.version,
|
|
2486
|
+
toVersion: activeSchema.version + 1
|
|
2487
|
+
}
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
return { status: "breaking", diff, actions };
|
|
2491
|
+
}
|
|
2492
|
+
async function initializeSchema(backend, graph) {
|
|
2493
|
+
const schema = serializeSchema(graph, 1);
|
|
2494
|
+
const hash = await computeSchemaHash(schema);
|
|
2495
|
+
return backend.commitSchemaVersion({
|
|
2496
|
+
graphId: graph.id,
|
|
2497
|
+
expected: { kind: "initial" },
|
|
2498
|
+
version: 1,
|
|
2499
|
+
schemaHash: hash,
|
|
2500
|
+
schemaDoc: schema
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
async function migrateSchema(backend, graph, currentVersion) {
|
|
2504
|
+
const committed = await commitNewSchemaVersion(
|
|
2505
|
+
backend,
|
|
2506
|
+
graph,
|
|
2507
|
+
currentVersion
|
|
2508
|
+
);
|
|
2509
|
+
return committed.version;
|
|
2510
|
+
}
|
|
2511
|
+
async function commitNewSchemaVersion(backend, graph, currentVersion) {
|
|
2512
|
+
const newVersion = currentVersion + 1;
|
|
2513
|
+
const schema = serializeSchema(graph, newVersion);
|
|
2514
|
+
const hash = await computeSchemaHash(schema);
|
|
2515
|
+
return backend.commitSchemaVersion({
|
|
2516
|
+
graphId: graph.id,
|
|
2517
|
+
expected: { kind: "active", version: currentVersion },
|
|
2518
|
+
version: newVersion,
|
|
2519
|
+
schemaHash: hash,
|
|
2520
|
+
schemaDoc: schema
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
async function rollbackSchema(backend, graphId, targetVersion) {
|
|
2524
|
+
const activeRow = await backend.getActiveSchema(graphId);
|
|
2525
|
+
if (activeRow === void 0) {
|
|
2526
|
+
throw new chunkW5MTHMTE_cjs.MigrationError(
|
|
2527
|
+
`Cannot rollback graph "${graphId}": no active schema version exists.`,
|
|
2528
|
+
{ graphId, fromVersion: 0, toVersion: targetVersion }
|
|
2529
|
+
);
|
|
2530
|
+
}
|
|
2531
|
+
await backend.setActiveVersion({
|
|
2532
|
+
graphId,
|
|
2533
|
+
expected: { kind: "active", version: activeRow.version },
|
|
2534
|
+
version: targetVersion
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
async function getActiveSchema(backend, graphId) {
|
|
2538
|
+
const row = await backend.getActiveSchema(graphId);
|
|
2539
|
+
if (row === void 0) return void 0;
|
|
2540
|
+
return parseSerializedSchema(row.schema_doc);
|
|
2541
|
+
}
|
|
2542
|
+
async function isSchemaInitialized(backend, graphId) {
|
|
2543
|
+
const row = await backend.getActiveSchema(graphId);
|
|
2544
|
+
return row !== void 0;
|
|
2545
|
+
}
|
|
2546
|
+
async function getSchemaChanges(backend, graph) {
|
|
2547
|
+
const activeSchema = await backend.getActiveSchema(graph.id);
|
|
2548
|
+
if (activeSchema === void 0) return void 0;
|
|
2549
|
+
const storedSchema = parseSerializedSchema(activeSchema.schema_doc);
|
|
2550
|
+
const currentSchema = serializeSchema(graph, activeSchema.version + 1);
|
|
2551
|
+
return computeSchemaDiff(storedSchema, currentSchema);
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
// src/errors/validation.ts
|
|
2555
|
+
function zodIssuesToValidationIssues(error) {
|
|
2556
|
+
return error.issues.map((issue) => ({
|
|
2557
|
+
path: issue.path.join("."),
|
|
2558
|
+
message: issue.message,
|
|
2559
|
+
code: issue.code
|
|
2560
|
+
}));
|
|
2561
|
+
}
|
|
2562
|
+
function buildLocationString(context) {
|
|
2563
|
+
if (context.id) {
|
|
2564
|
+
return `${context.kind}/${context.id}`;
|
|
2565
|
+
}
|
|
2566
|
+
return `new ${context.kind}`;
|
|
2567
|
+
}
|
|
2568
|
+
function validateProps(schema, props, context) {
|
|
2569
|
+
const result = schema.safeParse(props);
|
|
2570
|
+
if (result.success) {
|
|
2571
|
+
return result.data;
|
|
2572
|
+
}
|
|
2573
|
+
const issues = zodIssuesToValidationIssues(result.error);
|
|
2574
|
+
const location = buildLocationString(context);
|
|
2575
|
+
throw new chunkW5MTHMTE_cjs.ValidationError(
|
|
2576
|
+
`Invalid ${context.entityType} props for ${location}: ${result.error.message}`,
|
|
2577
|
+
{
|
|
2578
|
+
entityType: context.entityType,
|
|
2579
|
+
kind: context.kind,
|
|
2580
|
+
operation: context.operation,
|
|
2581
|
+
...context.id !== void 0 && { id: context.id },
|
|
2582
|
+
issues
|
|
2583
|
+
},
|
|
2584
|
+
{ cause: result.error }
|
|
2585
|
+
);
|
|
2586
|
+
}
|
|
2587
|
+
function validateNodeProps(schema, props, context) {
|
|
2588
|
+
return validateProps(schema, props, {
|
|
2589
|
+
entityType: "node",
|
|
2590
|
+
...context
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
function validateEdgeProps(schema, props, context) {
|
|
2594
|
+
return validateProps(schema, props, {
|
|
2595
|
+
entityType: "edge",
|
|
2596
|
+
...context
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
2599
|
+
function wrapZodError(error, context) {
|
|
2600
|
+
const issues = zodIssuesToValidationIssues(error);
|
|
2601
|
+
const location = buildLocationString(context);
|
|
2602
|
+
return new chunkW5MTHMTE_cjs.ValidationError(
|
|
2603
|
+
`Validation failed for ${context.entityType} ${location}: ${error.message}`,
|
|
2604
|
+
{
|
|
2605
|
+
entityType: context.entityType,
|
|
2606
|
+
kind: context.kind,
|
|
2607
|
+
operation: context.operation,
|
|
2608
|
+
...context.id !== void 0 && { id: context.id },
|
|
2609
|
+
issues
|
|
2610
|
+
},
|
|
2611
|
+
{ cause: error }
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
function createValidationError(message, issues, context) {
|
|
2615
|
+
return new chunkW5MTHMTE_cjs.ValidationError(message, {
|
|
2616
|
+
...context?.entityType !== void 0 && {
|
|
2617
|
+
entityType: context.entityType
|
|
2618
|
+
},
|
|
2619
|
+
...context?.kind !== void 0 && { kind: context.kind },
|
|
2620
|
+
...context?.operation !== void 0 && { operation: context.operation },
|
|
2621
|
+
...context?.id !== void 0 && { id: context.id },
|
|
2622
|
+
issues
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
exports.KindRegistry = KindRegistry;
|
|
2627
|
+
exports.META_EDGE_BRAND = META_EDGE_BRAND;
|
|
2628
|
+
exports.applyDeprecatedKinds = applyDeprecatedKinds;
|
|
2629
|
+
exports.broader = broader;
|
|
2630
|
+
exports.buildGraphExtensionOntologyKeySet = buildGraphExtensionOntologyKeySet;
|
|
2631
|
+
exports.canonicalEqual = canonicalEqual;
|
|
2632
|
+
exports.commitNewSchemaVersion = commitNewSchemaVersion;
|
|
2633
|
+
exports.compileTimeOntologyKey = compileTimeOntologyKey;
|
|
2634
|
+
exports.computeClosuresFromOntology = computeClosuresFromOntology;
|
|
2635
|
+
exports.computeSchemaDiff = computeSchemaDiff;
|
|
2636
|
+
exports.computeSchemaHash = computeSchemaHash;
|
|
2637
|
+
exports.core = core;
|
|
2638
|
+
exports.createEmptyClosures = createEmptyClosures;
|
|
2639
|
+
exports.createValidationError = createValidationError;
|
|
2640
|
+
exports.defineEdge = defineEdge;
|
|
2641
|
+
exports.defineNode = defineNode;
|
|
2642
|
+
exports.deserializeWherePredicate = deserializeWherePredicate;
|
|
2643
|
+
exports.differentFrom = differentFrom;
|
|
2644
|
+
exports.disjointWith = disjointWith;
|
|
2645
|
+
exports.ensureSchema = ensureSchema;
|
|
2646
|
+
exports.equivalentTo = equivalentTo;
|
|
2647
|
+
exports.extensionKindNames = extensionKindNames;
|
|
2648
|
+
exports.getActiveSchema = getActiveSchema;
|
|
2649
|
+
exports.getMigrationActions = getMigrationActions;
|
|
2650
|
+
exports.getSchemaChanges = getSchemaChanges;
|
|
2651
|
+
exports.getTypeName = getTypeName;
|
|
2652
|
+
exports.hasPart = hasPart;
|
|
2653
|
+
exports.implies = implies;
|
|
2654
|
+
exports.initializeSchema = initializeSchema;
|
|
2655
|
+
exports.inverseOf = inverseOf;
|
|
2656
|
+
exports.isBackwardsCompatible = isBackwardsCompatible;
|
|
2657
|
+
exports.isMetaEdge = isMetaEdge;
|
|
2658
|
+
exports.isSchemaInitialized = isSchemaInitialized;
|
|
2659
|
+
exports.loadActiveSchemaWithBootstrap = loadActiveSchemaWithBootstrap;
|
|
2660
|
+
exports.loadAndMergeGraphExtensionDocument = loadAndMergeGraphExtensionDocument;
|
|
2661
|
+
exports.mergeGraphExtension = mergeGraphExtension;
|
|
2662
|
+
exports.migrateSchema = migrateSchema;
|
|
2663
|
+
exports.narrower = narrower;
|
|
2664
|
+
exports.parseSerializedSchema = parseSerializedSchema;
|
|
2665
|
+
exports.partOf = partOf;
|
|
2666
|
+
exports.relatedTo = relatedTo;
|
|
2667
|
+
exports.rollbackSchema = rollbackSchema;
|
|
2668
|
+
exports.sameAs = sameAs;
|
|
2669
|
+
exports.serializeSchema = serializeSchema;
|
|
2670
|
+
exports.serializeSchemaProperties = serializeSchemaProperties;
|
|
2671
|
+
exports.sortedReplacer = sortedReplacer;
|
|
2672
|
+
exports.subClassOf = subClassOf;
|
|
2673
|
+
exports.validateEdgeProps = validateEdgeProps;
|
|
2674
|
+
exports.validateNodeProps = validateNodeProps;
|
|
2675
|
+
exports.validateProps = validateProps;
|
|
2676
|
+
exports.wrapZodError = wrapZodError;
|
|
2677
|
+
//# sourceMappingURL=chunk-7W3KAMVQ.cjs.map
|
|
2678
|
+
//# sourceMappingURL=chunk-7W3KAMVQ.cjs.map
|