@lde/search 0.15.0 → 0.16.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 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, 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, labelFieldOf, isRangeFacet, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
10
10
  export type { PhysicalFields } from './schema.js';
11
11
  export { physicalNameTokens } from './physical-name.js';
12
12
  export { filterOperatorFor, filterOperator, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
@@ -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,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,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"}
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, 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, labelFieldOf, isRangeFacet, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
10
10
  export { physicalNameTokens } from './physical-name.js';
11
11
  export { filterOperatorFor, filterOperator, isUnsatisfiable, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { projectRoots } from './project.js';
2
- export type { ProjectedNode, SearchDocument } from './project.js';
2
+ export type { ProjectedNode, ProjectionContext, SearchDocument, } from './project.js';
3
3
  export { defineSearchType, searchSchema, validateSearchType, assertValidSearchType, ID_FIELD, } from './schema.js';
4
- export type { FieldKind, SearchField, SearchFieldBase, TextField, KeywordField, ReferenceField, NumericField, BooleanField, SearchType, SearchTypeBase, RootType, ReferenceType, RootTypeOf, SearchTypeIssue, SearchSchema, FacetRange, } 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';
5
5
  export type { SearchQuery, Filter, Sort } from './query.js';
6
6
  export type { SearchEngine, SearchResult, SearchHit, ResultDocument, SearchValue, LocalizedValue, Reference, NestedDocument, FacetBucket, FacetMap, FacetsOutcome, FacetFieldsOf, OutputFieldsOf, } from './engine.js';
7
7
  export type { FramedNode } from './frame-by-type.js';
@@ -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,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAKlE,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,QAAQ,GACT,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,GACX,MAAM,aAAa,CAAC;AAIrB,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAI5D,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,GACT,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;AAIrB,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAI5D,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/project.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Quad } from '@rdfjs/types';
2
2
  import { type FramedNode } from './frame-by-type.js';
3
- import { type RootType, type SearchSchema, type SearchType } from './schema.js';
3
+ import { type ProjectionValue, type RootType, type SearchSchema, type SearchType } from './schema.js';
4
4
  /**
5
5
  * A projected node: the fields of one {@link SearchType}, flat. A root always
6
6
  * carries the `id` that keys it – it is a {@link SearchDocument} – but an inline
@@ -13,6 +13,21 @@ export type ProjectedNode = Record<string, unknown>;
13
13
  export type SearchDocument = {
14
14
  id: string;
15
15
  } & ProjectedNode;
16
+ /**
17
+ * What the projection knows that the graph does not say: the values a run
18
+ * carries about the *indexing* rather than about the data. They reach a
19
+ * declaration two ways – a field declaring {@link KeywordField.from `from`} is
20
+ * populated from one, and every `derive` receives the whole context as its
21
+ * second argument, so a derive can relate a projected value to it.
22
+ *
23
+ * Empty when the caller supplies nothing: projecting a graph in isolation (a
24
+ * test, a one-off) is legitimate, and a field over an absent value is simply
25
+ * left unpopulated, exactly as a `path` that matched nothing is.
26
+ */
27
+ export interface ProjectionContext extends Partial<Readonly<Record<ProjectionValue, string>>> {
28
+ /** The IRI of the dataset being indexed. */
29
+ readonly dataset?: string;
30
+ }
16
31
  /**
17
32
  * Project one framed JSON-LD node into a flat search document: apply each field
18
33
  * of the type in declaration order. A field with a `derive` function computes
@@ -27,7 +42,7 @@ export type SearchDocument = {
27
42
  * fans out to come from {@link physicalFields}, the single source shared with
28
43
  * the engine collection definition and the query compiler.
29
44
  */
30
- export declare function projectDocument(node: FramedNode, searchType: SearchType, schema?: SearchSchema): SearchDocument;
45
+ export declare function projectDocument(node: FramedNode, searchType: SearchType, schema?: SearchSchema, context?: ProjectionContext): SearchDocument;
31
46
  /**
32
47
  * Project a single type over a known set of `roots` – the per-type, roots-given
33
48
  * projection. The roots are supplied by the caller (the pipeline selector)
@@ -41,5 +56,5 @@ export declare function projectDocument(node: FramedNode, searchType: SearchType
41
56
  * Consumes `quads` once, so it accepts any `Iterable` – a batch’s materialized
42
57
  * array or a chained generator merging several readers.
43
58
  */
44
- export declare function projectRoots(quads: Iterable<Quad>, roots: readonly string[], schema: SearchSchema, searchType: RootType): AsyncIterable<SearchDocument>;
59
+ export declare function projectRoots(quads: Iterable<Quad>, roots: readonly string[], schema: SearchSchema, searchType: RootType, context?: ProjectionContext): AsyncIterable<SearchDocument>;
45
60
  //# sourceMappingURL=project.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAYL,KAAK,QAAQ,EAEb,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,UAAU,EACtB,MAAM,CAAC,EAAE,YAAY,GACpB,cAAc,CAWhB;AAwED;;;;;;;;;;;;GAYG;AACH,wBAAuB,YAAY,CACjC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,QAAQ,GACnB,aAAa,CAAC,cAAc,CAAC,CAW/B"}
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAWL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EAEb,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAkB,SAAQ,OAAO,CAChD,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAC1C;IACC,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,UAAU,EACtB,MAAM,CAAC,EAAE,YAAY,EACrB,OAAO,GAAE,iBAAyC,GACjD,cAAc,CAgBhB;AAyED;;;;;;;;;;;;GAYG;AACH,wBAAuB,YAAY,CACjC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,QAAQ,EACpB,OAAO,GAAE,iBAAyC,GACjD,aAAa,CAAC,cAAc,CAAC,CAW/B"}
package/dist/project.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { fold } from '@lde/text-normalization';
2
2
  import { buildSubjectIndex, frameSubjects, } from './frame-by-type.js';
3
3
  import { assertTypeInSchema, displayFieldName, inlineFramingDepth, irAlias, isInternalField, isInlineReference, isoToUnixSeconds, physicalFields, referenceTypeNamed, } from './schema.js';
4
+ /** The context a projection runs with when its caller supplied none. */
5
+ const NO_PROJECTION_CONTEXT = {};
4
6
  /**
5
7
  * Project one framed JSON-LD node into a flat search document: apply each field
6
8
  * of the type in declaration order. A field with a `derive` function computes
@@ -15,13 +17,13 @@ import { assertTypeInSchema, displayFieldName, inlineFramingDepth, irAlias, isIn
15
17
  * fans out to come from {@link physicalFields}, the single source shared with
16
18
  * the engine collection definition and the query compiler.
17
19
  */
18
- export function projectDocument(node, searchType, schema) {
20
+ export function projectDocument(node, searchType, schema, context = NO_PROJECTION_CONTEXT) {
19
21
  if (documentKey(node) === undefined) {
20
22
  throw new Error(`Cannot project a “${searchType.name}” node without an @id (a blank node label is not one): every search document needs a stable key, and an empty one would collide with other keyless nodes.`);
21
23
  }
22
24
  // The guard above is what makes this a SearchDocument: projectFields sets `id`
23
25
  // for exactly the nodes documentKey resolves.
24
- const document = projectFields(node, searchType, schema);
26
+ const document = projectFields(node, searchType, schema, context);
25
27
  pruneInternalFields(document, searchType, schema);
26
28
  return document;
27
29
  }
@@ -65,11 +67,11 @@ function pruneInternalFields(document, searchType, schema) {
65
67
  * Pruning is deferred to a single recursive pass ({@link pruneInternalFields})
66
68
  * once the whole nested structure is projected, so a derive at any depth can
67
69
  * still read an internal field before it is removed. */
68
- function projectFields(node, searchType, schema) {
70
+ function projectFields(node, searchType, schema, context) {
69
71
  const id = documentKey(node);
70
72
  const document = id === undefined ? {} : { id };
71
73
  for (const field of searchType.fields) {
72
- applyField(document, node, field, searchType, schema);
74
+ applyField(document, node, field, searchType, schema, context);
73
75
  }
74
76
  return document;
75
77
  }
@@ -97,7 +99,7 @@ function documentKey(node) {
97
99
  * Consumes `quads` once, so it accepts any `Iterable` – a batch’s materialized
98
100
  * array or a chained generator merging several readers.
99
101
  */
100
- export async function* projectRoots(quads, roots, schema, searchType) {
102
+ export async function* projectRoots(quads, roots, schema, searchType, context = NO_PROJECTION_CONTEXT) {
101
103
  assertTypeInSchema(schema, searchType);
102
104
  const index = buildSubjectIndex(quads);
103
105
  // Distinct roots only. A selector may return an IRI more than once – a
@@ -106,12 +108,18 @@ export async function* projectRoots(quads, roots, schema, searchType) {
106
108
  // duplicate document under the same `id`.
107
109
  const depth = inlineFramingDepth(schema, searchType);
108
110
  for await (const node of frameSubjects(index, [...new Set(roots)], depth)) {
109
- yield projectDocument(node, searchType, schema);
111
+ yield projectDocument(node, searchType, schema, context);
110
112
  }
111
113
  }
112
- function applyField(document, node, field, searchType, schema) {
114
+ function applyField(document, node, field, searchType, schema, context) {
115
+ // The three value sources, mutually exclusive by declaration
116
+ // (`validateSearchType`): a projection value, a computed value, a graph path.
117
+ if ((field.kind === 'keyword' || field.kind === 'reference') &&
118
+ field.from !== undefined) {
119
+ return applyProjectionValue(document, field, field.from, context);
120
+ }
113
121
  if (field.derive !== undefined) {
114
- const value = field.derive(document);
122
+ const value = field.derive(document, context);
115
123
  if (value !== undefined) {
116
124
  document[field.name] = value;
117
125
  }
@@ -134,7 +142,7 @@ function applyField(document, node, field, searchType, schema) {
134
142
  // project nothing rather than fall through and emit the referent IRIs under
135
143
  // the field name (the wrong shape).
136
144
  if (schema !== undefined) {
137
- applyInlineReference(document, node, alias, field, schema);
145
+ applyInlineReference(document, node, alias, field, schema, context);
138
146
  }
139
147
  return;
140
148
  }
@@ -241,6 +249,25 @@ function applyFacet(document, raw, field) {
241
249
  setString(document, searchField, folded[0]);
242
250
  }
243
251
  }
252
+ /**
253
+ * Project a field declared over a {@link ProjectionContext} value: read the
254
+ * value the run carries and write it exactly as a graph-read one, through
255
+ * {@link applyFacet} – so `array`, `transform` and the folded `searchable`
256
+ * companion mean the same thing for a declaration over the dataset as for one
257
+ * over a path, and the collection definition needs no special case.
258
+ *
259
+ * A value the context does not carry writes nothing: a projection run outside a
260
+ * pipeline (a test, a one-off) leaves the field absent rather than inventing a
261
+ * placeholder, the same as a `path` that matched nothing.
262
+ */
263
+ function applyProjectionValue(document, field, from, context) {
264
+ // `ProjectionContext` is keyed by `ProjectionValue`, so the declaration reads
265
+ // the context directly: a projection value that has no context key, or a
266
+ // context key no declaration can name, is a compile error rather than a
267
+ // silently unpopulated field.
268
+ const value = context[from];
269
+ applyFacet(document, value === undefined ? [] : [value], field);
270
+ }
244
271
  /**
245
272
  * Project an inline reference: the referent node(s) embedded under the field’s
246
273
  * {@link irAlias IR Alias} are each projected through the reference’s
@@ -258,7 +285,7 @@ function applyFacet(document, raw, field) {
258
285
  * the schema’s declared depth. The referent type is guaranteed declared by
259
286
  * {@link searchSchema}.
260
287
  */
261
- function applyInlineReference(document, node, alias, field, schema) {
288
+ function applyInlineReference(document, node, alias, field, schema, context) {
262
289
  // Resolves for a schema that declares the referent (always so for the schema a
263
290
  // type is projected through); a type framed against a foreign schema that
264
291
  // omits it simply contributes no nesting.
@@ -268,7 +295,7 @@ function applyInlineReference(document, node, alias, field, schema) {
268
295
  }
269
296
  const referents = valuesOf(node, alias)
270
297
  .filter(isObject)
271
- .map((referent) => projectFields(referent, referenceType, schema))
298
+ .map((referent) => projectFields(referent, referenceType, schema, context))
272
299
  // Fields, not identity, are what makes something a referent: a literal
273
300
  // value object under the alias (dirty source data), or a node this
274
301
  // reference type reads nothing from, projects nothing and is no referent.
package/dist/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ProjectedNode } from './project.js';
1
+ import type { ProjectedNode, ProjectionContext } from './project.js';
2
2
  /**
3
3
  * The engine-neutral kind of a queryable field. It drives every downstream
4
4
  * behavior: which physical fields the projection emits, the engine
@@ -33,9 +33,13 @@ export declare function filterOperatorFor(kind: FieldKind): FilterOperator | und
33
33
  * field with a {@link SearchFieldBase.derive `derive`} function instead of a
34
34
  * `path` is a **derived field** – computed from the document projected so far
35
35
  * rather than read from the graph – yet it still carries full query/schema/output
36
- * behavior (e.g. `status`, the compatibility booleans). A field declaring **no**
37
- * role at all is an {@link isInternalField **internal field**}: projected so a
38
- * later derive can read it, then pruned before the writer.
36
+ * behavior (e.g. `status`, the compatibility booleans). A `keyword`/`reference`
37
+ * field may instead declare {@link KeywordField.from `from`}, populating it from
38
+ * a {@link ProjectionValue} – something the run knows and the graph does not.
39
+ * `path`, `derive` and `from` are the three mutually exclusive value sources. A
40
+ * field declaring **no** role at all is an {@link isInternalField **internal
41
+ * field**}: projected so a later derive can read it, then pruned before the
42
+ * writer.
39
43
  *
40
44
  * The physical field names a declaration fans out to (per-locale search/sort
41
45
  * keys) follow one convention, owned by
@@ -89,9 +93,30 @@ export interface SearchFieldBase {
89
93
  * is the search document for a root type, and the referent’s own
90
94
  * projected fields for a Reference Type – which carry an `id` only when the
91
95
  * referent is a named node, never for a blank-node one.
96
+ *
97
+ * The second argument is the {@link ProjectionContext} – the run’s
98
+ * projection-time values, which are about the *indexing*, not the graph (the
99
+ * dataset being indexed). It is what lets a derive relate a projected value
100
+ * to its provenance: dropping a polymorphic `isPartOf` value that merely
101
+ * points back at the containing dataset, say.
92
102
  */
93
- readonly derive?: (document: ProjectedNode) => unknown;
103
+ readonly derive?: (document: ProjectedNode, context: ProjectionContext) => unknown;
94
104
  }
105
+ /**
106
+ * A projection-time value a field can be declared **over** – something the run
107
+ * knows that the graph does not say. `dataset` is the IRI of the dataset being
108
+ * indexed: every indexed document comes from exactly one, and for the many
109
+ * entity types that carry no containing-collection property (`Person`,
110
+ * `Organization`, `Place`, …) it is the only available answer to *which dataset
111
+ * does this come from*.
112
+ *
113
+ * A field declaring one is populated by the projection, like a `path`-bearing
114
+ * or `derive`d field, and carries the full range of behaviour: `output`,
115
+ * `filterable`, `facetable`, and – for a `reference` – a
116
+ * {@link ReferenceField.labelSource `labelSource`} that resolves the IRI to a
117
+ * readable label at query time.
118
+ */
119
+ export type ProjectionValue = 'dataset';
95
120
  /** Full-text inclusion with a `query_by` weight (folded; per-locale for
96
121
  * localized text). Presence is what makes a field searchable. */
97
122
  export interface Searchable {
@@ -127,6 +152,9 @@ export interface KeywordField extends SearchFieldBase, Searchable {
127
152
  /** Projection-time value transform (e.g. strip a media-type prefix). */
128
153
  readonly transform?: (value: string) => string;
129
154
  readonly facetRanges?: never;
155
+ /** Populate from a {@link ProjectionValue} instead of the graph. Mutually
156
+ * exclusive with `path` and `derive`. */
157
+ readonly from?: ProjectionValue;
130
158
  }
131
159
  /** An IRI-valued reference to another entity, label-resolved at the surface. */
132
160
  export interface ReferenceField extends SearchFieldBase, Searchable {
@@ -134,6 +162,11 @@ export interface ReferenceField extends SearchFieldBase, Searchable {
134
162
  /** Projection-time value transform. */
135
163
  readonly transform?: (value: string) => string;
136
164
  readonly facetRanges?: never;
165
+ /** Populate from a {@link ProjectionValue} instead of the graph – a
166
+ * `dataset` reference is how a type declares the dataset it was indexed
167
+ * from, resolvable to a label like any other reference. Mutually exclusive
168
+ * with `path` and `derive`. */
169
+ readonly from?: ProjectionValue;
137
170
  /**
138
171
  * The `name` of the {@link SearchType} whose collection resolves this
139
172
  * reference’s labels – its ‘label source’. The named type must declare an
@@ -375,7 +408,7 @@ export declare function labelFieldOf(searchType: SearchType): TextField | undefi
375
408
  */
376
409
  export interface SearchTypeIssue {
377
410
  readonly field: string;
378
- readonly reason: 'duplicate-field-name' | 'invalid-field-name' | 'unknown-kind' | 'invalid-locale' | 'missing-ref' | 'ref-not-allowed' | 'text-requires-locales' | 'locales-not-allowed' | 'facet-ranges-not-allowed' | 'searchable-not-allowed' | 'transform-not-allowed' | 'derive-with-path' | 'text-not-filterable' | 'text-not-facetable' | 'reserved-field-name';
411
+ readonly reason: 'duplicate-field-name' | 'invalid-field-name' | 'unknown-kind' | 'invalid-locale' | 'missing-ref' | 'ref-not-allowed' | 'text-requires-locales' | 'locales-not-allowed' | 'facet-ranges-not-allowed' | 'searchable-not-allowed' | 'transform-not-allowed' | 'derive-with-path' | 'from-not-allowed' | 'from-with-path' | 'from-with-derive' | 'from-with-inline-ref' | 'unknown-projection-value' | 'duplicate-projection-value' | 'text-not-filterable' | 'text-not-facetable' | 'reserved-field-name';
379
412
  }
380
413
  /**
381
414
  * The reserved logical name of a document’s IRI – the one field every indexed
@@ -414,7 +447,13 @@ export declare const ID_FIELD = "id";
414
447
  * - `transform` only on `keyword`/`reference` (the only kinds whose
415
448
  * projection applies it);
416
449
  * - `derive` and `path` are mutually exclusive (a field is projected or
417
- * computed, never both).
450
+ * computed, never both);
451
+ * - `from` names a known {@link ProjectionValue}, sits on a `keyword`/`reference`
452
+ * field, excludes `path` and `derive` (the three are the value sources, and a
453
+ * field has exactly one), is not an `inline` reference (a projection value is
454
+ * a bare IRI, with no referent to carry fields from), and no two fields
455
+ * declare the same projection value – which would leave a consumer reading
456
+ * the dataset off a declaration no rule picks between.
418
457
  *
419
458
  * Pure and total: returns every issue rather than throwing;
420
459
  * {@link assertValidSearchType} is the throwing entry point.
@@ -514,6 +553,18 @@ export declare function outputFields(searchType: SearchType): readonly SearchFie
514
553
  export declare function isInternalField(field: SearchField): boolean;
515
554
  /** Fields of kind `reference` (IRI-valued, label-resolved), in declaration order. */
516
555
  export declare function referenceFields(searchType: SearchType): readonly ReferenceField[];
556
+ /**
557
+ * The field a type declares over the dataset being indexed
558
+ * ({@link ProjectionValue `from: 'dataset'`}), if it declares one.
559
+ * {@link validateSearchType} rejects a second field over the same projection
560
+ * value, so for any type that reached a {@link SearchSchema} this is the only
561
+ * such field rather than the first of several.
562
+ *
563
+ * The single lookup every consumer of the declaration shares – the projection
564
+ * that populates it, and the engine writer that keeps its provenance
565
+ * bookkeeping on it rather than on a private field of its own.
566
+ */
567
+ export declare function datasetField(searchType: SearchType): (KeywordField | ReferenceField) | undefined;
517
568
  /** Look up a field by its logical name. */
518
569
  export declare function fieldNamed(searchType: SearchType, name: string): SearchField | undefined;
519
570
  /**
@@ -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
@@ -316,6 +316,15 @@ export const ID_FIELD = 'id';
316
316
  const SEARCHABLE_KINDS = ['text', 'keyword', 'reference'];
317
317
  /** Kinds whose projection applies the {@link KeywordField.transform}. */
318
318
  const TRANSFORMABLE_KINDS = ['keyword', 'reference'];
319
+ /**
320
+ * Kinds a {@link ProjectionValue} can populate: every projection value is an
321
+ * IRI or a token, so only the two string-shaped kinds can hold one. `reference`
322
+ * is what carries a {@link ReferenceField.labelSource}, and so the kind a
323
+ * facet over the dataset wants.
324
+ */
325
+ const FROM_KINDS = ['keyword', 'reference'];
326
+ /** The {@link ProjectionValue}s a declaration may name. */
327
+ const PROJECTION_VALUES = ['dataset'];
319
328
  /**
320
329
  * A safe logical field name: a GraphQL-style identifier. The name is
321
330
  * interpolated raw into physical field names AND, for a display text field,
@@ -356,7 +365,13 @@ const LOCALE_PATTERN = /^[A-Za-z0-9]+(-[A-Za-z0-9]+)*$/;
356
365
  * - `transform` only on `keyword`/`reference` (the only kinds whose
357
366
  * projection applies it);
358
367
  * - `derive` and `path` are mutually exclusive (a field is projected or
359
- * computed, never both).
368
+ * computed, never both);
369
+ * - `from` names a known {@link ProjectionValue}, sits on a `keyword`/`reference`
370
+ * field, excludes `path` and `derive` (the three are the value sources, and a
371
+ * field has exactly one), is not an `inline` reference (a projection value is
372
+ * a bare IRI, with no referent to carry fields from), and no two fields
373
+ * declare the same projection value – which would leave a consumer reading
374
+ * the dataset off a declaration no rule picks between.
360
375
  *
361
376
  * Pure and total: returns every issue rather than throwing;
362
377
  * {@link assertValidSearchType} is the throwing entry point.
@@ -364,6 +379,7 @@ const LOCALE_PATTERN = /^[A-Za-z0-9]+(-[A-Za-z0-9]+)*$/;
364
379
  export function validateSearchType(searchType) {
365
380
  const issues = [];
366
381
  const seen = new Set();
382
+ const seenProjectionValues = new Set();
367
383
  for (const declared of searchType.fields) {
368
384
  // Validation guards declarations built OUTSIDE TypeScript (a SHACL
369
385
  // generator, plain JS), so it inspects the uniform flat shape rather
@@ -439,6 +455,35 @@ export function validateSearchType(searchType) {
439
455
  if (field.derive !== undefined && field.path !== undefined) {
440
456
  issue('derive-with-path');
441
457
  }
458
+ if (field.from !== undefined) {
459
+ if (!PROJECTION_VALUES.includes(field.from)) {
460
+ issue('unknown-projection-value');
461
+ }
462
+ else if (seenProjectionValues.has(field.from)) {
463
+ // Two fields over one projection value leaves every consumer that
464
+ // resolves the value back to a declaration – the writer’s provenance
465
+ // field, above all – with no rule to pick between them.
466
+ issue('duplicate-projection-value');
467
+ }
468
+ seenProjectionValues.add(field.from);
469
+ if (!FROM_KINDS.includes(field.kind)) {
470
+ issue('from-not-allowed');
471
+ }
472
+ if (field.path !== undefined) {
473
+ issue('from-with-path');
474
+ }
475
+ if (field.derive !== undefined) {
476
+ issue('from-with-derive');
477
+ }
478
+ // An inline reference carries a referent’s projected fields, and the
479
+ // collection definition declares it as a nested object. A projection
480
+ // value has no referent – it is a bare IRI – so the two together would
481
+ // declare an object field the projection fills with a string, and every
482
+ // document import would fail.
483
+ if (field.ref?.strategy === 'inline') {
484
+ issue('from-with-inline-ref');
485
+ }
486
+ }
442
487
  }
443
488
  return issues;
444
489
  }
@@ -565,6 +610,21 @@ export function isInternalField(field) {
565
610
  export function referenceFields(searchType) {
566
611
  return searchType.fields.filter((field) => field.kind === 'reference');
567
612
  }
613
+ /**
614
+ * The field a type declares over the dataset being indexed
615
+ * ({@link ProjectionValue `from: 'dataset'`}), if it declares one.
616
+ * {@link validateSearchType} rejects a second field over the same projection
617
+ * value, so for any type that reached a {@link SearchSchema} this is the only
618
+ * such field rather than the first of several.
619
+ *
620
+ * The single lookup every consumer of the declaration shares – the projection
621
+ * that populates it, and the engine writer that keeps its provenance
622
+ * bookkeeping on it rather than on a private field of its own.
623
+ */
624
+ export function datasetField(searchType) {
625
+ return searchType.fields.find((field) => (field.kind === 'keyword' || field.kind === 'reference') &&
626
+ field.from === 'dataset');
627
+ }
568
628
  /** Look up a field by its logical name. */
569
629
  export function fieldNamed(searchType, name) {
570
630
  return searchType.fields.find((field) => field.name === name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/search",
3
- "version": "0.15.0",
3
+ "version": "0.16.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",
@@ -52,7 +52,7 @@
52
52
  "devDependencies": {
53
53
  "@tpluscode/rdf-ns-builders": "^5.0.0",
54
54
  "@types/jsonld": "^1.5.15",
55
- "n3": "^2.1.1"
55
+ "n3": "^2.1.2"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "vitest": "^4.0.0"