@lde/search 0.17.0 → 0.18.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/adapter.d.ts +2 -2
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/query.d.ts +51 -16
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +60 -39
- package/dist/schema.d.ts +16 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +24 -4
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +7 -5
- package/package.json +1 -1
package/dist/adapter.d.ts
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
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, labelFieldOf, isRangeFacet, 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, isRangeFacet, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export type { PhysicalFields } from './schema.js';
|
|
11
11
|
export { physicalNameTokens } from './physical-name.js';
|
|
12
|
-
export { filterOperatorFor, filterOperator, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
|
12
|
+
export { filterOperatorFor, filterOperator, filterOn, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
|
13
13
|
export type { FilterOperator, QueryIssue } from './query.js';
|
|
14
14
|
//# sourceMappingURL=adapter.d.ts.map
|
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,YAAY,EACZ,YAAY,EACZ,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,EACL,iBAAiB,EACjB,cAAc,EACd,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,YAAY,EACZ,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,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,6 +6,6 @@
|
|
|
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, labelFieldOf, isRangeFacet, 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, isRangeFacet, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export { physicalNameTokens } from './physical-name.js';
|
|
11
|
-
export { filterOperatorFor, filterOperator, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
|
11
|
+
export { filterOperatorFor, filterOperator, filterOn, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { projectRoots } from './project.js';
|
|
2
2
|
export type { ProjectedNode, ProjectionContext, SearchDocument, } from './project.js';
|
|
3
|
-
export { defineSearchType, searchSchema, validateSearchType, assertValidSearchType, ID_FIELD, } from './schema.js';
|
|
3
|
+
export { defineSearchType, searchSchema, validateSearchType, assertValidSearchType, ID_FIELD, AND_KEY, OR_KEY, } from './schema.js';
|
|
4
4
|
export type { FieldKind, SearchField, SearchFieldBase, TextField, KeywordField, ReferenceField, NumericField, BooleanField, SearchType, SearchTypeBase, RootType, ReferenceType, RootTypeOf, SearchTypeIssue, SearchSchema, FacetRange, ProjectionValue, } from './schema.js';
|
|
5
|
-
export
|
|
5
|
+
export { filterOn } from './query.js';
|
|
6
|
+
export type { SearchQuery, Filter, Criterion, Sort } from './query.js';
|
|
6
7
|
export type { SearchEngine, SearchResult, SearchHit, ResultDocument, SearchValue, LocalizedValue, Reference, NestedDocument, FacetBucket, FacetMap, FacetsOutcome, FacetFieldsOf, OutputFieldsOf, } from './engine.js';
|
|
7
8
|
export type { FramedNode } from './frame-by-type.js';
|
|
8
9
|
//# 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,
|
|
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,GACP,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;AAOrB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvE,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/index.js
CHANGED
|
@@ -10,4 +10,10 @@ export { projectRoots } from './project.js';
|
|
|
10
10
|
// Unified field model: one declaration drives projection, engine collection
|
|
11
11
|
// schema, query semantics and the GraphQL surface – a discriminated union by
|
|
12
12
|
// `kind`, validated again at runtime when the schema is built.
|
|
13
|
-
export { defineSearchType, searchSchema, validateSearchType, assertValidSearchType, ID_FIELD, } from './schema.js';
|
|
13
|
+
export { defineSearchType, searchSchema, validateSearchType, assertValidSearchType, ID_FIELD, AND_KEY, OR_KEY, } from './schema.js';
|
|
14
|
+
// Engine- and protocol-neutral query IR (what a `queryDefaults` policy or an
|
|
15
|
+
// in-process caller writes).
|
|
16
|
+
// `filterOn` builds the ordinary one-criterion clause – the shape a consumer
|
|
17
|
+
// policy (`queryDefaults`) appends to `where`, so it belongs on the authoring
|
|
18
|
+
// surface and not only on the adapter one.
|
|
19
|
+
export { filterOn } from './query.js';
|
package/dist/query.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { type SearchType } from './schema.js';
|
|
|
8
8
|
export interface SearchQuery {
|
|
9
9
|
/** Free-text query; `undefined`/`''` means browse (no text ranking). */
|
|
10
10
|
readonly text?: string;
|
|
11
|
-
/** AND across
|
|
11
|
+
/** AND across clauses; each clause is a disjunction ({@link Filter}). */
|
|
12
12
|
readonly where: readonly Filter[];
|
|
13
13
|
/** Primary public sort plus any server tie-breaks, in precedence order. */
|
|
14
14
|
readonly orderBy: readonly Sort[];
|
|
@@ -21,12 +21,17 @@ export interface SearchQuery {
|
|
|
21
21
|
readonly locale: string;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* One
|
|
25
|
-
* ({@link filterOperatorFor}): keyword/reference use `in` (OR
|
|
26
|
-
* the numeric/date kinds use an inclusive `range`,
|
|
27
|
-
* inclusive only – no `gt`/`gte`/`lt`/`lte`.
|
|
24
|
+
* One criterion on one field. The operator is fixed by that field’s
|
|
25
|
+
* {@link FieldKind} ({@link filterOperatorFor}): keyword/reference use `in` (OR
|
|
26
|
+
* within the value list), the numeric/date kinds use an inclusive `range`,
|
|
27
|
+
* boolean uses `is`. Bounds are inclusive only – no `gt`/`gte`/`lt`/`lte`.
|
|
28
|
+
*
|
|
29
|
+
* Criteria are the atoms a {@link Filter} is built from, so each carries its own
|
|
30
|
+
* field AND its own operator: one clause may range over a `reference` and a
|
|
31
|
+
* `keyword` field at once, and each field is constrained the way its kind
|
|
32
|
+
* allows.
|
|
28
33
|
*/
|
|
29
|
-
export type
|
|
34
|
+
export type Criterion = {
|
|
30
35
|
readonly field: string;
|
|
31
36
|
readonly in: readonly string[];
|
|
32
37
|
} | {
|
|
@@ -39,6 +44,21 @@ export type Filter = {
|
|
|
39
44
|
readonly field: string;
|
|
40
45
|
readonly is: boolean;
|
|
41
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* One `where` clause: a disjunction, matching a document that satisfies **any**
|
|
49
|
+
* of its criteria. An ordinary single-field filter is the one-criterion case,
|
|
50
|
+
* so there is no separate cross-field variant for a consumer to overlook – an
|
|
51
|
+
* adapter that iterates `or` serves one criterion and five by the same code.
|
|
52
|
+
*
|
|
53
|
+
* Clauses AND together ({@link SearchQuery.where}), so a query is a **flat**
|
|
54
|
+
* conjunction of disjunctions. Deliberately flat rather than a boolean tree:
|
|
55
|
+
* skip-own-filter (ADR 5) removes *a facet’s own clause*, which has no answer
|
|
56
|
+
* once a clause can be nested inside another. A criterion is therefore an atom –
|
|
57
|
+
* it can never itself be a conjunction.
|
|
58
|
+
*/
|
|
59
|
+
export interface Filter {
|
|
60
|
+
readonly or: readonly Criterion[];
|
|
61
|
+
}
|
|
42
62
|
/** A single sort dimension. */
|
|
43
63
|
export interface Sort {
|
|
44
64
|
readonly field: string;
|
|
@@ -47,11 +67,15 @@ export interface Sort {
|
|
|
47
67
|
export { filterOperatorFor } from './schema.js';
|
|
48
68
|
export type { FilterOperator } from './schema.js';
|
|
49
69
|
import type { FilterOperator } from './schema.js';
|
|
50
|
-
/** The operator a {@link
|
|
51
|
-
export declare function filterOperator(
|
|
70
|
+
/** The operator a {@link Criterion} carries, from its discriminating key. */
|
|
71
|
+
export declare function filterOperator(criterion: Criterion): FilterOperator;
|
|
72
|
+
/** A one-criterion clause – the ordinary single-field filter, and the shape a
|
|
73
|
+
* keyed API surface compiles each of its keys into. */
|
|
74
|
+
export declare function filterOn(criterion: Criterion): Filter;
|
|
52
75
|
/**
|
|
53
76
|
* Whether the query asks for nothing, so no engine can answer it with a hit.
|
|
54
|
-
* True for an empty `in` on {@link ID_FIELD} – and
|
|
77
|
+
* True for an empty `in` on a clause naming {@link ID_FIELD} **alone** – and
|
|
78
|
+
* only there, deliberately:
|
|
55
79
|
*
|
|
56
80
|
* An **identity** filter enumerates the documents wanted, so the empty set
|
|
57
81
|
* wants none. A **value** filter constrains a dimension, so an empty set
|
|
@@ -62,6 +86,12 @@ export declare function filterOperator(filter: Filter): FilterOperator;
|
|
|
62
86
|
* specific things – the likely shape being a client mapping a possibly-empty
|
|
63
87
|
* reference array (`id: { in: doc.publisher }`) into a batch lookup.
|
|
64
88
|
*
|
|
89
|
+
* The identity reading needs the clause to be *only* about identity, so it must
|
|
90
|
+
* carry that one criterion and nothing else. A clause pairing `id` with a value
|
|
91
|
+
* field (`{ or: [{ field: 'id', in: [] }, { field: 'creator', in: [] }] }`)
|
|
92
|
+
* is a disjunction that happens to include identity, not an enumeration of
|
|
93
|
+
* wanted documents, so it stays the vacuous no-op every other empty `in` is.
|
|
94
|
+
*
|
|
65
95
|
* An adapter MUST answer an unsatisfiable query with an empty result rather
|
|
66
96
|
* than dispatching it.
|
|
67
97
|
*/
|
|
@@ -69,8 +99,11 @@ export declare function isUnsatisfiable(query: SearchQuery): boolean;
|
|
|
69
99
|
/**
|
|
70
100
|
* One structural problem {@link validateQuery} found: the query references a
|
|
71
101
|
* field the search type does not declare, or uses it in a role it does not
|
|
72
|
-
* opt into.
|
|
73
|
-
*
|
|
102
|
+
* opt into. Reported per **criterion**, so a clause carrying two criteria over
|
|
103
|
+
* unknown fields yields two issues, each naming its own field.
|
|
104
|
+
*
|
|
105
|
+
* Vacuous-but-valid clauses (an empty `in` list, a `range` with no bound, a
|
|
106
|
+
* clause with no criteria) are NOT issues – a compiler skips those as no-ops.
|
|
74
107
|
*/
|
|
75
108
|
export interface QueryIssue {
|
|
76
109
|
readonly part: 'where' | 'facets' | 'orderBy';
|
|
@@ -78,11 +111,13 @@ export interface QueryIssue {
|
|
|
78
111
|
readonly reason: 'unknown-field' | 'not-filterable' | 'operator-mismatch' | 'not-facetable';
|
|
79
112
|
}
|
|
80
113
|
/**
|
|
81
|
-
* Structurally validate a query against its search type: every
|
|
82
|
-
*
|
|
83
|
-
* ({@link filterOperatorFor}) – or the undeclared,
|
|
84
|
-
* {@link ID_FIELD}, which takes `in`; every requested facet is
|
|
85
|
-
* field; every sort is `relevance` or a declared field.
|
|
114
|
+
* Structurally validate a query against its search type: **every criterion of
|
|
115
|
+
* every `where` clause** names a declared, `filterable` field whose kind accepts
|
|
116
|
+
* that criterion’s operator ({@link filterOperatorFor}) – or the undeclared,
|
|
117
|
+
* always-filterable {@link ID_FIELD}, which takes `in`; every requested facet is
|
|
118
|
+
* a declared, `facetable` field; every sort is `relevance` or a declared field.
|
|
119
|
+
* Because each criterion is matched against its own field’s kind, one clause may
|
|
120
|
+
* range over fields of different kinds. Sorting deliberately
|
|
86
121
|
* checks declaration only, not the `sortable` flag: that flag means *publicly
|
|
87
122
|
* selectable*, and a deployment policy may sort on a private tie-break field.
|
|
88
123
|
*
|
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;AAErB;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAErB;;;;;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;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC1D;IACE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;KAChC,CAAC;CACH,GACD;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;CAAE,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,EAAE,EAAE,SAAS,SAAS,EAAE,CAAC;CACnC;AAED,+BAA+B;AAC/B,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;CACpC;AAKD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,CAEnE;AAED;wDACwD;AACxD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAErD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAW3D;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EACb,eAAe,GAAG,gBAAgB,GAAG,mBAAmB,GAAG,eAAe,CAAC;CAC9E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,UAAU,GACrB,SAAS,UAAU,EAAE,CA0DvB;AAED;yEACyE;AACzE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,UAAU,GACrB,IAAI,CAUN;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE"}
|
package/dist/query.js
CHANGED
|
@@ -3,13 +3,19 @@ import { fieldNamed, filterOperatorFor, ID_FIELD, } from './schema.js';
|
|
|
3
3
|
// for the query IR, the surfaces, the adapters AND declaration validation);
|
|
4
4
|
// re-exported here so the query-IR module stays the natural import site.
|
|
5
5
|
export { filterOperatorFor } from './schema.js';
|
|
6
|
-
/** The operator a {@link
|
|
7
|
-
export function filterOperator(
|
|
8
|
-
return 'in' in
|
|
6
|
+
/** The operator a {@link Criterion} carries, from its discriminating key. */
|
|
7
|
+
export function filterOperator(criterion) {
|
|
8
|
+
return 'in' in criterion ? 'in' : 'range' in criterion ? 'range' : 'is';
|
|
9
|
+
}
|
|
10
|
+
/** A one-criterion clause – the ordinary single-field filter, and the shape a
|
|
11
|
+
* keyed API surface compiles each of its keys into. */
|
|
12
|
+
export function filterOn(criterion) {
|
|
13
|
+
return { or: [criterion] };
|
|
9
14
|
}
|
|
10
15
|
/**
|
|
11
16
|
* Whether the query asks for nothing, so no engine can answer it with a hit.
|
|
12
|
-
* True for an empty `in` on {@link ID_FIELD} – and
|
|
17
|
+
* True for an empty `in` on a clause naming {@link ID_FIELD} **alone** – and
|
|
18
|
+
* only there, deliberately:
|
|
13
19
|
*
|
|
14
20
|
* An **identity** filter enumerates the documents wanted, so the empty set
|
|
15
21
|
* wants none. A **value** filter constrains a dimension, so an empty set
|
|
@@ -20,18 +26,33 @@ export function filterOperator(filter) {
|
|
|
20
26
|
* specific things – the likely shape being a client mapping a possibly-empty
|
|
21
27
|
* reference array (`id: { in: doc.publisher }`) into a batch lookup.
|
|
22
28
|
*
|
|
29
|
+
* The identity reading needs the clause to be *only* about identity, so it must
|
|
30
|
+
* carry that one criterion and nothing else. A clause pairing `id` with a value
|
|
31
|
+
* field (`{ or: [{ field: 'id', in: [] }, { field: 'creator', in: [] }] }`)
|
|
32
|
+
* is a disjunction that happens to include identity, not an enumeration of
|
|
33
|
+
* wanted documents, so it stays the vacuous no-op every other empty `in` is.
|
|
34
|
+
*
|
|
23
35
|
* An adapter MUST answer an unsatisfiable query with an empty result rather
|
|
24
36
|
* than dispatching it.
|
|
25
37
|
*/
|
|
26
38
|
export function isUnsatisfiable(query) {
|
|
27
|
-
return query.where.some((filter) =>
|
|
39
|
+
return query.where.some((filter) => {
|
|
40
|
+
const [criterion] = filter.or;
|
|
41
|
+
return (filter.or.length === 1 &&
|
|
42
|
+
criterion !== undefined &&
|
|
43
|
+
criterion.field === ID_FIELD &&
|
|
44
|
+
'in' in criterion &&
|
|
45
|
+
criterion.in.length === 0);
|
|
46
|
+
});
|
|
28
47
|
}
|
|
29
48
|
/**
|
|
30
|
-
* Structurally validate a query against its search type: every
|
|
31
|
-
*
|
|
32
|
-
* ({@link filterOperatorFor}) – or the undeclared,
|
|
33
|
-
* {@link ID_FIELD}, which takes `in`; every requested facet is
|
|
34
|
-
* field; every sort is `relevance` or a declared field.
|
|
49
|
+
* Structurally validate a query against its search type: **every criterion of
|
|
50
|
+
* every `where` clause** names a declared, `filterable` field whose kind accepts
|
|
51
|
+
* that criterion’s operator ({@link filterOperatorFor}) – or the undeclared,
|
|
52
|
+
* always-filterable {@link ID_FIELD}, which takes `in`; every requested facet is
|
|
53
|
+
* a declared, `facetable` field; every sort is `relevance` or a declared field.
|
|
54
|
+
* Because each criterion is matched against its own field’s kind, one clause may
|
|
55
|
+
* range over fields of different kinds. Sorting deliberately
|
|
35
56
|
* checks declaration only, not the `sortable` flag: that flag means *publicly
|
|
36
57
|
* selectable*, and a deployment policy may sort on a private tie-break field.
|
|
37
58
|
*
|
|
@@ -43,40 +64,40 @@ export function isUnsatisfiable(query) {
|
|
|
43
64
|
export function validateQuery(query, searchType) {
|
|
44
65
|
const issues = [];
|
|
45
66
|
for (const filter of query.where) {
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
// Each criterion is checked on its own, so a multi-criterion clause needs
|
|
68
|
+
// no rule of its own: naming an undeclared or non-filterable field is the
|
|
69
|
+
// same mistake whether the clause carries one criterion or five, and each
|
|
70
|
+
// criterion is matched against ITS OWN field’s kind – so one clause may mix
|
|
71
|
+
// a `reference` membership with a `date` range without either being wrong.
|
|
72
|
+
for (const criterion of filter.or) {
|
|
73
|
+
const name = criterion.field;
|
|
74
|
+
// `id` is filterable on every type without being declared by any: it is
|
|
75
|
+
// the document’s IRI, so the lookup exists wherever documents do.
|
|
76
|
+
// Membership only – an IRI has no range and no truth value.
|
|
77
|
+
if (name === ID_FIELD) {
|
|
78
|
+
if (filterOperator(criterion) !== 'in') {
|
|
79
|
+
issues.push({
|
|
80
|
+
part: 'where',
|
|
81
|
+
field: name,
|
|
82
|
+
reason: 'operator-mismatch',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const field = fieldNamed(searchType, name);
|
|
88
|
+
if (field === undefined) {
|
|
89
|
+
issues.push({ part: 'where', field: name, reason: 'unknown-field' });
|
|
90
|
+
}
|
|
91
|
+
else if (field.filterable !== true) {
|
|
92
|
+
issues.push({ part: 'where', field: name, reason: 'not-filterable' });
|
|
93
|
+
}
|
|
94
|
+
else if (filterOperatorFor(field.kind) !== filterOperator(criterion)) {
|
|
51
95
|
issues.push({
|
|
52
96
|
part: 'where',
|
|
53
|
-
field:
|
|
97
|
+
field: name,
|
|
54
98
|
reason: 'operator-mismatch',
|
|
55
99
|
});
|
|
56
100
|
}
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const field = fieldNamed(searchType, filter.field);
|
|
60
|
-
if (field === undefined) {
|
|
61
|
-
issues.push({
|
|
62
|
-
part: 'where',
|
|
63
|
-
field: filter.field,
|
|
64
|
-
reason: 'unknown-field',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
else if (field.filterable !== true) {
|
|
68
|
-
issues.push({
|
|
69
|
-
part: 'where',
|
|
70
|
-
field: filter.field,
|
|
71
|
-
reason: 'not-filterable',
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
else if (filterOperatorFor(field.kind) !== filterOperator(filter)) {
|
|
75
|
-
issues.push({
|
|
76
|
-
part: 'where',
|
|
77
|
-
field: filter.field,
|
|
78
|
-
reason: 'operator-mismatch',
|
|
79
|
-
});
|
|
80
101
|
}
|
|
81
102
|
}
|
|
82
103
|
for (const name of query.facets) {
|
package/dist/schema.d.ts
CHANGED
|
@@ -423,6 +423,22 @@ export interface SearchTypeIssue {
|
|
|
423
423
|
* {@link validateSearchType} rejects as `reserved-field-name`.
|
|
424
424
|
*/
|
|
425
425
|
export declare const ID_FIELD = "id";
|
|
426
|
+
/**
|
|
427
|
+
* The reserved `where` keys that name a **combinator** rather than a field.
|
|
428
|
+
* Sibling keys in a `where` object already AND, so `or` is what makes a
|
|
429
|
+
* disjunction expressible at all, and `and` is what lets a query carry more
|
|
430
|
+
* than one of them.
|
|
431
|
+
*
|
|
432
|
+
* They live in the same namespace a declaration draws from, so a field called
|
|
433
|
+
* `and` or `or` would shadow the combinator in `where` and silently answer a
|
|
434
|
+
* different question – exactly as a declared `id` would.
|
|
435
|
+
* {@link validateSearchType} rejects all three as `reserved-field-name`.
|
|
436
|
+
* Neither is plausible as an RDF property name; a deployment that needs one
|
|
437
|
+
* anyway can declare it under a different logical name, since the logical name
|
|
438
|
+
* is deliberately not derived from the predicate IRI.
|
|
439
|
+
*/
|
|
440
|
+
export declare const AND_KEY = "and";
|
|
441
|
+
export declare const OR_KEY = "or";
|
|
426
442
|
/**
|
|
427
443
|
* Structurally validate one {@link SearchType} declaration – the
|
|
428
444
|
* declaration-time counterpart of `validateQuery`. Rules:
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.js
CHANGED
|
@@ -312,6 +312,25 @@ function assertResolvableLabelSources(types) {
|
|
|
312
312
|
* {@link validateSearchType} rejects as `reserved-field-name`.
|
|
313
313
|
*/
|
|
314
314
|
export const ID_FIELD = 'id';
|
|
315
|
+
/**
|
|
316
|
+
* The reserved `where` keys that name a **combinator** rather than a field.
|
|
317
|
+
* Sibling keys in a `where` object already AND, so `or` is what makes a
|
|
318
|
+
* disjunction expressible at all, and `and` is what lets a query carry more
|
|
319
|
+
* than one of them.
|
|
320
|
+
*
|
|
321
|
+
* They live in the same namespace a declaration draws from, so a field called
|
|
322
|
+
* `and` or `or` would shadow the combinator in `where` and silently answer a
|
|
323
|
+
* different question – exactly as a declared `id` would.
|
|
324
|
+
* {@link validateSearchType} rejects all three as `reserved-field-name`.
|
|
325
|
+
* Neither is plausible as an RDF property name; a deployment that needs one
|
|
326
|
+
* anyway can declare it under a different logical name, since the logical name
|
|
327
|
+
* is deliberately not derived from the predicate IRI.
|
|
328
|
+
*/
|
|
329
|
+
export const AND_KEY = 'and';
|
|
330
|
+
export const OR_KEY = 'or';
|
|
331
|
+
/** The logical field names no {@link SearchType} may declare, each because a
|
|
332
|
+
* surface already gives that name a meaning of its own. */
|
|
333
|
+
const RESERVED_FIELD_NAMES = [ID_FIELD, AND_KEY, OR_KEY];
|
|
315
334
|
/** Kinds that can feed full-text search (project a folded search field). */
|
|
316
335
|
const SEARCHABLE_KINDS = ['text', 'keyword', 'reference'];
|
|
317
336
|
/** Kinds whose projection applies the {@link KeywordField.transform}. */
|
|
@@ -395,10 +414,11 @@ export function validateSearchType(searchType) {
|
|
|
395
414
|
if (!FIELD_NAME_PATTERN.test(field.name)) {
|
|
396
415
|
issue('invalid-field-name');
|
|
397
416
|
}
|
|
398
|
-
// `id` is the document’s IRI, surfaced and filtered for every type
|
|
399
|
-
//
|
|
400
|
-
// `where`, silently
|
|
401
|
-
|
|
417
|
+
// `id` is the document’s IRI, surfaced and filtered for every type, and
|
|
418
|
+
// `and`/`or` are the `where` combinators; a declared field of any of those
|
|
419
|
+
// names would shadow it in the API output or in `where`, silently
|
|
420
|
+
// answering a different question.
|
|
421
|
+
if (RESERVED_FIELD_NAMES.includes(field.name)) {
|
|
402
422
|
issue('reserved-field-name');
|
|
403
423
|
}
|
|
404
424
|
// Every kind-dependent rule below would silently pass for a kind outside
|
package/dist/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAmBhD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,YAAY,GACzB,IAAI,CAuON"}
|
package/dist/testing.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { filterOperatorFor, } from './query.js';
|
|
2
|
+
import { filterOn, filterOperatorFor, } from './query.js';
|
|
3
3
|
import { facetableFields, filterableFields, ID_FIELD, nestedReferenceType, outputFields, } from './schema.js';
|
|
4
4
|
/**
|
|
5
5
|
* The executable {@link SearchEngine} port contract (import from
|
|
@@ -48,7 +48,7 @@ export function describeSearchEngineContract(name, engine) {
|
|
|
48
48
|
for (const searchType of types()) {
|
|
49
49
|
const query = {
|
|
50
50
|
...browse(searchType),
|
|
51
|
-
where: [{ field: 'fieldThatDoesNotExist', in: ['x'] }],
|
|
51
|
+
where: [filterOn({ field: 'fieldThatDoesNotExist', in: ['x'] })],
|
|
52
52
|
};
|
|
53
53
|
await expect(engine().search(searchType, query)).rejects.toThrow(/unknown-field/);
|
|
54
54
|
}
|
|
@@ -62,7 +62,9 @@ export function describeSearchEngineContract(name, engine) {
|
|
|
62
62
|
for (const searchType of types()) {
|
|
63
63
|
const query = {
|
|
64
64
|
...browse(searchType),
|
|
65
|
-
where: [
|
|
65
|
+
where: [
|
|
66
|
+
filterOn({ field: ID_FIELD, in: ['urn:test:no-such-document'] }),
|
|
67
|
+
],
|
|
66
68
|
};
|
|
67
69
|
const result = await engine().search(searchType, query);
|
|
68
70
|
expect(result.total).toBe(0);
|
|
@@ -215,8 +217,8 @@ export function describeSearchEngineContract(name, engine) {
|
|
|
215
217
|
/** A filter whose operator deliberately mismatches the field’s kind. */
|
|
216
218
|
function mismatchedFilter(field, operator) {
|
|
217
219
|
return operator === 'in'
|
|
218
|
-
? { field, range: { min: 0 } }
|
|
219
|
-
: { field, in: ['x'] };
|
|
220
|
+
? filterOn({ field, range: { min: 0 } })
|
|
221
|
+
: filterOn({ field, in: ['x'] });
|
|
220
222
|
}
|
|
221
223
|
/** The locale a query against this type may select (any is contract-valid). */
|
|
222
224
|
function firstLocale(searchType) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
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",
|