@lde/search 0.7.0 → 0.7.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/README.md +8 -6
- package/dist/adapter.d.ts +1 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -0
- package/dist/physical-name.d.ts +31 -0
- package/dist/physical-name.d.ts.map +1 -0
- package/dist/physical-name.js +44 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -309,18 +309,20 @@ unrepresentable; the port enforces them for everyone else (deployment
|
|
|
309
309
|
An engine is **bound to the whole `SearchSchema` at construction** – like
|
|
310
310
|
every other schema consumer (`projectGraph(quads, schema)`,
|
|
311
311
|
`buildGraphQLSchema(schema)`): the adapter factory takes the deployment’s
|
|
312
|
-
declaration
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
declaration, so a query can never meet the wrong index, and deployment-level
|
|
313
|
+
concerns (the label cache, cross-type search, facet batching) have one home.
|
|
314
|
+
Where each type physically lives is the **adapter’s** to decide – it derives a
|
|
315
|
+
collection/index name from the type, by its own engine’s naming conventions,
|
|
316
|
+
and a deployment only overrides that where it must. A search names its type per
|
|
315
317
|
call. Because `searchSchema()` captures the declared types as a literal
|
|
316
318
|
tuple, `search()` accepts **only the deployment’s own types** (a foreign type
|
|
317
319
|
is a compile error) and returns facet/document keys typed by the type passed
|
|
318
320
|
– no caller-side generics:
|
|
319
321
|
|
|
320
322
|
```ts
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
323
|
+
// No `collections`: each type reads the collection the adapter names it,
|
|
324
|
+
// which is the one its writer builds. Pass `collections` only to override.
|
|
325
|
+
const engine = createTypesenseSearchEngine(client, schema);
|
|
324
326
|
|
|
325
327
|
const result = await engine.search(DATASET, query);
|
|
326
328
|
result.facets.publisher; // typed: only DATASET’s facetable fields are keys
|
package/dist/adapter.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { assertTypeInSchema, physicalFields, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, referenceFields, fieldNamed, labelFieldOf, isRangeFacet, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export type { PhysicalFields } from './schema.js';
|
|
11
|
+
export { physicalNameTokens } from './physical-name.js';
|
|
11
12
|
export { filterOperatorFor, filterOperator, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
|
12
13
|
export type { FilterOperator, QueryIssue } from './query.js';
|
|
13
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,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,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,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,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,aAAa,EACb,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/adapter.js
CHANGED
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
* this; the main entry point carries that (small) authoring surface.
|
|
8
8
|
*/
|
|
9
9
|
export { assertTypeInSchema, physicalFields, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, referenceFields, fieldNamed, labelFieldOf, isRangeFacet, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
|
+
export { physicalNameTokens } from './physical-name.js';
|
|
10
11
|
export { filterOperatorFor, filterOperator, validateQuery, assertValidQuery, pageForOffset, } from './query.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SearchType } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* The engine-neutral word tokens an adapter formats into the physical name of a
|
|
4
|
+
* {@link SearchType}’s container – a Typesense collection, an Elasticsearch or
|
|
5
|
+
* OpenSearch index: the type’s `name` split into words, lowercased, with the
|
|
6
|
+
* last word pluralized (`CreativeWork` → `['creative', 'works']`).
|
|
7
|
+
*
|
|
8
|
+
* Both engines document the same convention – name a container after the plural
|
|
9
|
+
* of what it holds – and differ only in how they join the words: Typesense
|
|
10
|
+
* snake_case (`blog_articles`), Elasticsearch/OpenSearch kebab-case
|
|
11
|
+
* (`blog-articles`). So the split and the inflection are shared here, and only
|
|
12
|
+
* the join and the engine’s own legality rules live in the adapter – which is
|
|
13
|
+
* why this returns tokens rather than a formatted name, and why it is spelled
|
|
14
|
+
* neutrally (‘container’, not ‘collection’ or ‘index’).
|
|
15
|
+
*
|
|
16
|
+
* Acronyms stay whole (`DCATDataset` → `['dcat', 'datasets']`, `TVSeries` →
|
|
17
|
+
* `['tv', 'series']`), which is why the split is hand-rolled rather than
|
|
18
|
+
* delegated to an inflector’s `underscore`/`tableize` – those split on every
|
|
19
|
+
* capital (`t_v_series`).
|
|
20
|
+
*
|
|
21
|
+
* Pluralization is a real inflector, so irregular and invariant nouns land the
|
|
22
|
+
* way the engines’ own docs write them (`Person` → `people`, `TVSeries` →
|
|
23
|
+
* `tv_series`, `Analysis` → `analyses`) rather than as the non-words regular
|
|
24
|
+
* rules produce (`serieses`, `analysises`). An already-plural name is
|
|
25
|
+
* idempotent (`People` → `people`).
|
|
26
|
+
*
|
|
27
|
+
* Returns an empty array when `name` carries no alphanumerics at all; the
|
|
28
|
+
* adapter decides what that means, since only it knows its engine’s rules.
|
|
29
|
+
*/
|
|
30
|
+
export declare function physicalNameTokens(searchType: SearchType): readonly string[];
|
|
31
|
+
//# sourceMappingURL=physical-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physical-name.d.ts","sourceRoot":"","sources":["../src/physical-name.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE,CAK5E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { pluralize } from 'inflection';
|
|
2
|
+
/**
|
|
3
|
+
* The engine-neutral word tokens an adapter formats into the physical name of a
|
|
4
|
+
* {@link SearchType}’s container – a Typesense collection, an Elasticsearch or
|
|
5
|
+
* OpenSearch index: the type’s `name` split into words, lowercased, with the
|
|
6
|
+
* last word pluralized (`CreativeWork` → `['creative', 'works']`).
|
|
7
|
+
*
|
|
8
|
+
* Both engines document the same convention – name a container after the plural
|
|
9
|
+
* of what it holds – and differ only in how they join the words: Typesense
|
|
10
|
+
* snake_case (`blog_articles`), Elasticsearch/OpenSearch kebab-case
|
|
11
|
+
* (`blog-articles`). So the split and the inflection are shared here, and only
|
|
12
|
+
* the join and the engine’s own legality rules live in the adapter – which is
|
|
13
|
+
* why this returns tokens rather than a formatted name, and why it is spelled
|
|
14
|
+
* neutrally (‘container’, not ‘collection’ or ‘index’).
|
|
15
|
+
*
|
|
16
|
+
* Acronyms stay whole (`DCATDataset` → `['dcat', 'datasets']`, `TVSeries` →
|
|
17
|
+
* `['tv', 'series']`), which is why the split is hand-rolled rather than
|
|
18
|
+
* delegated to an inflector’s `underscore`/`tableize` – those split on every
|
|
19
|
+
* capital (`t_v_series`).
|
|
20
|
+
*
|
|
21
|
+
* Pluralization is a real inflector, so irregular and invariant nouns land the
|
|
22
|
+
* way the engines’ own docs write them (`Person` → `people`, `TVSeries` →
|
|
23
|
+
* `tv_series`, `Analysis` → `analyses`) rather than as the non-words regular
|
|
24
|
+
* rules produce (`serieses`, `analysises`). An already-plural name is
|
|
25
|
+
* idempotent (`People` → `people`).
|
|
26
|
+
*
|
|
27
|
+
* Returns an empty array when `name` carries no alphanumerics at all; the
|
|
28
|
+
* adapter decides what that means, since only it knows its engine’s rules.
|
|
29
|
+
*/
|
|
30
|
+
export function physicalNameTokens(searchType) {
|
|
31
|
+
const words = searchType.name.match(NAME_WORD_PATTERN) ?? [];
|
|
32
|
+
const tokens = words.map((word) => word.toLowerCase());
|
|
33
|
+
const last = tokens.at(-1);
|
|
34
|
+
return last === undefined ? [] : [...tokens.slice(0, -1), pluralize(last)];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* One word of a PascalCase/camelCase name, in precedence order: a run of
|
|
38
|
+
* capitals not followed by a lowercase letter (an acronym – `DCAT` in
|
|
39
|
+
* `DCATDataset`, `TV` in `TVSeries`); a capital starting an ordinary word; or a
|
|
40
|
+
* lowercase run. Anything else (a separator, punctuation) matches nothing and
|
|
41
|
+
* is dropped, so a name already written as `creative_work` or `creative-work`
|
|
42
|
+
* tokenizes the same way.
|
|
43
|
+
*/
|
|
44
|
+
const NAME_WORD_PATTERN = /[A-Z]+(?![a-z])|[A-Z][a-z0-9]*|[a-z0-9]+/g;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.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",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@lde/text-normalization": "^0.1.1",
|
|
41
41
|
"@rdfjs/types": "^2.0.1",
|
|
42
42
|
"@tpluscode/rdf-ns-builders": "^5.0.0",
|
|
43
|
+
"inflection": "^3.0.2",
|
|
43
44
|
"jsonld": "^9.0.0",
|
|
44
45
|
"tslib": "^2.3.0"
|
|
45
46
|
},
|