@loradb/lora-graphql 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +324 -77
- package/dist/analyze/access.d.ts +32 -0
- package/dist/analyze/lint.d.ts +9 -0
- package/dist/cli.js +310 -286
- package/dist/cli.js.map +1 -1
- package/dist/compile/auth.d.ts +64 -2
- package/dist/compile/cache.d.ts +37 -0
- package/dist/compile/context.d.ts +12 -0
- package/dist/compile/cypher.d.ts +5 -0
- package/dist/compile/read.d.ts +6 -0
- package/dist/{diff-fpWH5KUa.js → diff-DUOLUgrI.js} +2 -2
- package/dist/{diff-fpWH5KUa.js.map → diff-DUOLUgrI.js.map} +1 -1
- package/dist/driver-C7a5NkfH.js +11521 -0
- package/dist/driver-C7a5NkfH.js.map +1 -0
- package/dist/driver.d.ts +17 -8
- package/dist/errors.d.ts +1 -1
- package/dist/execute/feed.d.ts +1 -1
- package/dist/guards.d.ts +13 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/lora-graphql.d.ts +37 -5
- package/dist/model/desugar.d.ts +34 -0
- package/dist/model/directives.d.ts +1 -1
- package/dist/model/positions.d.ts +22 -0
- package/dist/model/types.d.ts +38 -1
- package/dist/testing.d.ts +27 -0
- package/dist/testing.js +145 -28
- package/dist/testing.js.map +1 -1
- package/package.json +4 -3
- package/dist/driver-CQj9gkvl.js +0 -9580
- package/dist/driver-CQj9gkvl.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { stat as
|
|
3
|
-
import { join as
|
|
4
|
-
import { parse as q, Kind as p, visit as
|
|
5
|
-
import { d as me } from "./diff-
|
|
6
|
-
import { m as
|
|
7
|
-
const be = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]),
|
|
2
|
+
import { stat as H, readdir as oe, readFile as ie, mkdir as re, writeFile as _ } from "node:fs/promises";
|
|
3
|
+
import { join as D, relative as ce } from "node:path";
|
|
4
|
+
import { parse as q, Kind as p, visit as Q, print as V, typeFromAST as ue, isNonNullType as W, isListType as le, getNamedType as fe, isEnumType as de, isInputObjectType as pe } from "graphql";
|
|
5
|
+
import { d as me } from "./diff-DUOLUgrI.js";
|
|
6
|
+
import { m as Y, d as he, M as ge, L as M, l as Z, f as C, o as K, b as ve, i as we, r as Ee, u as Te } from "./driver-C7a5NkfH.js";
|
|
7
|
+
const be = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]), B = {
|
|
8
8
|
coalesce: "@coalesce is not supported: it hides predicates from indexes; store a value instead",
|
|
9
9
|
subscriptionsAuthorization: "@subscriptionsAuthorization is not supported: SUBSCRIBE rules go in @authorization",
|
|
10
10
|
shareable: "federation (@shareable) is not supported",
|
|
@@ -38,177 +38,177 @@ const be = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]), W = {
|
|
|
38
38
|
includes: "INCLUDES",
|
|
39
39
|
caseInsensitive: "CASE_INSENSITIVE"
|
|
40
40
|
};
|
|
41
|
-
function
|
|
42
|
-
const o = q(
|
|
43
|
-
(i) => i.kind === p.OBJECT_TYPE_DEFINITION && !be.has(i.name.value) && !
|
|
44
|
-
), u = new Set(e.map((i) => i.name.value)),
|
|
41
|
+
function ye(n, s = []) {
|
|
42
|
+
const o = q(n, { noLocation: !0 }), a = [], e = o.definitions.filter(
|
|
43
|
+
(i) => i.kind === p.OBJECT_TYPE_DEFINITION && !be.has(i.name.value) && !k(i.directives, "relationshipProperties") && !k(i.directives, "jwt")
|
|
44
|
+
), u = new Set(e.map((i) => i.name.value)), t = s.length > 0 ? $e(s, e) : void 0, r = Q(o, {
|
|
45
45
|
ObjectTypeDefinition(i) {
|
|
46
46
|
if (!u.has(i.name.value)) return;
|
|
47
|
-
const
|
|
48
|
-
let l =
|
|
47
|
+
const c = i.name.value;
|
|
48
|
+
let l = X(
|
|
49
49
|
i.directives ?? [],
|
|
50
|
-
|
|
50
|
+
c,
|
|
51
51
|
void 0,
|
|
52
|
-
|
|
52
|
+
a
|
|
53
53
|
);
|
|
54
|
-
|
|
55
|
-
const d =
|
|
56
|
-
|
|
54
|
+
k(l, "node") || (l = [...l, y("node")]);
|
|
55
|
+
const d = t?.mutations.get(c);
|
|
56
|
+
k(l, "mutation") || (t ? d && d.size > 0 && (l = [
|
|
57
57
|
...l,
|
|
58
|
-
|
|
58
|
+
y("mutation", {
|
|
59
59
|
operations: R([...d].sort())
|
|
60
60
|
})
|
|
61
|
-
]) : (l = [...l,
|
|
62
|
-
`${
|
|
61
|
+
]) : (l = [...l, y("mutation")], a.push(
|
|
62
|
+
`${c}: @mutation added (@neo4j/graphql generates mutations for every type); remove it or narrow its operations`
|
|
63
63
|
)));
|
|
64
|
-
const m = (i.fields ?? []).filter((v) =>
|
|
65
|
-
m.length === 0 ?
|
|
66
|
-
`${
|
|
67
|
-
) : m.length > 1 &&
|
|
64
|
+
const m = (i.fields ?? []).filter((v) => k(v.directives, "id"));
|
|
65
|
+
m.length === 0 ? a.push(
|
|
66
|
+
`${c}: no @id field; add a required @key field (the sort tie-breaker and mutation address)`
|
|
67
|
+
) : m.length > 1 && a.push(`${c}: several @id fields; keep one as the @key`);
|
|
68
68
|
const h = (i.fields ?? []).map(
|
|
69
|
-
(v) =>
|
|
69
|
+
(v) => Ie(v, c, t, a)
|
|
70
70
|
);
|
|
71
71
|
return { ...i, directives: l, fields: h };
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
|
-
return { typeDefs:
|
|
74
|
+
return { typeDefs: V(r), todos: a };
|
|
75
75
|
}
|
|
76
|
-
function
|
|
77
|
-
let e =
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
function Ie(n, s, o, a) {
|
|
77
|
+
let e = X(
|
|
78
|
+
n.directives ?? [],
|
|
79
|
+
s,
|
|
80
|
+
n.name.value,
|
|
81
|
+
a
|
|
82
82
|
);
|
|
83
|
-
e.find((
|
|
84
|
-
(
|
|
85
|
-
), e.push(
|
|
86
|
-
const
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
), o?.sorts.get(
|
|
83
|
+
e.find((r) => r.name.value === "id") && (e = e.filter(
|
|
84
|
+
(r) => r.name.value !== "id" && r.name.value !== "unique"
|
|
85
|
+
), e.push(y("key", { generate: te(!0) })));
|
|
86
|
+
const t = o?.filters.get(s)?.get(n.name.value);
|
|
87
|
+
return t && t.size > 0 && !k(e, "filterable") && e.push(
|
|
88
|
+
k(e, "relationship") ? y("filterable") : y("filterable", { byValue: R([...t].sort()) })
|
|
89
|
+
), o?.sorts.get(s)?.has(n.name.value) && !k(e, "sortable") && e.push(y("sortable")), { ...n, directives: e };
|
|
90
90
|
}
|
|
91
|
-
function
|
|
92
|
-
const e = o ? `${
|
|
93
|
-
for (const
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
|
|
91
|
+
function X(n, s, o, a) {
|
|
92
|
+
const e = o ? `${s}.${o}` : s, u = [];
|
|
93
|
+
for (const t of n) {
|
|
94
|
+
const r = t.name.value;
|
|
95
|
+
if (r in B) {
|
|
96
|
+
a.push(`${e}: ${B[r]}`);
|
|
97
97
|
continue;
|
|
98
98
|
}
|
|
99
|
-
if (
|
|
100
|
-
|
|
99
|
+
if (r === "key" && !o) {
|
|
100
|
+
a.push(`${e}: federation @key(fields:) is not supported`);
|
|
101
101
|
continue;
|
|
102
102
|
}
|
|
103
|
-
if (
|
|
104
|
-
u.push(
|
|
103
|
+
if (r === "unique") {
|
|
104
|
+
u.push(y("unique"));
|
|
105
105
|
continue;
|
|
106
106
|
}
|
|
107
|
-
if (
|
|
108
|
-
u.push(Oe(
|
|
107
|
+
if (r === "relationship") {
|
|
108
|
+
u.push(Oe(t, e, a));
|
|
109
109
|
continue;
|
|
110
110
|
}
|
|
111
|
-
if (
|
|
112
|
-
u.push(
|
|
111
|
+
if (r === "fulltext") {
|
|
112
|
+
u.push(De(t, "indexes", "indexName", "name"));
|
|
113
113
|
continue;
|
|
114
114
|
}
|
|
115
|
-
if (
|
|
116
|
-
u.push(ke(
|
|
115
|
+
if (r === "subscription") {
|
|
116
|
+
u.push(ke(t, e, a));
|
|
117
117
|
continue;
|
|
118
118
|
}
|
|
119
|
-
(
|
|
120
|
-
`${e}: check the @${
|
|
121
|
-
), u.push(
|
|
119
|
+
(r === "authorization" || r === "authentication") && a.push(
|
|
120
|
+
`${e}: check the @${r} rule's filters: operators are written { field: { eq: ... } } here`
|
|
121
|
+
), u.push(t);
|
|
122
122
|
}
|
|
123
123
|
return u;
|
|
124
124
|
}
|
|
125
|
-
function Oe(
|
|
126
|
-
const
|
|
127
|
-
for (const e of
|
|
125
|
+
function Oe(n, s, o) {
|
|
126
|
+
const a = [];
|
|
127
|
+
for (const e of n.arguments ?? []) {
|
|
128
128
|
const u = e.name.value;
|
|
129
129
|
if (u === "queryDirection" && e.value.kind === p.ENUM) {
|
|
130
|
-
e.value.value.includes("UNDIRECTED") &&
|
|
130
|
+
e.value.value.includes("UNDIRECTED") && a.push(A("queryDirection", ee("UNDIRECTED")));
|
|
131
131
|
continue;
|
|
132
132
|
}
|
|
133
133
|
if (u === "nestedOperations" && e.value.kind === p.LIST) {
|
|
134
|
-
const
|
|
135
|
-
(
|
|
134
|
+
const t = e.value.values.filter(
|
|
135
|
+
(r) => r.kind === p.ENUM && r.value !== "CONNECT_OR_CREATE"
|
|
136
136
|
);
|
|
137
|
-
|
|
137
|
+
t.length < e.value.values.length && o.push(`${s}: connectOrCreate is not supported; use upsert`), a.push(A("nestedOperations", { kind: p.LIST, values: t }));
|
|
138
138
|
continue;
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
a.push(e);
|
|
141
141
|
}
|
|
142
|
-
return { ...
|
|
142
|
+
return { ...n, arguments: a };
|
|
143
143
|
}
|
|
144
|
-
function ke(
|
|
145
|
-
const
|
|
146
|
-
if (!
|
|
144
|
+
function ke(n, s, o) {
|
|
145
|
+
const a = n.arguments?.find((t) => t.name.value === "events")?.value;
|
|
146
|
+
if (!a || a.kind !== p.LIST) return n;
|
|
147
147
|
const e = /* @__PURE__ */ new Set();
|
|
148
148
|
let u = !1;
|
|
149
|
-
for (const
|
|
150
|
-
|
|
149
|
+
for (const t of a.values)
|
|
150
|
+
t.kind === p.ENUM && (t.value.startsWith("CREATED") && !t.value.includes("RELATIONSHIP") ? e.add("CREATE") : t.value.startsWith("UPDATED") ? e.add("UPDATE") : t.value.startsWith("DELETED") && !t.value.includes("RELATIONSHIP") ? e.add("DELETE") : t.value.includes("RELATIONSHIP") && (u = !0));
|
|
151
151
|
return o.push(
|
|
152
|
-
`${
|
|
153
|
-
),
|
|
152
|
+
`${s}: subscriptions see writes made through this library (or the engine change feed), not CDC`
|
|
153
|
+
), y("subscription", {
|
|
154
154
|
operations: R([...e].sort()),
|
|
155
|
-
...u ? { relationships:
|
|
155
|
+
...u ? { relationships: te(!0) } : {}
|
|
156
156
|
});
|
|
157
157
|
}
|
|
158
|
-
function
|
|
158
|
+
function $e(n, s) {
|
|
159
159
|
const o = {
|
|
160
160
|
filters: /* @__PURE__ */ new Map(),
|
|
161
161
|
sorts: /* @__PURE__ */ new Map(),
|
|
162
162
|
mutations: /* @__PURE__ */ new Map()
|
|
163
|
-
},
|
|
164
|
-
for (const
|
|
165
|
-
|
|
166
|
-
const e = new Map(
|
|
167
|
-
const m = o.filters.get(
|
|
168
|
-
h.add(d), m.set(l, h), o.filters.set(
|
|
169
|
-
},
|
|
163
|
+
}, a = /* @__PURE__ */ new Map();
|
|
164
|
+
for (const c of s)
|
|
165
|
+
a.set(Y(c.name.value), c), a.set(Ae(c.name.value), c);
|
|
166
|
+
const e = new Map(s.map((c) => [c.name.value, c])), u = (c, l, d) => {
|
|
167
|
+
const m = o.filters.get(c) ?? /* @__PURE__ */ new Map(), h = m.get(l) ?? /* @__PURE__ */ new Set();
|
|
168
|
+
h.add(d), m.set(l, h), o.filters.set(c, m);
|
|
169
|
+
}, t = (c, l) => {
|
|
170
170
|
if (l.kind === p.OBJECT)
|
|
171
171
|
for (const d of l.fields) {
|
|
172
172
|
const m = d.name.value;
|
|
173
173
|
if (m === "AND" || m === "OR") {
|
|
174
174
|
if (d.value.kind === p.LIST)
|
|
175
|
-
for (const w of d.value.values)
|
|
175
|
+
for (const w of d.value.values) t(c, w);
|
|
176
176
|
continue;
|
|
177
177
|
}
|
|
178
178
|
if (m === "NOT") {
|
|
179
|
-
|
|
179
|
+
t(c, d.value);
|
|
180
180
|
continue;
|
|
181
181
|
}
|
|
182
182
|
const h = /^(.+)_(SOME|ALL|NONE|SINGLE)$/.exec(m);
|
|
183
183
|
if (h) {
|
|
184
|
-
const w =
|
|
185
|
-
w && S && (u(
|
|
184
|
+
const w = c.fields?.find(($) => $.name.value === h[1]), S = w && e.get(G(w));
|
|
185
|
+
w && S && (u(c.name.value, h[1], "EQ"), t(S, d.value));
|
|
186
186
|
continue;
|
|
187
187
|
}
|
|
188
|
-
const v = Ne.find(([w]) => m.endsWith(w)), T = v ? m.slice(0, -v[0].length) : m, g =
|
|
188
|
+
const v = Ne.find(([w]) => m.endsWith(w)), T = v ? m.slice(0, -v[0].length) : m, g = c.fields?.find((w) => w.name.value === T);
|
|
189
189
|
if (!g) continue;
|
|
190
|
-
const N = e.get(
|
|
190
|
+
const N = e.get(G(g));
|
|
191
191
|
if (N) {
|
|
192
|
-
if (u(
|
|
193
|
-
for (const w of d.value.fields)
|
|
194
|
-
|
|
192
|
+
if (u(c.name.value, T, "EQ"), d.value.kind === p.OBJECT) {
|
|
193
|
+
for (const w of d.value.fields) t(N, w.value);
|
|
194
|
+
t(N, d.value);
|
|
195
195
|
}
|
|
196
196
|
continue;
|
|
197
197
|
}
|
|
198
|
-
if (v) u(
|
|
198
|
+
if (v) u(c.name.value, T, v[1]);
|
|
199
199
|
else if (d.value.kind === p.OBJECT)
|
|
200
200
|
for (const w of d.value.fields) {
|
|
201
201
|
const S = Se[w.name.value];
|
|
202
|
-
S && u(
|
|
202
|
+
S && u(c.name.value, T, S);
|
|
203
203
|
}
|
|
204
|
-
else u(
|
|
204
|
+
else u(c.name.value, T, "EQ");
|
|
205
205
|
}
|
|
206
|
-
},
|
|
207
|
-
for (const d of
|
|
206
|
+
}, r = (c, l) => {
|
|
207
|
+
for (const d of c?.selections ?? []) {
|
|
208
208
|
if (d.kind !== p.FIELD) continue;
|
|
209
209
|
const m = d.name.value;
|
|
210
210
|
if (l) {
|
|
211
|
-
const h = /^(create|update|delete|upsert)(.+)$/.exec(m), v = m.replace(/(Connection|Aggregate)$/, ""), T =
|
|
211
|
+
const h = /^(create|update|delete|upsert)(.+)$/.exec(m), v = m.replace(/(Connection|Aggregate)$/, ""), T = a.get(v) ?? (h ? a.get(ne(h[2])) : void 0);
|
|
212
212
|
if (T && h) {
|
|
213
213
|
const g = o.mutations.get(T.name.value) ?? /* @__PURE__ */ new Set(), N = h[1].toUpperCase();
|
|
214
214
|
N === "UPSERT" ? (g.add("CREATE"), g.add("UPDATE")) : g.add(N), o.mutations.set(T.name.value, g);
|
|
@@ -216,63 +216,63 @@ function De(t, n) {
|
|
|
216
216
|
if (T)
|
|
217
217
|
for (const g of d.arguments ?? []) i(T, g);
|
|
218
218
|
}
|
|
219
|
-
|
|
219
|
+
r(d.selectionSet, !1);
|
|
220
220
|
}
|
|
221
|
-
}, i = (
|
|
222
|
-
if (l.name.value === "where" &&
|
|
223
|
-
const d = o.sorts.get(
|
|
221
|
+
}, i = (c, l) => {
|
|
222
|
+
if (l.name.value === "where" && t(c, l.value), l.name.value === "sort" || l.name.value === "options") {
|
|
223
|
+
const d = o.sorts.get(c.name.value) ?? /* @__PURE__ */ new Set(), m = (h) => {
|
|
224
224
|
if (h.kind === p.LIST) h.values.forEach(m);
|
|
225
225
|
else if (h.kind === p.OBJECT)
|
|
226
226
|
for (const v of h.fields)
|
|
227
227
|
v.name.value === "sort" ? m(v.value) : v.value.kind === p.ENUM && d.add(v.name.value);
|
|
228
228
|
};
|
|
229
|
-
m(l.value), o.sorts.set(
|
|
229
|
+
m(l.value), o.sorts.set(c.name.value, d);
|
|
230
230
|
}
|
|
231
231
|
};
|
|
232
|
-
for (const
|
|
233
|
-
for (const l of
|
|
234
|
-
l.kind === p.OPERATION_DEFINITION &&
|
|
232
|
+
for (const c of n)
|
|
233
|
+
for (const l of c.definitions)
|
|
234
|
+
l.kind === p.OPERATION_DEFINITION && r(l.selectionSet, !0);
|
|
235
235
|
return o;
|
|
236
236
|
}
|
|
237
|
-
function
|
|
238
|
-
let
|
|
239
|
-
for (;
|
|
240
|
-
return
|
|
237
|
+
function G(n) {
|
|
238
|
+
let s = n.type;
|
|
239
|
+
for (; s.kind !== p.NAMED_TYPE; ) s = s.type;
|
|
240
|
+
return s.name.value;
|
|
241
241
|
}
|
|
242
|
-
function
|
|
243
|
-
return (
|
|
242
|
+
function k(n, s) {
|
|
243
|
+
return (n ?? []).some((o) => o.name.value === s);
|
|
244
244
|
}
|
|
245
|
-
function
|
|
245
|
+
function y(n, s = {}) {
|
|
246
246
|
return {
|
|
247
247
|
kind: p.DIRECTIVE,
|
|
248
|
-
name: { kind: p.NAME, value:
|
|
249
|
-
arguments: Object.entries(
|
|
248
|
+
name: { kind: p.NAME, value: n },
|
|
249
|
+
arguments: Object.entries(s).map(([o, a]) => A(o, a))
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
|
-
function A(
|
|
253
|
-
return { kind: p.ARGUMENT, name: { kind: p.NAME, value:
|
|
252
|
+
function A(n, s) {
|
|
253
|
+
return { kind: p.ARGUMENT, name: { kind: p.NAME, value: n }, value: s };
|
|
254
254
|
}
|
|
255
|
-
const
|
|
255
|
+
const ee = (n) => ({
|
|
256
256
|
kind: p.ENUM,
|
|
257
|
-
value:
|
|
258
|
-
}),
|
|
257
|
+
value: n
|
|
258
|
+
}), te = (n) => ({
|
|
259
259
|
kind: p.BOOLEAN,
|
|
260
|
-
value:
|
|
261
|
-
}), R = (
|
|
260
|
+
value: n
|
|
261
|
+
}), R = (n) => ({
|
|
262
262
|
kind: p.LIST,
|
|
263
|
-
values:
|
|
263
|
+
values: n.map(ee)
|
|
264
264
|
});
|
|
265
|
-
function
|
|
265
|
+
function De(n, s, o, a) {
|
|
266
266
|
return {
|
|
267
|
-
...
|
|
268
|
-
arguments: (
|
|
269
|
-
(e) => e.name.value ===
|
|
267
|
+
...n,
|
|
268
|
+
arguments: (n.arguments ?? []).map(
|
|
269
|
+
(e) => e.name.value === s && e.value.kind === p.LIST ? A(s, {
|
|
270
270
|
kind: p.LIST,
|
|
271
271
|
values: e.value.values.map(
|
|
272
272
|
(u) => u.kind === p.OBJECT ? {
|
|
273
273
|
...u,
|
|
274
274
|
fields: u.fields.map(
|
|
275
|
-
(
|
|
275
|
+
(t) => t.name.value === o ? { ...t, name: { kind: p.NAME, value: a } } : t
|
|
276
276
|
)
|
|
277
277
|
} : u
|
|
278
278
|
)
|
|
@@ -290,20 +290,22 @@ const Le = {
|
|
|
290
290
|
foot: "feet",
|
|
291
291
|
tooth: "teeth"
|
|
292
292
|
};
|
|
293
|
-
function Ae(
|
|
294
|
-
const
|
|
295
|
-
for (const [
|
|
296
|
-
if (o.endsWith(
|
|
297
|
-
return
|
|
298
|
-
return
|
|
293
|
+
function Ae(n) {
|
|
294
|
+
const s = ne(n), o = s.toLowerCase();
|
|
295
|
+
for (const [a, e] of Object.entries(Le))
|
|
296
|
+
if (o.endsWith(a))
|
|
297
|
+
return s.slice(0, s.length - a.length) + e;
|
|
298
|
+
return Y(n);
|
|
299
299
|
}
|
|
300
|
-
function
|
|
301
|
-
return
|
|
300
|
+
function ne(n) {
|
|
301
|
+
return n.charAt(0).toLowerCase() + n.slice(1);
|
|
302
302
|
}
|
|
303
|
-
const
|
|
303
|
+
const z = `lora-graphql <command>
|
|
304
304
|
|
|
305
305
|
print <schema.graphql> the public SDL clients see
|
|
306
306
|
directives the directive definitions, for editors
|
|
307
|
+
access <schema.graphql> [--json] who may do what: each type and guarded field,
|
|
308
|
+
operation and kind of caller
|
|
307
309
|
requirements <schema.graphql> [--ddl] constraints and indexes the API needs
|
|
308
310
|
check <schema.graphql> [--operations <file|dir>]... [--json]
|
|
309
311
|
[--variables <file>] [--context <file>]
|
|
@@ -322,52 +324,54 @@ const G = `lora-graphql <command>
|
|
|
322
324
|
what has no equivalent
|
|
323
325
|
diff <old.graphql> <new.graphql> [--allow-breaking] [--json]
|
|
324
326
|
database statements and API changes`;
|
|
325
|
-
async function qe(
|
|
326
|
-
const [o, ...
|
|
327
|
-
for (let i = 0; i <
|
|
328
|
-
const
|
|
329
|
-
|
|
327
|
+
async function qe(n, s = Be) {
|
|
328
|
+
const [o, ...a] = n, e = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Map(), t = [], r = [];
|
|
329
|
+
for (let i = 0; i < a.length; i++) {
|
|
330
|
+
const c = a[i];
|
|
331
|
+
c === "--operations" ? r.push(a[++i] ?? "") : je.has(c) ? u.set(c, a[++i] ?? "") : c.startsWith("--") ? e.add(c) : t.push(c);
|
|
330
332
|
}
|
|
331
333
|
try {
|
|
332
334
|
switch (o) {
|
|
333
335
|
case "print":
|
|
334
|
-
return await _e(
|
|
336
|
+
return await _e(O(t, 1), s);
|
|
335
337
|
case "directives":
|
|
336
|
-
return
|
|
338
|
+
return s.out(he.trim()), 0;
|
|
339
|
+
case "access":
|
|
340
|
+
return await Ce(O(t, 1), e.has("--json"), s);
|
|
337
341
|
case "requirements":
|
|
338
|
-
return await
|
|
342
|
+
return await xe(O(t, 1), e.has("--ddl"), s);
|
|
339
343
|
case "check":
|
|
340
|
-
return await Me(
|
|
344
|
+
return await Me(O(t, 1), r, e, u, s);
|
|
341
345
|
case "compile":
|
|
342
|
-
return await
|
|
346
|
+
return await Pe(O(t, 1), r, u, s);
|
|
343
347
|
case "analyze":
|
|
344
|
-
return await
|
|
348
|
+
return await Ue(O(t, 1), u, s);
|
|
345
349
|
case "migrate": {
|
|
346
|
-
const [i,
|
|
350
|
+
const [i, c] = O(t, 2);
|
|
347
351
|
if (i !== "neo4j") throw new L("migrate supports neo4j");
|
|
348
352
|
const l = [];
|
|
349
|
-
for (const m of
|
|
350
|
-
for (const h of await
|
|
351
|
-
const d =
|
|
352
|
-
for (const m of d.todos)
|
|
353
|
-
return d.todos.length > 0 &&
|
|
353
|
+
for (const m of r)
|
|
354
|
+
for (const h of await j(m)) l.push(q(h.source));
|
|
355
|
+
const d = ye(await E(c), l);
|
|
356
|
+
for (const m of d.todos) s.out(`# TODO(migrate): ${m}`);
|
|
357
|
+
return d.todos.length > 0 && s.out(""), s.out(d.typeDefs), 0;
|
|
354
358
|
}
|
|
355
359
|
case "diff": {
|
|
356
|
-
const [i,
|
|
357
|
-
return await
|
|
360
|
+
const [i, c] = O(t, 2);
|
|
361
|
+
return await We(i, c, e, s);
|
|
358
362
|
}
|
|
359
363
|
default:
|
|
360
|
-
return
|
|
364
|
+
return s.err(z), 2;
|
|
361
365
|
}
|
|
362
366
|
} catch (i) {
|
|
363
|
-
return i instanceof L ? (
|
|
367
|
+
return i instanceof L ? (s.err(`${i.message}
|
|
364
368
|
|
|
365
|
-
${
|
|
369
|
+
${z}`), 2) : i instanceof ge ? (s.err(i.message), 1) : (s.err(i instanceof Error ? i.message : String(i)), 1);
|
|
366
370
|
}
|
|
367
371
|
}
|
|
368
372
|
class L extends Error {
|
|
369
373
|
}
|
|
370
|
-
const
|
|
374
|
+
const je = /* @__PURE__ */ new Set([
|
|
371
375
|
"--out",
|
|
372
376
|
"--variables",
|
|
373
377
|
"--context",
|
|
@@ -377,66 +381,85 @@ const Ce = /* @__PURE__ */ new Set([
|
|
|
377
381
|
"--name",
|
|
378
382
|
"--sample"
|
|
379
383
|
]);
|
|
380
|
-
function
|
|
381
|
-
if (
|
|
382
|
-
throw new L(`expected ${
|
|
383
|
-
return
|
|
384
|
+
function O(n, s) {
|
|
385
|
+
if (n.length < s)
|
|
386
|
+
throw new L(`expected ${s} file argument(s)`);
|
|
387
|
+
return n;
|
|
384
388
|
}
|
|
385
|
-
const E = (
|
|
386
|
-
function
|
|
387
|
-
const
|
|
389
|
+
const E = (n) => ie(n, "utf8");
|
|
390
|
+
function P(n) {
|
|
391
|
+
const s = {
|
|
388
392
|
run: () => Promise.reject(new Error("no database"))
|
|
389
393
|
};
|
|
390
|
-
return new M({ typeDefs:
|
|
394
|
+
return new M({ typeDefs: n, driver: s });
|
|
391
395
|
}
|
|
392
|
-
async function
|
|
393
|
-
|
|
396
|
+
async function Ce([n], s, o) {
|
|
397
|
+
const a = P(await E(n)).accessMatrix();
|
|
398
|
+
if (s)
|
|
399
|
+
return o.out(JSON.stringify(a, null, 2)), 0;
|
|
400
|
+
const e = a.map((t) => [
|
|
401
|
+
t.field ? `${t.type}.${t.field}` : t.type,
|
|
402
|
+
t.operation,
|
|
403
|
+
t.principal,
|
|
404
|
+
t.verdict,
|
|
405
|
+
t.by.join(", ")
|
|
406
|
+
]), u = [0, 1, 2, 3].map(
|
|
407
|
+
(t) => Math.max(...e.map((r) => r[t].length), 0)
|
|
408
|
+
);
|
|
409
|
+
for (const t of e)
|
|
410
|
+
o.out(
|
|
411
|
+
t.map((r, i) => i < 4 ? r.padEnd(u[i]) : r).join(" ").trimEnd()
|
|
412
|
+
);
|
|
413
|
+
return 0;
|
|
414
|
+
}
|
|
415
|
+
async function _e([n], s) {
|
|
416
|
+
return s.out(P(await E(n)).printPublicSchema()), 0;
|
|
394
417
|
}
|
|
395
|
-
async function
|
|
396
|
-
const
|
|
397
|
-
for (const e of we(
|
|
418
|
+
async function xe([n], s, o) {
|
|
419
|
+
const a = ve(await E(n));
|
|
420
|
+
for (const e of we(a))
|
|
398
421
|
o.out(
|
|
399
|
-
|
|
422
|
+
s ? `${Ee(e)};` : `${K(e)}, because ${e.reason}`
|
|
400
423
|
);
|
|
401
424
|
return 0;
|
|
402
425
|
}
|
|
403
|
-
async function se(
|
|
426
|
+
async function se(n, s) {
|
|
404
427
|
try {
|
|
405
428
|
const { createDatabase: o } = await import("@loradb/lora-node");
|
|
406
429
|
return o;
|
|
407
430
|
} catch {
|
|
408
|
-
|
|
409
|
-
`${
|
|
431
|
+
n.err(
|
|
432
|
+
`${s} needs @loradb/lora-node: npm install --save-dev @loradb/lora-node`
|
|
410
433
|
);
|
|
411
434
|
return;
|
|
412
435
|
}
|
|
413
436
|
}
|
|
414
|
-
async function Me([
|
|
415
|
-
const u = o.has("--json"),
|
|
416
|
-
if (!
|
|
417
|
-
const i =
|
|
418
|
-
i ?
|
|
437
|
+
async function Me([n], s, o, a, e) {
|
|
438
|
+
const u = o.has("--json"), t = await E(n), r = await se(e, "check");
|
|
439
|
+
if (!r) return 1;
|
|
440
|
+
const i = a.get("--database"), c = await r(
|
|
441
|
+
i ? a.get("--name") ?? "app" : void 0,
|
|
419
442
|
i ? { databaseDir: i } : {}
|
|
420
443
|
), l = new M({
|
|
421
|
-
typeDefs:
|
|
422
|
-
driver:
|
|
444
|
+
typeDefs: t,
|
|
445
|
+
driver: Z(c)
|
|
423
446
|
});
|
|
424
447
|
i || await l.assertSchema({ create: !0 });
|
|
425
|
-
const d = l.getSchema(), m =
|
|
426
|
-
for (const f of
|
|
427
|
-
for (const b of await
|
|
428
|
-
for (const
|
|
429
|
-
const
|
|
448
|
+
const d = l.getSchema(), m = a.has("--variables") ? JSON.parse(await E(a.get("--variables"))) : {}, h = a.has("--context") ? JSON.parse(await E(a.get("--context"))) : {}, v = [];
|
|
449
|
+
for (const f of s)
|
|
450
|
+
for (const b of await j(f))
|
|
451
|
+
for (const I of Fe(d, b.path, b.source)) {
|
|
452
|
+
const U = I.name.split("#")[1] ?? "", F = m[I.name] ?? m[U], J = h[I.name] ?? h[U] ?? h["*"];
|
|
430
453
|
v.push({
|
|
431
|
-
...
|
|
432
|
-
...
|
|
433
|
-
...
|
|
454
|
+
...I,
|
|
455
|
+
...F ? { variables: F } : {},
|
|
456
|
+
...J !== void 0 ? { context: J } : {}
|
|
434
457
|
});
|
|
435
458
|
}
|
|
436
|
-
const T =
|
|
459
|
+
const T = a.has("--row-budget") ? Number(a.get("--row-budget")) : void 0, g = await l.check({
|
|
437
460
|
operations: v,
|
|
438
461
|
...T !== void 0 ? { rowBudget: T } : {}
|
|
439
|
-
}), N =
|
|
462
|
+
}), N = a.get("--baseline"), w = {};
|
|
440
463
|
for (const f of g.plans)
|
|
441
464
|
w[`${f.operation} › ${f.field}`] = f.reports.map((b) => b.operators);
|
|
442
465
|
const S = [];
|
|
@@ -457,27 +480,28 @@ async function Me([t], n, o, s, e) {
|
|
|
457
480
|
]))
|
|
458
481
|
JSON.stringify(f[b]) !== JSON.stringify(w[b]) && S.push(b);
|
|
459
482
|
}
|
|
460
|
-
const
|
|
483
|
+
const $ = g.ok && S.length === 0;
|
|
461
484
|
if (u)
|
|
462
|
-
return e.out(JSON.stringify({ ...g, ok:
|
|
463
|
-
for (const f of g.warnings) e.out(`warning ${
|
|
464
|
-
for (const f of g.lint) e.out(`lint ${
|
|
485
|
+
return e.out(JSON.stringify({ ...g, ok: $, planChanges: S }, null, 2)), $ ? 0 : 1;
|
|
486
|
+
for (const f of g.warnings) e.out(`warning ${C(f)}`);
|
|
487
|
+
for (const f of g.lint) e.out(`lint ${C(f)}`);
|
|
465
488
|
for (const f of g.unused)
|
|
466
489
|
e.out(
|
|
467
490
|
`unused ${f.type} index ${f.name} on :${f.labels.join(":")}(${f.properties.join(", ")})`
|
|
468
491
|
);
|
|
492
|
+
for (const f of g.security) e.out(`error ${C(f)}`);
|
|
469
493
|
for (const f of g.missing)
|
|
470
|
-
e.out(`error missing ${
|
|
494
|
+
e.out(`error missing ${K(f)}`);
|
|
471
495
|
for (const f of g.cypher)
|
|
472
496
|
e.out(`error ${f.type}.${f.field}: ${f.message}`);
|
|
473
497
|
for (const f of g.errors)
|
|
474
498
|
e.out(`error ${f.operation}: ${f.message}`);
|
|
475
499
|
for (const f of g.plans)
|
|
476
500
|
for (const b of f.reports) {
|
|
477
|
-
for (const
|
|
478
|
-
e.out(`error ${f.operation} › ${f.field}: ${
|
|
479
|
-
for (const
|
|
480
|
-
e.out(`lint ${f.operation} › ${f.field}: ${
|
|
501
|
+
for (const I of b.findings)
|
|
502
|
+
e.out(`error ${f.operation} › ${f.field}: ${I.message}`);
|
|
503
|
+
for (const I of b.notes)
|
|
504
|
+
e.out(`lint ${f.operation} › ${f.field}: ${I.message}`);
|
|
481
505
|
}
|
|
482
506
|
for (const f of S)
|
|
483
507
|
e.out(
|
|
@@ -485,108 +509,108 @@ async function Me([t], n, o, s, e) {
|
|
|
485
509
|
);
|
|
486
510
|
const ae = g.plans.length;
|
|
487
511
|
return e.out(
|
|
488
|
-
|
|
489
|
-
),
|
|
512
|
+
$ ? `ok ${ae} root field(s) in ${v.length} operation(s) seek as expected` : "failed"
|
|
513
|
+
), $ ? 0 : 1;
|
|
490
514
|
}
|
|
491
|
-
async function Re(
|
|
492
|
-
const
|
|
493
|
-
for (const o of
|
|
494
|
-
if ((await
|
|
515
|
+
async function Re(n) {
|
|
516
|
+
const s = {};
|
|
517
|
+
for (const o of n) {
|
|
518
|
+
if ((await H(o)).isFile() && o.endsWith(".json")) {
|
|
495
519
|
Object.assign(
|
|
496
|
-
|
|
520
|
+
s,
|
|
497
521
|
JSON.parse(await E(o))
|
|
498
522
|
);
|
|
499
523
|
continue;
|
|
500
524
|
}
|
|
501
|
-
for (const e of await
|
|
502
|
-
const u = q(e.source),
|
|
525
|
+
for (const e of await j(o)) {
|
|
526
|
+
const u = q(e.source), t = new Map(
|
|
503
527
|
u.definitions.filter(
|
|
504
528
|
(i) => i.kind === p.FRAGMENT_DEFINITION
|
|
505
529
|
).map((i) => [i.name.value, i])
|
|
506
|
-
),
|
|
530
|
+
), r = ce(process.cwd(), e.path);
|
|
507
531
|
u.definitions.filter(
|
|
508
532
|
(i) => i.kind === p.OPERATION_DEFINITION
|
|
509
|
-
).forEach((i,
|
|
510
|
-
const l = `${
|
|
511
|
-
|
|
533
|
+
).forEach((i, c) => {
|
|
534
|
+
const l = `${r}#${i.name?.value ?? c + 1}`;
|
|
535
|
+
s[l] = V({
|
|
512
536
|
kind: p.DOCUMENT,
|
|
513
|
-
definitions: [i, ...
|
|
537
|
+
definitions: [i, ...Te(i, t)]
|
|
514
538
|
});
|
|
515
539
|
});
|
|
516
540
|
}
|
|
517
541
|
}
|
|
518
|
-
return
|
|
542
|
+
return s;
|
|
519
543
|
}
|
|
520
|
-
async function
|
|
521
|
-
if (
|
|
544
|
+
async function Pe([n], s, o, a) {
|
|
545
|
+
if (s.length === 0)
|
|
522
546
|
throw new L("compile needs --operations <file|dir>");
|
|
523
|
-
const e =
|
|
524
|
-
await Re(
|
|
525
|
-
),
|
|
526
|
-
return await re(
|
|
527
|
-
|
|
547
|
+
const e = P(await E(n)), u = e.buildManifest(
|
|
548
|
+
await Re(s)
|
|
549
|
+
), t = o.get("--out") ?? "lora-graphql";
|
|
550
|
+
return await re(t, { recursive: !0 }), await _(
|
|
551
|
+
D(t, "manifest.json"),
|
|
528
552
|
JSON.stringify(u) + `
|
|
529
553
|
`
|
|
530
554
|
), await _(
|
|
531
|
-
|
|
555
|
+
D(t, "operations.d.ts"),
|
|
532
556
|
e.generateTypes(u)
|
|
533
|
-
),
|
|
534
|
-
`wrote ${Object.keys(u.operations).length} operation(s) to ${
|
|
557
|
+
), a.out(
|
|
558
|
+
`wrote ${Object.keys(u.operations).length} operation(s) to ${D(t, "manifest.json")} and ${D(t, "operations.d.ts")}`
|
|
535
559
|
), 0;
|
|
536
560
|
}
|
|
537
|
-
async function
|
|
538
|
-
const
|
|
539
|
-
if (!
|
|
561
|
+
async function Ue([n], s, o) {
|
|
562
|
+
const a = s.get("--database");
|
|
563
|
+
if (!a) throw new L("analyze needs --database <dir>");
|
|
540
564
|
const e = await se(o, "analyze");
|
|
541
565
|
if (!e) return 1;
|
|
542
|
-
const u = await e(
|
|
543
|
-
databaseDir:
|
|
544
|
-
}),
|
|
545
|
-
typeDefs: await E(
|
|
546
|
-
driver:
|
|
547
|
-
}),
|
|
566
|
+
const u = await e(s.get("--name") ?? "app", {
|
|
567
|
+
databaseDir: a
|
|
568
|
+
}), t = new M({
|
|
569
|
+
typeDefs: await E(n),
|
|
570
|
+
driver: Z(u)
|
|
571
|
+
}), r = s.has("--sample") ? Number(s.get("--sample")) : void 0, i = await t.analyze(r !== void 0 ? { sample: r } : {});
|
|
548
572
|
return o.out(JSON.stringify(i, null, 2)), u.dispose?.(), 0;
|
|
549
573
|
}
|
|
550
|
-
async function
|
|
551
|
-
if ((await
|
|
574
|
+
async function j(n) {
|
|
575
|
+
if ((await H(n)).isFile()) return [{ path: n, source: await E(n) }];
|
|
552
576
|
const o = [];
|
|
553
|
-
for (const
|
|
554
|
-
const e =
|
|
555
|
-
|
|
577
|
+
for (const a of await oe(n, { withFileTypes: !0 })) {
|
|
578
|
+
const e = D(n, a.name);
|
|
579
|
+
a.isDirectory() ? o.push(...await j(e)) : /\.(graphql|gql)$/.test(a.name) && o.push({ path: e, source: await E(e) });
|
|
556
580
|
}
|
|
557
581
|
return o;
|
|
558
582
|
}
|
|
559
|
-
function
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
(
|
|
563
|
-
).map((
|
|
564
|
-
), u = (
|
|
565
|
-
const
|
|
583
|
+
function Fe(n, s, o) {
|
|
584
|
+
const a = q(o), e = new Map(
|
|
585
|
+
a.definitions.filter(
|
|
586
|
+
(t) => t.kind === p.FRAGMENT_DEFINITION
|
|
587
|
+
).map((t) => [t.name.value, t])
|
|
588
|
+
), u = (t) => {
|
|
589
|
+
const r = /* @__PURE__ */ new Map(), i = (c) => Q(c, {
|
|
566
590
|
FragmentSpread(l) {
|
|
567
591
|
const d = e.get(l.name.value);
|
|
568
|
-
d && !
|
|
592
|
+
d && !r.has(d.name.value) && (r.set(d.name.value, d), i(d));
|
|
569
593
|
}
|
|
570
594
|
});
|
|
571
|
-
return i(
|
|
595
|
+
return i(t), [...r.values()];
|
|
572
596
|
};
|
|
573
|
-
return
|
|
574
|
-
(
|
|
575
|
-
).map((
|
|
597
|
+
return a.definitions.filter(
|
|
598
|
+
(t) => t.kind === p.OPERATION_DEFINITION && t.operation === "query"
|
|
599
|
+
).map((t, r) => {
|
|
576
600
|
const i = {};
|
|
577
|
-
for (const
|
|
578
|
-
if (
|
|
579
|
-
const l = ue(
|
|
580
|
-
l && (i[
|
|
601
|
+
for (const c of t.variableDefinitions ?? []) {
|
|
602
|
+
if (c.defaultValue || c.type.kind !== p.NON_NULL_TYPE) continue;
|
|
603
|
+
const l = ue(n, c.type);
|
|
604
|
+
l && (i[c.variable.name.value] = x(l));
|
|
581
605
|
}
|
|
582
606
|
return {
|
|
583
|
-
name: `${
|
|
584
|
-
document: { kind: p.DOCUMENT, definitions: [
|
|
607
|
+
name: `${s}${t.name ? `#${t.name.value}` : `#${r + 1}`}`,
|
|
608
|
+
document: { kind: p.DOCUMENT, definitions: [t, ...u(t)] },
|
|
585
609
|
variables: i
|
|
586
610
|
};
|
|
587
611
|
});
|
|
588
612
|
}
|
|
589
|
-
const
|
|
613
|
+
const Je = {
|
|
590
614
|
String: "x",
|
|
591
615
|
ID: "x",
|
|
592
616
|
Int: 1,
|
|
@@ -600,40 +624,40 @@ const Fe = {
|
|
|
600
624
|
LocalDateTime: "2026-01-01T12:00:00",
|
|
601
625
|
Duration: "P1D"
|
|
602
626
|
};
|
|
603
|
-
function
|
|
604
|
-
const
|
|
605
|
-
if (le(
|
|
606
|
-
const o = fe(
|
|
627
|
+
function x(n) {
|
|
628
|
+
const s = W(n) ? n.ofType : n;
|
|
629
|
+
if (le(s)) return [x(s.ofType)];
|
|
630
|
+
const o = fe(s);
|
|
607
631
|
if (de(o)) return o.getValues()[0]?.value;
|
|
608
632
|
if (pe(o)) {
|
|
609
|
-
const
|
|
633
|
+
const a = {};
|
|
610
634
|
for (const e of Object.values(o.getFields()))
|
|
611
|
-
|
|
612
|
-
return
|
|
635
|
+
W(e.type) && e.defaultValue === void 0 && (a[e.name] = x(e.type));
|
|
636
|
+
return a;
|
|
613
637
|
}
|
|
614
|
-
return
|
|
638
|
+
return Je[o.name] ?? "x";
|
|
615
639
|
}
|
|
616
|
-
async function
|
|
617
|
-
const e = me(await E(
|
|
640
|
+
async function We(n, s, o, a) {
|
|
641
|
+
const e = me(await E(n), await E(s)), u = e.api.breaking.length > 0, t = u && !o.has("--allow-breaking") ? 1 : 0;
|
|
618
642
|
if (o.has("--json"))
|
|
619
|
-
return
|
|
620
|
-
|
|
621
|
-
for (const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
# API`), !u && e.api.dangerous.length === 0 &&
|
|
625
|
-
for (const
|
|
626
|
-
for (const
|
|
627
|
-
for (const
|
|
628
|
-
return
|
|
643
|
+
return a.out(JSON.stringify(e, null, 2)), t;
|
|
644
|
+
a.out("# Database"), e.database.statements.length === 0 && a.out("no changes");
|
|
645
|
+
for (const r of e.database.statements)
|
|
646
|
+
a.out(`${r.destructive ? "// destructive: " : "// "}${r.reason}`), a.out(`${r.text};`);
|
|
647
|
+
a.out(`
|
|
648
|
+
# API`), !u && e.api.dangerous.length === 0 && a.out("no changes");
|
|
649
|
+
for (const r of e.api.breaking) a.out(`breaking ${r.description}`);
|
|
650
|
+
for (const r of e.api.dangerous) a.out(`dangerous ${r.description}`);
|
|
651
|
+
for (const r of e.notes) a.out(`note ${r}`);
|
|
652
|
+
return t;
|
|
629
653
|
}
|
|
630
|
-
const
|
|
631
|
-
out: (
|
|
654
|
+
const Be = {
|
|
655
|
+
out: (n) => process.stdout.write(n + `
|
|
632
656
|
`),
|
|
633
|
-
err: (
|
|
657
|
+
err: (n) => process.stderr.write(n + `
|
|
634
658
|
`)
|
|
635
|
-
},
|
|
636
|
-
|
|
659
|
+
}, Ge = typeof process < "u" && process.argv[1] !== void 0 && /lora-graphql(\.js)?$|cli\.js$/.test(process.argv[1]);
|
|
660
|
+
Ge && qe(process.argv.slice(2)).then((n) => process.exit(n));
|
|
637
661
|
export {
|
|
638
662
|
qe as main
|
|
639
663
|
};
|