@lde/search-api-graphql 0.22.0 → 0.23.1
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/build-schema.d.ts.map +1 -1
- package/dist/build-schema.js +61 -17
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-schema.d.ts","sourceRoot":"","sources":["../src/build-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAWL,aAAa,EAQd,MAAM,SAAS,CAAC;AACjB,OAAO,EAKL,KAAK,YAAY,EAEjB,KAAK,WAAW,EAChB,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAqBrB,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAGvB,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B;;sDAEkD;IAClD,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACjE;AAED;2EAC2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC;yCACqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;uBACmB;IACnB,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,aAAa,KACnB,WAAW,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC;;kEAE8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC;;gDAE4C;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;
|
|
1
|
+
{"version":3,"file":"build-schema.d.ts","sourceRoot":"","sources":["../src/build-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAWL,aAAa,EAQd,MAAM,SAAS,CAAC;AACjB,OAAO,EAKL,KAAK,YAAY,EAEjB,KAAK,WAAW,EAChB,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAqBrB,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAGvB,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B;;sDAEkD;IAClD,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACjE;AAED;2EAC2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC;yCACqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;uBACmB;IACnB,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,aAAa,KACnB,WAAW,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC;;kEAE8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC;;gDAE4C;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AA4GD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,yBAA8B,GACtC,aAAa,CAsxBf;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,yBAA8B,GACtC,MAAM,CAER"}
|
package/dist/build-schema.js
CHANGED
|
@@ -15,21 +15,28 @@ const scalarOutput = (scalar, field) => field.required === true ? new GraphQLNon
|
|
|
15
15
|
* distinguishable. Consequence for consumers: a variable must be declared
|
|
16
16
|
* `[IRI!]`, not `[String!]`, because GraphQL checks variable usage nominally.
|
|
17
17
|
*
|
|
18
|
-
* **
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* **It validates in both directions.** Rejecting a bare token on the way in is
|
|
19
|
+
* what turns `where: { material: { in: ["boerenbont"] } }` from a silent empty
|
|
20
|
+
* result into an error saying why – the same job `argsToQuery` already does for
|
|
21
|
+
* an out-of-range `perPage`. Outbound matters for the same reason: a type
|
|
22
|
+
* enforced in one direction only is not one a consumer can rely on, and the
|
|
23
|
+
* coarse discovery strategy reads `IRI` as the promise that a value is a
|
|
24
|
+
* selection key.
|
|
22
25
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* **Where a bad value is dropped rather than raised.** Raising is right where
|
|
27
|
+
* the value IS the document’s identity (`id`, a reference’s `id`): such a
|
|
28
|
+
* document cannot be selected, so serving it would hand back something
|
|
29
|
+
* unusable. It is wrong for a facet bucket – `value: IRI!` sits inside a chain
|
|
30
|
+
* of non-nulls up to the root field, so raising there nulls the WHOLE response
|
|
31
|
+
* and discards `items`, which is precisely what facet-batch.ts’s degradation
|
|
32
|
+
* contract forbids a supplementary sidebar count from doing. The facet
|
|
33
|
+
* resolvers therefore filter unselectable buckets out instead.
|
|
30
34
|
*
|
|
31
35
|
* What counts as an IRI is {@link isAbsoluteIri} – shared with the projection,
|
|
32
|
-
*
|
|
36
|
+
* which applies it on every route a reference value can take (graph path,
|
|
37
|
+
* `derive`, `from`, `transform`), so the surface cannot promise something the
|
|
38
|
+
* index contradicts and the outbound error is reachable only from an index
|
|
39
|
+
* written before that rule existed.
|
|
33
40
|
*/
|
|
34
41
|
const iriScalar = new GraphQLScalarType({
|
|
35
42
|
name: 'IRI',
|
|
@@ -133,7 +140,7 @@ export function buildGraphQLSchema(schema, options = {}) {
|
|
|
133
140
|
// that selects it, with no `String`-to-`IRI` boundary in between – the
|
|
134
141
|
// contract BooleanBucket already keeps for `is`.
|
|
135
142
|
const iriBucket = new GraphQLObjectType({
|
|
136
|
-
name: '
|
|
143
|
+
name: 'IRIBucket',
|
|
137
144
|
fields: valueBucketFields(iriScalar),
|
|
138
145
|
});
|
|
139
146
|
// A numeric range-facet bin: half-open `[min, max)` bounds (max null on an
|
|
@@ -254,7 +261,28 @@ export function buildGraphQLSchema(schema, options = {}) {
|
|
|
254
261
|
// collide: searchSchema resolves its typeName to a declared Reference Type
|
|
255
262
|
// and rejects duplicate names schema-wide.
|
|
256
263
|
const referenceTypes = new Map();
|
|
257
|
-
|
|
264
|
+
// Seeded with the shared types every schema carries, not just the root type
|
|
265
|
+
// names: a declaration is free to name a type `IRI` or `ValueBucket`, and
|
|
266
|
+
// without this it would pass both collision checks and fail at
|
|
267
|
+
// `new GraphQLSchema` with graphql-js’s “Schema must contain uniquely named
|
|
268
|
+
// types” – naming neither the declaration nor the field, which is the opaque
|
|
269
|
+
// failure these checks exist to replace.
|
|
270
|
+
const takenTypeNames = new Set([
|
|
271
|
+
...rootTypeNames,
|
|
272
|
+
iriScalar.name,
|
|
273
|
+
keywordFilter.name,
|
|
274
|
+
iriFilter.name,
|
|
275
|
+
languageString.name,
|
|
276
|
+
valueBucket.name,
|
|
277
|
+
iriBucket.name,
|
|
278
|
+
rangeBucket.name,
|
|
279
|
+
booleanBucket.name,
|
|
280
|
+
paginationType.name,
|
|
281
|
+
sortDirection.name,
|
|
282
|
+
intRange.name,
|
|
283
|
+
floatRange.name,
|
|
284
|
+
dateRange.name,
|
|
285
|
+
]);
|
|
258
286
|
/** The label key each id-plus-label reference type was registered with; no
|
|
259
287
|
* entry for a surfaced inline one, which carries fields instead of a label. */
|
|
260
288
|
const labelKeys = new Map();
|
|
@@ -611,7 +639,7 @@ export function buildGraphQLSchema(schema, options = {}) {
|
|
|
611
639
|
});
|
|
612
640
|
// Keyed facets object: one field per facetable field, typed by its kind
|
|
613
641
|
// (range fields → [RangeBucket!], boolean fields → [BooleanBucket!],
|
|
614
|
-
// reference fields → [
|
|
642
|
+
// reference fields → [IRIBucket!], else [ValueBucket!]). Only the selected
|
|
615
643
|
// fields are resolved (GraphQL prunes the rest), so the selection IS the
|
|
616
644
|
// request; how they are computed – skip-own-filter, batched into one
|
|
617
645
|
// engine dispatch – lives in facet-batch.ts.
|
|
@@ -705,12 +733,28 @@ export function buildGraphQLSchema(schema, options = {}) {
|
|
|
705
733
|
fields: () => {
|
|
706
734
|
const fields = {};
|
|
707
735
|
for (const field of facetable) {
|
|
736
|
+
const bucketType = bucketTypeFor(field);
|
|
708
737
|
fields[field.name] = {
|
|
709
|
-
type: nonNullListOf(
|
|
738
|
+
type: nonNullListOf(bucketType),
|
|
710
739
|
// The skip-own-filter query building, the batching into one
|
|
711
740
|
// engine dispatch and the degrade-to-[] error handling all live
|
|
712
741
|
// in the loader (facet-batch.ts).
|
|
713
|
-
resolve: (source) =>
|
|
742
|
+
resolve: async (source) => {
|
|
743
|
+
const buckets = await source.loadFacet(field.name);
|
|
744
|
+
if (bucketType !== iriBucket) {
|
|
745
|
+
return buckets;
|
|
746
|
+
}
|
|
747
|
+
// A bucket keyed on something that is not an IRI is not a
|
|
748
|
+
// selection key – it cannot be sent back as the filter that
|
|
749
|
+
// selects it – so it is dropped rather than served under `IRI`.
|
|
750
|
+
// Dropping, not throwing: `value: IRI!` sits inside a chain of
|
|
751
|
+
// non-nulls up to the root field, so a raising coercion here
|
|
752
|
+
// would null the WHOLE response and take `items` with it, which
|
|
753
|
+
// is exactly what facet-batch.ts’s degradation contract forbids
|
|
754
|
+
// a supplementary sidebar count from doing.
|
|
755
|
+
return buckets.filter((bucket) => typeof bucket.value === 'string' &&
|
|
756
|
+
isAbsoluteIri(bucket.value));
|
|
757
|
+
},
|
|
714
758
|
};
|
|
715
759
|
}
|
|
716
760
|
return fields;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search-api-graphql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"description": "Engine- and domain-agnostic GraphQL surface for @lde/search: builds an executable GraphQLSchema from a whole SearchSchema at runtime (no codegen) – one root query field per SearchType – served by generic resolvers over any SearchEngine – and serves it as a framework-agnostic fetch handler with a self-contained playground, SDL endpoint, CORS and depth/cost limits. You supply the schema and per-type typeNames; it names neither your domain nor your engine.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "git+https://github.com/ldelements/lde.git",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@escape.tech/graphql-armor-cost-limit": "^2.4.3",
|
|
38
38
|
"@escape.tech/graphql-armor-max-depth": "^2.4.2",
|
|
39
39
|
"@graphql-yoga/render-graphiql": "^5.21.2",
|
|
40
|
-
"@lde/search": "^0.
|
|
40
|
+
"@lde/search": "^0.21.1",
|
|
41
41
|
"commander": "^15.0.0",
|
|
42
42
|
"dataloader": "^2.2.3",
|
|
43
43
|
"graphql": "^16.9.0",
|