@lde/search 0.22.1 → 0.23.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/query.d.ts CHANGED
@@ -154,9 +154,10 @@ export declare function filterOn(criterion: Criterion): Filter;
154
154
  export declare function isUnsatisfiable(query: SearchQuery): boolean;
155
155
  /**
156
156
  * One structural problem {@link validateQuery} found: the query references a
157
- * field the search type does not declare, or uses it in a role it does not
158
- * opt into. Reported per **criterion**, so a clause carrying two criteria over
159
- * unknown fields yields two issues, each naming its own field.
157
+ * field the search type does not declare, uses it in a role it does not opt
158
+ * into, or constrains it with a value that cannot be read. Reported per
159
+ * **criterion**, so a clause carrying two criteria over unknown fields yields
160
+ * two issues, each naming its own field.
160
161
  *
161
162
  * Vacuous-but-valid clauses (an empty `in` list, a `range` with no bound, a
162
163
  * clause with no criteria) are NOT issues – a compiler skips those as no-ops.
@@ -164,6 +165,9 @@ export declare function isUnsatisfiable(query: SearchQuery): boolean;
164
165
  export interface QueryIssue {
165
166
  readonly part: 'where' | 'facets' | 'orderBy' | 'resolve';
166
167
  readonly field: string;
168
+ /** The offending literal, on an issue about a **value** rather than a field:
169
+ * the bound of an `unparseable-bound`. Absent on every other reason. */
170
+ readonly value?: string;
167
171
  readonly reason: 'unknown-field' | 'not-filterable' | 'operator-mismatch' | 'not-facetable'
168
172
  /** The criterion’s `on` path is longer than {@link MAX_JOIN_DEPTH}. */
169
173
  | 'join-too-deep'
@@ -171,7 +175,18 @@ export interface QueryIssue {
171
175
  * that is not `joinable`, or no join graph to resolve it against. */
172
176
  | 'unknown-join'
173
177
  /** A projected reference is not a `lookup`, so nothing resolves it. */
174
- | 'not-resolvable';
178
+ | 'not-resolvable'
179
+ /**
180
+ * A `date` range bound the storage codec ({@link isoToUnixSeconds}) cannot
181
+ * read, so there is no stored value to compare against – reported per
182
+ * bound, each issue naming its own {@link QueryIssue.value}.
183
+ *
184
+ * Caught here rather than left to a compiler because the alternatives both
185
+ * lie: a dropped bound answers a *wider* question than the caller asked,
186
+ * and a rejected criterion answers a narrower one. Neither is the query,
187
+ * and only the caller can fix the bound.
188
+ */
189
+ | 'unparseable-bound';
175
190
  }
176
191
  /**
177
192
  * Structurally validate a query against its search type: **every criterion of
@@ -180,7 +195,10 @@ export interface QueryIssue {
180
195
  * always-filterable {@link ID_FIELD}, which takes `in`; every requested facet is
181
196
  * a declared, `facetable` field; every sort is `relevance` or a declared field.
182
197
  * Because each criterion is matched against its own field’s kind, one clause may
183
- * range over fields of different kinds. Sorting deliberately
198
+ * range over fields of different kinds. A `date` range is checked one step
199
+ * further, on its **values**: a bound the storage codec cannot read is an
200
+ * `unparseable-bound`, the one place a criterion is rejected for what it says
201
+ * rather than for what it names. Sorting deliberately
184
202
  * checks declaration only, not the `sortable` flag: that flag means *publicly
185
203
  * selectable*, and a deployment policy may sort on a private tie-break field.
186
204
  *
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EACjB,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;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B;gEAC4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CACxC,MAAM,CACJ,MAAM,EACN;IACE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACxC,CACF,CACF,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,SAAS,GACjB,CAAC,aAAa,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,GACpD,CAAC,aAAa,GAAG;IACf,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,CAAC,GACF,CAAC,aAAa,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE/C;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;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,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EACX,eAAe,GACf,gBAAgB,GAChB,mBAAmB,GACnB,eAAe;IACjB,uEAAuE;OACrE,eAAe;IACjB;0EACsE;OACpE,cAAc;IAChB,uEAAuE;OACrE,gBAAgB,CAAC;CACtB;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE,SAAS,GAChB,SAAS,UAAU,EAAE,CAgFvB;AAkDD;yEACyE;AACzE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE,SAAS,GAChB,IAAI,CAUN;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
package/dist/query.js CHANGED
@@ -1,4 +1,4 @@
1
- import { fieldNamed, filterOperatorFor, ID_FIELD, } from './schema.js';
1
+ import { fieldNamed, filterOperatorFor, ID_FIELD, isoToUnixSeconds, } from './schema.js';
2
2
  import { MAX_JOIN_DEPTH } from './join-graph.js';
3
3
  // The kind→operator table lives with the field model in schema.ts (one source
4
4
  // for the query IR, the surfaces, the adapters AND declaration validation);
@@ -64,7 +64,10 @@ function issueField(criterion) {
64
64
  * always-filterable {@link ID_FIELD}, which takes `in`; every requested facet is
65
65
  * a declared, `facetable` field; every sort is `relevance` or a declared field.
66
66
  * Because each criterion is matched against its own field’s kind, one clause may
67
- * range over fields of different kinds. Sorting deliberately
67
+ * range over fields of different kinds. A `date` range is checked one step
68
+ * further, on its **values**: a bound the storage codec cannot read is an
69
+ * `unparseable-bound`, the one place a criterion is rejected for what it says
70
+ * rather than for what it names. Sorting deliberately
68
71
  * checks declaration only, not the `sortable` flag: that flag means *publicly
69
72
  * selectable*, and a deployment policy may sort on a private tie-break field.
70
73
  *
@@ -143,6 +146,23 @@ export function validateQuery(query, searchType, schema, joins) {
143
146
  reason: 'operator-mismatch',
144
147
  });
145
148
  }
149
+ else if (declared.kind === 'date' && 'range' in criterion) {
150
+ // A `date` bound is ISO 8601 at the edge and Unix seconds in storage,
151
+ // so a bound the codec cannot read has nothing to compare against.
152
+ // Both bounds are checked, so a caller who wrote two bad ones is told
153
+ // about both instead of fixing one to be told about the other.
154
+ for (const bound of [criterion.range.min, criterion.range.max]) {
155
+ if (typeof bound === 'string' &&
156
+ isoToUnixSeconds(bound) === undefined) {
157
+ issues.push({
158
+ part: 'where',
159
+ field,
160
+ value: bound,
161
+ reason: 'unparseable-bound',
162
+ });
163
+ }
164
+ }
165
+ }
146
166
  }
147
167
  }
148
168
  for (const name of query.facets) {
@@ -213,7 +233,10 @@ export function assertValidQuery(query, searchType, schema, joins) {
213
233
  const issues = validateQuery(query, searchType, schema, joins);
214
234
  if (issues.length > 0) {
215
235
  const detail = issues
216
- .map((issue) => `${issue.part}: “${issue.field}” (${issue.reason})`)
236
+ .map((issue) => {
237
+ const value = issue.value === undefined ? '' : `: “${issue.value}”`;
238
+ return `${issue.part}: “${issue.field}” (${issue.reason}${value})`;
239
+ })
217
240
  .join(', ');
218
241
  throw new Error(`Invalid search query for “${searchType.name}”: ${detail}.`);
219
242
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/search",
3
- "version": "0.22.1",
3
+ "version": "0.23.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",