@lde/search 0.21.1 → 0.22.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/adapter.d.ts +1 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/join-graph.d.ts.map +1 -1
- package/dist/join-graph.js +8 -7
- package/dist/project.js +16 -4
- package/dist/query.d.ts +35 -5
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +49 -3
- package/dist/schema.d.ts +62 -57
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +81 -22
- package/package.json +1 -1
package/dist/adapter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* deployment author declaring a schema and running searches needs none of
|
|
7
7
|
* this; the main entry point carries that (small) authoring surface.
|
|
8
8
|
*/
|
|
9
|
-
export { assertTypeInSchema, physicalFields, irAlias, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, isInternalField, isInlineReference, nestedReferenceType, nestedFieldName, referenceFields, referenceTypeNamed, inlineFramingDepth, fieldNamed, datasetField, ID_FIELD, AND_KEY, OR_KEY, labelFieldOf, labelFieldNameOf, DEFAULT_LABEL_FIELD, isRangeFacet, isAbsoluteIri, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
9
|
+
export { assertTypeInSchema, physicalFields, irAlias, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, isInternalField, isInlineReference, nestedReferenceType, nestedFieldName, referenceFields, referenceTypeNamed, inlineFramingDepth, fieldNamed, datasetField, ID_FIELD, AND_KEY, OR_KEY, labelFieldOf, labelFieldNameOf, labelSourceNameOf, DEFAULT_LABEL_FIELD, isRangeFacet, isAbsoluteIri, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export type { PhysicalFields } from './schema.js';
|
|
11
11
|
export { physicalNameTokens } from './physical-name.js';
|
|
12
12
|
export { joinGraph, MAX_JOIN_DEPTH } from './join-graph.js';
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/adapter.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* deployment author declaring a schema and running searches needs none of
|
|
7
7
|
* this; the main entry point carries that (small) authoring surface.
|
|
8
8
|
*/
|
|
9
|
-
export { assertTypeInSchema, physicalFields, irAlias, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, isInternalField, isInlineReference, nestedReferenceType, nestedFieldName, referenceFields, referenceTypeNamed, inlineFramingDepth, fieldNamed, datasetField, ID_FIELD, AND_KEY, OR_KEY, labelFieldOf, labelFieldNameOf, DEFAULT_LABEL_FIELD, isRangeFacet, isAbsoluteIri, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
9
|
+
export { assertTypeInSchema, physicalFields, irAlias, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, isInternalField, isInlineReference, nestedReferenceType, nestedFieldName, referenceFields, referenceTypeNamed, inlineFramingDepth, fieldNamed, datasetField, ID_FIELD, AND_KEY, OR_KEY, labelFieldOf, labelFieldNameOf, labelSourceNameOf, DEFAULT_LABEL_FIELD, isRangeFacet, isAbsoluteIri, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export { physicalNameTokens } from './physical-name.js';
|
|
11
11
|
export { joinGraph, MAX_JOIN_DEPTH } from './join-graph.js';
|
|
12
12
|
export { filterOperatorFor, filterOperator, filterOn, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { projectRoots } from './project.js';
|
|
2
2
|
export type { ProjectedNode, ProjectionContext, SearchDocument, } from './project.js';
|
|
3
3
|
export { defineSearchType, searchSchema, validateSearchType, assertValidSearchType, ID_FIELD, AND_KEY, OR_KEY, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
4
|
-
export type { FieldKind, SearchField, SearchFieldBase, TextField, KeywordField, ReferenceField, NumericField, BooleanField, SearchType, SearchTypeBase, RootType, ReferenceType, RootTypeOf, SearchTypeIssue, SearchSchema, FacetRange, ProjectionValue, } from './schema.js';
|
|
4
|
+
export type { FieldKind, SearchField, SearchFieldBase, TextField, KeywordField, ReferenceField, ReferenceStrategy, NumericField, BooleanField, SearchType, SearchTypeBase, RootType, ReferenceType, RootTypeOf, SearchTypeIssue, SearchSchema, FacetRange, ProjectionValue, } from './schema.js';
|
|
5
5
|
export { joinGraph, MAX_JOIN_DEPTH } from './join-graph.js';
|
|
6
6
|
export type { JoinGraph } from './join-graph.js';
|
|
7
7
|
export { filterOn } from './query.js';
|
|
8
|
-
export type { SearchQuery, Filter, Criterion, CriterionBase, Sort, } from './query.js';
|
|
8
|
+
export type { SearchQuery, ReferenceProjection, Filter, Criterion, CriterionBase, Sort, } from './query.js';
|
|
9
9
|
export type { SearchEngine, SearchResult, SearchHit, ResultDocument, SearchValue, LocalizedValue, Reference, NestedDocument, FacetBucket, FacetMap, FacetsOutcome, FacetFieldsOf, OutputFieldsOf, } from './engine.js';
|
|
10
10
|
export type { FramedNode } from './frame-by-type.js';
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,QAAQ,EACR,OAAO,EACP,MAAM,EAMN,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,EACT,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,eAAe,GAChB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,aAAa,EACb,IAAI,GACL,MAAM,YAAY,CAAC;AAIpB,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,cAAc,EACd,WAAW,EACX,cAAc,EACd,SAAS,EACT,cAAc,EACd,WAAW,EACX,QAAQ,EACR,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,QAAQ,EACR,OAAO,EACP,MAAM,EAMN,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,EACT,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,eAAe,GAChB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,MAAM,EACN,SAAS,EACT,aAAa,EACb,IAAI,GACL,MAAM,YAAY,CAAC;AAIpB,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,cAAc,EACd,WAAW,EACX,cAAc,EACd,SAAS,EACT,cAAc,EACd,WAAW,EACX,QAAQ,EACR,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/join-graph.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join-graph.d.ts","sourceRoot":"","sources":["../src/join-graph.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"join-graph.d.ts","sourceRoot":"","sources":["../src/join-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAErB;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,CAAC;IACtD;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC1E;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAQzD"}
|
package/dist/join-graph.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { referenceFields, } from './schema.js';
|
|
1
|
+
import { labelSourceNameOf, referenceFields, } from './schema.js';
|
|
2
2
|
/**
|
|
3
3
|
* The deepest `on` path a query may state: `dataset → publisher → country` is
|
|
4
4
|
* three hops. Fixed rather than configurable, and enforced in the query IR
|
|
@@ -97,12 +97,13 @@ function declaredEdges(searchType, byName) {
|
|
|
97
97
|
if (field.joinable !== true) {
|
|
98
98
|
continue;
|
|
99
99
|
}
|
|
100
|
-
// Both lookups always hit: `validateSearchType` rejects `joinable`
|
|
101
|
-
//
|
|
102
|
-
// must declare a `searchable`
|
|
103
|
-
// carry (a nested field is `output`
|
|
104
|
-
// collection at the far end without
|
|
105
|
-
|
|
100
|
+
// Both lookups always hit: `validateSearchType` rejects `joinable` on a
|
|
101
|
+
// reference that names no type to resolve against, and such a type is
|
|
102
|
+
// always an indexed Root Type – it must declare a `searchable` label
|
|
103
|
+
// field, which a Reference Type cannot carry (a nested field is `output`
|
|
104
|
+
// only). So a joinable edge always has a collection at the far end without
|
|
105
|
+
// a rule of its own.
|
|
106
|
+
const target = byName.get(labelSourceNameOf(field));
|
|
106
107
|
const claimed = claimedBy.get(target.name);
|
|
107
108
|
if (claimed !== undefined) {
|
|
108
109
|
throw new Error(`Search type “${searchType.name}” declares two joinable references to “${target.name}” (“${claimed}” and “${field.name}”); an engine addresses a join by collection, not by field, so only one reference per target can be joinable. Drop “joinable” from one of them – it keeps its labels, facets and id filtering.`);
|
package/dist/project.js
CHANGED
|
@@ -123,7 +123,7 @@ function applyField(document, node, field, searchType, schema, context) {
|
|
|
123
123
|
if (field.derive !== undefined) {
|
|
124
124
|
const derived = field.derive(document, context);
|
|
125
125
|
// A derived `reference` is held to the same rule as a read one: what it
|
|
126
|
-
// stores is a selection key, and the surface types it `IRI`. ADR
|
|
126
|
+
// stores is a selection key, and the surface types it `IRI`. ADR 21 sends
|
|
127
127
|
// an IRI-valued `keyword` derive here by converting it to `reference`, so
|
|
128
128
|
// this is the busiest way a non-IRI could otherwise reach the index. A
|
|
129
129
|
// value that survives nothing leaves the field absent, exactly as a derive
|
|
@@ -132,11 +132,17 @@ function applyField(document, node, field, searchType, schema, context) {
|
|
|
132
132
|
? derivedIris(derived)
|
|
133
133
|
: // A derived `date` goes through the same storage codec as a read one:
|
|
134
134
|
// the field is stored as Unix seconds, so an ISO string returned here
|
|
135
|
-
// would otherwise land as a string in an int64 field.
|
|
136
|
-
// already computed seconds returns a number and passes through.
|
|
135
|
+
// would otherwise land as a string in an int64 field.
|
|
137
136
|
field.kind === 'date' && typeof derived === 'string'
|
|
138
137
|
? isoToUnixSeconds(derived)
|
|
139
|
-
:
|
|
138
|
+
: // A derive that computed seconds itself returns a number, which the
|
|
139
|
+
// codec never saw and so never range-checked. Seconds outside what
|
|
140
|
+
// `Date` can represent – reachable now that deep time is – would
|
|
141
|
+
// store fine and then throw on every read at the surface, where an
|
|
142
|
+
// unparseable string merely leaves the field absent. Drop it too.
|
|
143
|
+
field.kind === 'date' && typeof derived === 'number'
|
|
144
|
+
? storableSeconds(derived)
|
|
145
|
+
: derived;
|
|
140
146
|
// NaN is not a value any kind stores, and a derive is the only route that
|
|
141
147
|
// can produce one (`setNumber` guards the read route). It serializes as
|
|
142
148
|
// `null`, which an engine rejects for a numeric field – so drop it, leaving
|
|
@@ -421,6 +427,12 @@ function derivedIris(value) {
|
|
|
421
427
|
}
|
|
422
428
|
return typeof value === 'string' && isAbsoluteIri(value) ? value : undefined;
|
|
423
429
|
}
|
|
430
|
+
/** Stored Unix seconds a `Date` can represent, or `undefined` – the same
|
|
431
|
+
* answer {@link isoToUnixSeconds} gives a string it cannot parse, so the two
|
|
432
|
+
* routes into a `date` field agree on what is storable. */
|
|
433
|
+
function storableSeconds(seconds) {
|
|
434
|
+
return Number.isNaN(new Date(seconds * 1000).getTime()) ? undefined : seconds;
|
|
435
|
+
}
|
|
424
436
|
function toInteger(literal) {
|
|
425
437
|
return literal === undefined ? undefined : Math.trunc(Number(literal));
|
|
426
438
|
}
|
package/dist/query.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SearchType } from './schema.js';
|
|
1
|
+
import { type SearchSchema, type SearchType } from './schema.js';
|
|
2
2
|
import { type JoinGraph } from './join-graph.js';
|
|
3
3
|
/**
|
|
4
4
|
* The engine- and protocol-neutral query IR. Every API surface compiles its
|
|
@@ -20,6 +20,16 @@ export interface SearchQuery {
|
|
|
20
20
|
readonly facets: readonly string[];
|
|
21
21
|
/** Selects the per-locale fields to query/sort on (from `Accept-Language`). */
|
|
22
22
|
readonly locale: string;
|
|
23
|
+
/**
|
|
24
|
+
* Which `lookup` references to resolve on the hits, and how much of each
|
|
25
|
+
* referent to carry. Omitted (or a field left out of it), a lookup resolves
|
|
26
|
+
* its target’s label alone – what every reference carried before.
|
|
27
|
+
*
|
|
28
|
+
* A surface builds this from what its caller asked for (GraphQL: the
|
|
29
|
+
* selection set), so the engine fetches neither less nor more. See
|
|
30
|
+
* [ADR 20](../../docs/decisions/0020-resolve-a-references-fields-from-the-targets-own-collection.md).
|
|
31
|
+
*/
|
|
32
|
+
readonly resolve?: ReferenceProjection;
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* What every {@link Criterion} carries, whatever its operator: the field it
|
|
@@ -50,6 +60,19 @@ export interface CriterionBase {
|
|
|
50
60
|
*/
|
|
51
61
|
readonly on?: readonly string[];
|
|
52
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* What to carry for each resolved reference, keyed by the reference field’s
|
|
65
|
+
* name. `fields` names the referent’s own output fields; `resolve` nests, for a
|
|
66
|
+
* referent whose own references are wanted in turn – an engine answers one
|
|
67
|
+
* batched lookup per level, never one per document.
|
|
68
|
+
*
|
|
69
|
+
* Deliberately the shape of a selection set rather than a second vocabulary: a
|
|
70
|
+
* per-level option (a `limit` here, a `where` there) would multiply with depth.
|
|
71
|
+
*/
|
|
72
|
+
export type ReferenceProjection = Readonly<Record<string, {
|
|
73
|
+
readonly fields?: readonly string[];
|
|
74
|
+
readonly resolve?: ReferenceProjection;
|
|
75
|
+
}>>;
|
|
53
76
|
/**
|
|
54
77
|
* One criterion on one field. The operator is fixed by that field’s
|
|
55
78
|
* {@link FieldKind} ({@link filterOperatorFor}): keyword/reference use `in` (OR
|
|
@@ -139,14 +162,16 @@ export declare function isUnsatisfiable(query: SearchQuery): boolean;
|
|
|
139
162
|
* clause with no criteria) are NOT issues – a compiler skips those as no-ops.
|
|
140
163
|
*/
|
|
141
164
|
export interface QueryIssue {
|
|
142
|
-
readonly part: 'where' | 'facets' | 'orderBy';
|
|
165
|
+
readonly part: 'where' | 'facets' | 'orderBy' | 'resolve';
|
|
143
166
|
readonly field: string;
|
|
144
167
|
readonly reason: 'unknown-field' | 'not-filterable' | 'operator-mismatch' | 'not-facetable'
|
|
145
168
|
/** The criterion’s `on` path is longer than {@link MAX_JOIN_DEPTH}. */
|
|
146
169
|
| 'join-too-deep'
|
|
147
170
|
/** The `on` path does not resolve: a name that is not a field, a reference
|
|
148
171
|
* that is not `joinable`, or no join graph to resolve it against. */
|
|
149
|
-
| 'unknown-join'
|
|
172
|
+
| 'unknown-join'
|
|
173
|
+
/** A projected reference is not a `lookup`, so nothing resolves it. */
|
|
174
|
+
| 'not-resolvable';
|
|
150
175
|
}
|
|
151
176
|
/**
|
|
152
177
|
* Structurally validate a query against its search type: **every criterion of
|
|
@@ -168,15 +193,20 @@ export interface QueryIssue {
|
|
|
168
193
|
* with no join path needs none; a joined criterion validated without one is an
|
|
169
194
|
* `unknown-join`, never a silently unchecked filter.
|
|
170
195
|
*
|
|
196
|
+
* A `resolve` projection is checked at every level, which is why the whole
|
|
197
|
+
* `schema` is passed alongside the type being queried: each level’s fields
|
|
198
|
+
* belong to the `target` the level above names, and only the schema resolves a
|
|
199
|
+
* target to its type.
|
|
200
|
+
*
|
|
171
201
|
* This is the port’s always-on guard: every {@link SearchEngine} adapter MUST
|
|
172
202
|
* reject a query with issues ({@link assertValidQuery}) instead of passing
|
|
173
203
|
* garbage to its engine, so validation holds for every caller – including
|
|
174
204
|
* `queryDefaults` policies and surfaces weaker than GraphQL.
|
|
175
205
|
*/
|
|
176
|
-
export declare function validateQuery(query: SearchQuery, searchType: SearchType, joins?: JoinGraph): readonly QueryIssue[];
|
|
206
|
+
export declare function validateQuery(query: SearchQuery, searchType: SearchType, schema: SearchSchema, joins?: JoinGraph): readonly QueryIssue[];
|
|
177
207
|
/** Throw on the first structurally invalid query part ({@link validateQuery}),
|
|
178
208
|
* naming every issue. The always-on entry point for engine adapters. */
|
|
179
|
-
export declare function assertValidQuery(query: SearchQuery, searchType: SearchType, joins?: JoinGraph): void;
|
|
209
|
+
export declare function assertValidQuery(query: SearchQuery, searchType: SearchType, schema: SearchSchema, joins?: JoinGraph): void;
|
|
180
210
|
/**
|
|
181
211
|
* The 1-based page an `offset` falls on – the numbered-pagination presentation
|
|
182
212
|
* of the IR, shared by the surfaces and the adapters. `limit: 0` (a facet-only
|
package/dist/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAClC,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
package/dist/query.js
CHANGED
|
@@ -77,12 +77,17 @@ function issueField(criterion) {
|
|
|
77
77
|
* with no join path needs none; a joined criterion validated without one is an
|
|
78
78
|
* `unknown-join`, never a silently unchecked filter.
|
|
79
79
|
*
|
|
80
|
+
* A `resolve` projection is checked at every level, which is why the whole
|
|
81
|
+
* `schema` is passed alongside the type being queried: each level’s fields
|
|
82
|
+
* belong to the `target` the level above names, and only the schema resolves a
|
|
83
|
+
* target to its type.
|
|
84
|
+
*
|
|
80
85
|
* This is the port’s always-on guard: every {@link SearchEngine} adapter MUST
|
|
81
86
|
* reject a query with issues ({@link assertValidQuery}) instead of passing
|
|
82
87
|
* garbage to its engine, so validation holds for every caller – including
|
|
83
88
|
* `queryDefaults` policies and surfaces weaker than GraphQL.
|
|
84
89
|
*/
|
|
85
|
-
export function validateQuery(query, searchType, joins) {
|
|
90
|
+
export function validateQuery(query, searchType, schema, joins) {
|
|
86
91
|
const issues = [];
|
|
87
92
|
for (const filter of query.where) {
|
|
88
93
|
// Each criterion is checked on its own, so a multi-criterion clause needs
|
|
@@ -149,6 +154,7 @@ export function validateQuery(query, searchType, joins) {
|
|
|
149
154
|
issues.push({ part: 'facets', field: name, reason: 'not-facetable' });
|
|
150
155
|
}
|
|
151
156
|
}
|
|
157
|
+
collectProjectionIssues(query.resolve, searchType, schema, issues);
|
|
152
158
|
for (const sort of query.orderBy) {
|
|
153
159
|
if (sort.field !== 'relevance' &&
|
|
154
160
|
fieldNamed(searchType, sort.field) === undefined) {
|
|
@@ -161,10 +167,50 @@ export function validateQuery(query, searchType, joins) {
|
|
|
161
167
|
}
|
|
162
168
|
return issues;
|
|
163
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Walk a projection level by level: each key names a `lookup` reference on the
|
|
172
|
+
* type that level belongs to, each `fields` entry an `output` field of the
|
|
173
|
+
* target it resolves against, and each nested `resolve` repeats against that
|
|
174
|
+
* target. A level whose reference is unresolvable stops there – its subtree
|
|
175
|
+
* belongs to a target that does not exist, so reporting it too would bury the
|
|
176
|
+
* one mistake under its consequences.
|
|
177
|
+
*/
|
|
178
|
+
function collectProjectionIssues(projection, searchType, schema, issues) {
|
|
179
|
+
for (const [name, level] of Object.entries(projection ?? {})) {
|
|
180
|
+
const field = fieldNamed(searchType, name);
|
|
181
|
+
if (field === undefined) {
|
|
182
|
+
issues.push({ part: 'resolve', field: name, reason: 'unknown-field' });
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (field.kind !== 'reference' || field.ref?.strategy !== 'lookup') {
|
|
186
|
+
issues.push({ part: 'resolve', field: name, reason: 'not-resolvable' });
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const targetName = field.ref.target;
|
|
190
|
+
const target = [...schema.values()].find((rootType) => rootType.name === targetName);
|
|
191
|
+
if (target === undefined) {
|
|
192
|
+
// searchSchema rejects a lookup whose target it cannot resolve, so this
|
|
193
|
+
// is a query built against a different schema than the engine serves.
|
|
194
|
+
issues.push({ part: 'resolve', field: name, reason: 'not-resolvable' });
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
for (const wanted of level.fields ?? []) {
|
|
198
|
+
const targetField = fieldNamed(target, wanted);
|
|
199
|
+
if (targetField === undefined || targetField.output !== true) {
|
|
200
|
+
issues.push({
|
|
201
|
+
part: 'resolve',
|
|
202
|
+
field: `${name}.${wanted}`,
|
|
203
|
+
reason: 'unknown-field',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
collectProjectionIssues(level.resolve, target, schema, issues);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
164
210
|
/** Throw on the first structurally invalid query part ({@link validateQuery}),
|
|
165
211
|
* naming every issue. The always-on entry point for engine adapters. */
|
|
166
|
-
export function assertValidQuery(query, searchType, joins) {
|
|
167
|
-
const issues = validateQuery(query, searchType, joins);
|
|
212
|
+
export function assertValidQuery(query, searchType, schema, joins) {
|
|
213
|
+
const issues = validateQuery(query, searchType, schema, joins);
|
|
168
214
|
if (issues.length > 0) {
|
|
169
215
|
const detail = issues
|
|
170
216
|
.map((issue) => `${issue.part}: “${issue.field}” (${issue.reason})`)
|
package/dist/schema.d.ts
CHANGED
|
@@ -174,7 +174,38 @@ export interface KeywordField extends SearchFieldBase, Searchable {
|
|
|
174
174
|
* exclusive with `path` and `derive`. */
|
|
175
175
|
readonly from?: ProjectionValue;
|
|
176
176
|
}
|
|
177
|
-
/**
|
|
177
|
+
/**
|
|
178
|
+
* Where a reference’s fields come from – the one axis the three shapes sit on:
|
|
179
|
+
*
|
|
180
|
+
* - `idOnly` carries the bare IRI and nothing else. It emits no type, so it
|
|
181
|
+
* names none; a {@link ReferenceField.labelSource} still labels its facet
|
|
182
|
+
* buckets.
|
|
183
|
+
* - `lookup` carries fields read from the **target’s own indexed document**,
|
|
184
|
+
* resolved at query time from that Root Type’s collection. `target` names it
|
|
185
|
+
* once – the collection to read and the emitted type name alike (GraphQL:
|
|
186
|
+
* `‹Target›Reference`, since type names must be unique).
|
|
187
|
+
* - `inline` carries fields denormalised from the **parent’s** RDF framing at
|
|
188
|
+
* index time, shaped by the declared {@link ReferenceType} `typeName` names –
|
|
189
|
+
* so its typeName can never name a root type.
|
|
190
|
+
*/
|
|
191
|
+
export type ReferenceStrategy = {
|
|
192
|
+
readonly strategy: 'idOnly';
|
|
193
|
+
/** Optional, unlike the other strategies – including when the field is
|
|
194
|
+
* `output`: an `idOnly` reference surfaces as its bare IRI, so there is
|
|
195
|
+
* no object type to name. It names the reference’s *filter* target
|
|
196
|
+
* instead, so declare it where the referent’s IRIs form a nameable set a
|
|
197
|
+
* consumer should be able to tell from IRIs at large; omit it for IRIs
|
|
198
|
+
* that belong to no such set. */
|
|
199
|
+
readonly typeName?: string;
|
|
200
|
+
readonly target?: never;
|
|
201
|
+
} | {
|
|
202
|
+
readonly strategy: 'lookup';
|
|
203
|
+
readonly target: string;
|
|
204
|
+
} | {
|
|
205
|
+
readonly strategy: 'inline';
|
|
206
|
+
readonly typeName: string;
|
|
207
|
+
};
|
|
208
|
+
/** An IRI-valued reference to another entity, resolved at the surface. */
|
|
178
209
|
export interface ReferenceField extends SearchFieldBase, Searchable {
|
|
179
210
|
readonly kind: 'reference';
|
|
180
211
|
/** Projection-time value transform. */
|
|
@@ -186,22 +217,23 @@ export interface ReferenceField extends SearchFieldBase, Searchable {
|
|
|
186
217
|
* with `path` and `derive`. */
|
|
187
218
|
readonly from?: ProjectionValue;
|
|
188
219
|
/**
|
|
189
|
-
* The `name` of the
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
220
|
+
* The `name` of the Root Type whose collection labels this reference’s facet
|
|
221
|
+
* buckets. Only an `idOnly` reference declares one: a `lookup` reads its
|
|
222
|
+
* labels from the `target` it already names, and an `inline` reference
|
|
223
|
+
* carries the referent’s own fields. The named type must declare an `output`,
|
|
224
|
+
* `searchable` text field under its {@link SearchTypeBase.labelField} name
|
|
225
|
+
* (`label` by default; validated by {@link searchSchema}), so an engine can
|
|
226
|
+
* both reconstruct the label and search it (typeahead).
|
|
196
227
|
*/
|
|
197
228
|
readonly labelSource?: string;
|
|
198
229
|
/**
|
|
199
230
|
* Turn this reference into an **engine-level join**, so a query can filter
|
|
200
231
|
* this type by a condition on the referent – `“every object published by
|
|
201
|
-
* institution X”` in one round-trip instead of two. Valid only
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
232
|
+
* institution X”` in one round-trip instead of two. Valid only where the
|
|
233
|
+
* reference names the type it resolves against – a `lookup`’s `target` or an
|
|
234
|
+
* `idOnly`’s {@link ReferenceField.labelSource} ({@link labelSourceNameOf}) –
|
|
235
|
+
* which already asserts that this field’s values are ids of documents in that
|
|
236
|
+
* type’s collection, exactly the fact a join needs.
|
|
205
237
|
*
|
|
206
238
|
* A capability flag in the vocabulary of `filterable`/`facetable`/`sortable`,
|
|
207
239
|
* and deliberately not derived from `labelSource`: an engine may refuse to
|
|
@@ -218,54 +250,20 @@ export interface ReferenceField extends SearchFieldBase, Searchable {
|
|
|
218
250
|
*/
|
|
219
251
|
readonly joinable?: boolean;
|
|
220
252
|
/**
|
|
221
|
-
* The referenced entity’s shape and
|
|
222
|
-
* the field is `output` – the strategy is what decides the output shape, so
|
|
223
|
-
*
|
|
253
|
+
* The referenced entity’s shape and where its fields come from. Required when
|
|
254
|
+
* the field is `output` – the strategy is what decides the output shape, so a
|
|
255
|
+
* surfaced reference must state it; optional for a facet- or filter-only
|
|
224
256
|
* reference.
|
|
225
257
|
*
|
|
226
|
-
* A **discriminated union by `strategy
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* then tell IRIs of that target apart from IRIs at large.
|
|
258
|
+
* A **discriminated union by `strategy`** ({@link ReferenceStrategy}), because
|
|
259
|
+
* what names the referent differs per strategy and is meaningless for the
|
|
260
|
+
* others: a `lookup` names the Root Type it reads from, an `inline` one names
|
|
261
|
+
* a declared {@link ReferenceType}, and an `idOnly` one carries a bare IRI
|
|
262
|
+
* that may belong to no declared type at all (`sameAs` points at a vocabulary
|
|
263
|
+
* nobody indexes). See
|
|
264
|
+
* [ADR 20](../../docs/decisions/0020-resolve-a-references-fields-from-the-targets-own-collection.md).
|
|
234
265
|
*/
|
|
235
|
-
readonly ref?:
|
|
236
|
-
/** Logical API type name of the referenced entity (PascalCase, e.g.
|
|
237
|
-
* `Organization`) – names the reference’s type in the API surfaces,
|
|
238
|
-
* the way {@link SearchType.name} names a root type; fields sharing it
|
|
239
|
-
* share one emitted type. For a `labelOnly` reference it is a name,
|
|
240
|
-
* not a key: it need not correspond to any indexed root type, and it
|
|
241
|
-
* may name one (`creator` → `Person`, with the labels resolved from
|
|
242
|
-
* that root’s collection via `labelSource`) – an API surface then
|
|
243
|
-
* serves the reference under a derived name (GraphQL:
|
|
244
|
-
* `‹Name›Reference`) to keep type names unique. An `inline`
|
|
245
|
-
* reference’s typeName instead resolves to a declared
|
|
246
|
-
* {@link ReferenceType}, so it can never name a root type. */
|
|
247
|
-
readonly typeName: string;
|
|
248
|
-
/** `labelOnly` carries the id plus a display label resolved from a
|
|
249
|
-
* label source; `inline` carries the referent’s own projected fields
|
|
250
|
-
* through a declared {@link ReferenceType} (see
|
|
251
|
-
* {@link isInlineReference}). */
|
|
252
|
-
readonly strategy: 'labelOnly' | 'inline';
|
|
253
|
-
} | {
|
|
254
|
-
/** Optional here, unlike the other strategies: an `idOnly` reference
|
|
255
|
-
* emits no type of its own, so a name is not needed to emit one under.
|
|
256
|
-
* Declare it when the referent’s IRIs form a nameable set an API
|
|
257
|
-
* surface should distinguish; omit it for IRIs that belong to no such
|
|
258
|
-
* set. */
|
|
259
|
-
readonly typeName?: string;
|
|
260
|
-
/** The IRI, and nothing else – no label resolution, no nested fields.
|
|
261
|
-
* Surfaces as a bare IRI rather than an object, which is what makes it
|
|
262
|
-
* the right strategy for a reference whose referent is not an entity
|
|
263
|
-
* this deployment describes: a canonical vocabulary URI, a licence, a
|
|
264
|
-
* content URL. A {@link ReferenceField.labelSource} is still honoured
|
|
265
|
-
* for facet bucket labels – the strategy governs the output shape, not
|
|
266
|
-
* whether a bucket can be labelled. */
|
|
267
|
-
readonly strategy: 'idOnly';
|
|
268
|
-
};
|
|
266
|
+
readonly ref?: ReferenceStrategy;
|
|
269
267
|
}
|
|
270
268
|
/**
|
|
271
269
|
* Range-facet bins for a numeric (`integer`/`number`/`date`) facetable field.
|
|
@@ -482,6 +480,13 @@ export declare function labelFieldNameOf(searchType: SearchType): string;
|
|
|
482
480
|
* named as a {@link ReferenceField.labelSource}.
|
|
483
481
|
*/
|
|
484
482
|
export declare function labelFieldOf(searchType: SearchType): TextField | undefined;
|
|
483
|
+
/**
|
|
484
|
+
* The Root Type a reference resolves labels from, by name: a `lookup`’s
|
|
485
|
+
* `target`, an `idOnly`’s {@link ReferenceField.labelSource}, or `undefined`
|
|
486
|
+
* when it resolves none. One reading for the two declarations, so a consumer
|
|
487
|
+
* never branches on the strategy to find the collection.
|
|
488
|
+
*/
|
|
489
|
+
export declare function labelSourceNameOf(field: ReferenceField): string | undefined;
|
|
485
490
|
/**
|
|
486
491
|
* One structural problem {@link validateSearchType} found: a field declares a
|
|
487
492
|
* capability or property its `kind` cannot honour, or the declaration is
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGrE;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GACnB,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,CAAC;AAE/E;oEACoE;AACpE,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;AAcnD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,GAAG,SAAS,CAE7E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,MAAM,WAAW,GACrB,SAAS,GAAG,YAAY,GAAG,cAAc,GAAG,YAAY,GAAG,YAAY,CAAC;AAE1E,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B;wCACoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;+EAC2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;2DAGuD;IACvD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;yCAEqC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,yBAAyB;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,iCAAiC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAChB,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC;CACd;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC;AAExC;kEACkE;AAClE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAU,SAAQ,eAAe,EAAE,UAAU;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC;CAC9B;AAED;gCACgC;AAChC,MAAM,WAAW,YAAa,SAAQ,eAAe,EAAE,UAAU;IAC/D,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC;IAC7B;8CAC0C;IAC1C,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC;CACjC;AAED
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.js
CHANGED
|
@@ -246,6 +246,12 @@ function assertServiceableNestedFields(referenceTypes) {
|
|
|
246
246
|
if (field.labelSource !== undefined) {
|
|
247
247
|
throw new Error(`Nested field “${referenceType.name}.${field.name}” declares a label source, which an inline reference cannot serve; nest the referent through an inline reference instead of resolving a label for it.`);
|
|
248
248
|
}
|
|
249
|
+
// A lookup is resolved from the hit's own projection, level by level; a
|
|
250
|
+
// nested document is read back with its referent and never appears in
|
|
251
|
+
// one. Accepting it would emit a type whose every field serves null.
|
|
252
|
+
if (field.kind === 'reference' && field.ref?.strategy === 'lookup') {
|
|
253
|
+
throw new Error(`Nested field “${referenceType.name}.${field.name}” is a lookup, which an inline reference cannot serve: a nested document is read back with its referent, so nothing resolves a lookup inside one. Nest the referent through an inline reference instead.`);
|
|
254
|
+
}
|
|
249
255
|
}
|
|
250
256
|
}
|
|
251
257
|
}
|
|
@@ -289,9 +295,21 @@ export function labelFieldOf(searchType) {
|
|
|
289
295
|
: undefined;
|
|
290
296
|
}
|
|
291
297
|
/**
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
298
|
+
* The Root Type a reference resolves labels from, by name: a `lookup`’s
|
|
299
|
+
* `target`, an `idOnly`’s {@link ReferenceField.labelSource}, or `undefined`
|
|
300
|
+
* when it resolves none. One reading for the two declarations, so a consumer
|
|
301
|
+
* never branches on the strategy to find the collection.
|
|
302
|
+
*/
|
|
303
|
+
export function labelSourceNameOf(field) {
|
|
304
|
+
return field.ref?.strategy === 'lookup'
|
|
305
|
+
? field.ref.target
|
|
306
|
+
: field.labelSource;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Every name a reference resolves labels from – a `lookup`’s `target` or an
|
|
310
|
+
* `idOnly`’s {@link ReferenceField.labelSource} – must be a declared type that
|
|
311
|
+
* can actually serve labels ({@link labelFieldOf}). Checked schema-wide,
|
|
312
|
+
* because a single declaration cannot see its siblings.
|
|
295
313
|
*
|
|
296
314
|
* That leaves only a {@link RootType}, without naming one: a label field is
|
|
297
315
|
* `searchable`, and {@link assertServiceableNestedFields} already rejects a
|
|
@@ -304,18 +322,29 @@ function assertResolvableLabelSources(types) {
|
|
|
304
322
|
for (const field of searchType.fields) {
|
|
305
323
|
const labelSource = field
|
|
306
324
|
.labelSource;
|
|
307
|
-
if (labelSource
|
|
308
|
-
|
|
325
|
+
if (labelSource !== undefined) {
|
|
326
|
+
if (field.kind !== 'reference') {
|
|
327
|
+
throw new Error(`Field “${searchType.name}.${field.name}” declares a label source but is a ${field.kind} field; only reference fields resolve labels from a source.`);
|
|
328
|
+
}
|
|
329
|
+
// A lookup reads its labels from the `target` it already names, and an
|
|
330
|
+
// inline reference carries the referent’s own fields – so a second name
|
|
331
|
+
// for the same thing could only disagree with the first.
|
|
332
|
+
if (field.ref !== undefined && field.ref.strategy !== 'idOnly') {
|
|
333
|
+
throw new Error(`Reference “${searchType.name}.${field.name}” declares a label source on a ${field.ref.strategy} reference; only an idOnly reference does, for its facet buckets.`);
|
|
334
|
+
}
|
|
309
335
|
}
|
|
310
|
-
|
|
311
|
-
|
|
336
|
+
const sourceName = field.kind === 'reference' && field.ref?.strategy === 'lookup'
|
|
337
|
+
? field.ref.target
|
|
338
|
+
: labelSource;
|
|
339
|
+
if (sourceName === undefined) {
|
|
340
|
+
continue;
|
|
312
341
|
}
|
|
313
|
-
const source = byName.get(
|
|
342
|
+
const source = byName.get(sourceName);
|
|
314
343
|
if (source === undefined) {
|
|
315
|
-
throw new Error(`Reference “${searchType.name}.${field.name}” names unknown label source “${
|
|
344
|
+
throw new Error(`Reference “${searchType.name}.${field.name}” names unknown label source “${sourceName}”; declare a SearchType with that name.`);
|
|
316
345
|
}
|
|
317
346
|
if (labelFieldOf(source) === undefined) {
|
|
318
|
-
throw new Error(`Reference “${searchType.name}.${field.name}” uses label source “${
|
|
347
|
+
throw new Error(`Reference “${searchType.name}.${field.name}” uses label source “${sourceName}”, which must declare an output, searchable text field “${labelFieldNameOf(source)}”.`);
|
|
319
348
|
}
|
|
320
349
|
}
|
|
321
350
|
}
|
|
@@ -461,20 +490,23 @@ export function validateSearchType(searchType) {
|
|
|
461
490
|
if (field.output === true && field.ref === undefined) {
|
|
462
491
|
issue('missing-ref');
|
|
463
492
|
}
|
|
464
|
-
// `typeName`
|
|
465
|
-
//
|
|
466
|
-
//
|
|
467
|
-
//
|
|
468
|
-
//
|
|
493
|
+
// `typeName` names the emitted type, and only an `inline` reference
|
|
494
|
+
// must declare one: a `lookup` derives its name from the `target` it
|
|
495
|
+
// already names, and an `idOnly` surfaces as a bare IRI, emitting no
|
|
496
|
+
// type at all. Without a name where one is needed, an API surface has
|
|
497
|
+
// nothing to emit – the GraphQL one silently prints `undefined` as the
|
|
498
|
+
// field's type, publishing a contract that is not a schema.
|
|
469
499
|
if (field.output === true &&
|
|
470
|
-
field.ref
|
|
471
|
-
|
|
472
|
-
|
|
500
|
+
((field.ref?.strategy === 'inline' &&
|
|
501
|
+
field.ref.typeName === undefined) ||
|
|
502
|
+
(field.ref?.strategy === 'lookup' && field.ref.target === undefined))) {
|
|
473
503
|
issue('missing-ref-type-name');
|
|
474
504
|
}
|
|
475
|
-
// A join addresses the referent
|
|
476
|
-
//
|
|
477
|
-
|
|
505
|
+
// A join addresses the referent's collection – the one a lookup's
|
|
506
|
+
// `target` or an idOnly's `labelSource` names. With neither, the flag
|
|
507
|
+
// states an edge to nowhere.
|
|
508
|
+
if (field.joinable === true &&
|
|
509
|
+
labelSourceNameOf(field) === undefined) {
|
|
478
510
|
issue('joinable-without-label-source');
|
|
479
511
|
}
|
|
480
512
|
// An inline reference is stored as a NESTED OBJECT, not as an id an
|
|
@@ -780,9 +812,36 @@ const ABSOLUTE_IRI = /^[A-Za-z][A-Za-z0-9+.-]*:\S*$/;
|
|
|
780
812
|
* unparseable value.
|
|
781
813
|
*/
|
|
782
814
|
export function isoToUnixSeconds(iso) {
|
|
783
|
-
|
|
815
|
+
// Trim first: XSD collapses whitespace around a date literal before parsing,
|
|
816
|
+
// so a padded lexical form is legal and reaches here verbatim. Left in place
|
|
817
|
+
// it defeats the year expansion below in both directions – a leading space
|
|
818
|
+
// stops the match, a trailing one survives it into the legacy parser – and
|
|
819
|
+
// each lands the value in a different year than it reads.
|
|
820
|
+
const millis = new Date(expandYear(iso.trim())).getTime();
|
|
784
821
|
return Number.isNaN(millis) ? undefined : Math.trunc(millis / 1000);
|
|
785
822
|
}
|
|
823
|
+
/**
|
|
824
|
+
* Pad a year outside the plain four-digit form to the signed six digits ISO
|
|
825
|
+
* 8601 expects, so `Date` reads it as a year at all. Deep time is real data,
|
|
826
|
+
* not a corner case: SCHEMA-AP-NDE blesses years beyond four digits for
|
|
827
|
+
* `schema:dateCreated`. Left unexpanded, neither era parses as written and
|
|
828
|
+
* neither fails loudly – `-1100` is read as a bare UTC offset and lands
|
|
829
|
+
* around 1100 **CE** (shifted by the host’s offset), `25000` is read as a
|
|
830
|
+
* legacy local-time date and lands a year early, on a boundary that moves
|
|
831
|
+
* with the host’s timezone. Either way nothing throws, no field is left
|
|
832
|
+
* absent, and the value sorts and filters as if it were another date
|
|
833
|
+
* entirely. A plain four-digit year and an already-expanded one pass through
|
|
834
|
+
* unchanged, so the form the API itself emits round-trips.
|
|
835
|
+
*/
|
|
836
|
+
function expandYear(iso) {
|
|
837
|
+
// The year, then the rest: a non-digit stops the run, so a longer digit
|
|
838
|
+
// string (epoch millis, say) is left alone rather than cut into a year.
|
|
839
|
+
const year = /^([+-]?)(\d{1,6})(\D.*|)$/.exec(iso);
|
|
840
|
+
if (year === null || (year[1] === '' && year[2].length === 4)) {
|
|
841
|
+
return iso;
|
|
842
|
+
}
|
|
843
|
+
return `${year[1] || '+'}${year[2].padStart(6, '0')}${year[3]}`;
|
|
844
|
+
}
|
|
786
845
|
/** The inverse of {@link isoToUnixSeconds}: stored Unix seconds → ISO 8601. */
|
|
787
846
|
export function unixSecondsToIso(seconds) {
|
|
788
847
|
return new Date(seconds * 1000).toISOString();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "Engine- and domain-agnostic core for RDF-backed search: a unified declarative field model (SearchField/SearchType/SearchSchema), a neutral query IR, the SearchEngine port with logical result types, and a streaming CONSTRUCT-to-document projection. Bakes in no engine, protocol, or domain.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "git+https://github.com/ldelements/lde.git",
|