@lde/search-pipeline 0.26.0 → 0.26.2
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/extraction.d.ts +9 -0
- package/dist/extraction.d.ts.map +1 -1
- package/dist/extraction.js +55 -13
- package/package.json +3 -3
package/dist/extraction.d.ts
CHANGED
|
@@ -33,6 +33,15 @@ export interface ExtractionOptions {
|
|
|
33
33
|
* nested template (`{ ?root <…/ref> ?r . ?r <…/field> ?v }`), recursing into
|
|
34
34
|
* the reference type to the schema’s declared depth. The referent-binding hop
|
|
35
35
|
* uses the source `path`; the emitted triples use the minted aliases.
|
|
36
|
+
* - **`local` lookups** ({@link ReferenceStrategy.local}): a reference that also
|
|
37
|
+
* stores what this document states about its referent gets its branch
|
|
38
|
+
* extended with the **target Root Type’s own** fields, read off the referent
|
|
39
|
+
* and emitted under that type’s aliases – the same recursion an inline
|
|
40
|
+
* reference makes, through a Root Type rather than a Reference Type, and the
|
|
41
|
+
* same reach {@link inlineFramingDepth} already frames for. `OPTIONAL`, so a
|
|
42
|
+
* referent the document states nothing about keeps its row and still stores
|
|
43
|
+
* its id. It subsumes the key hop below, the key field being one of the
|
|
44
|
+
* target’s own.
|
|
36
45
|
* - **references into a keyed type**: a reference naming a target that declares
|
|
37
46
|
* a `key` gets its branch extended with an `OPTIONAL` hop reading the
|
|
38
47
|
* referent’s key field, emitted under the **target’s** alias for it – so the
|
package/dist/extraction.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EAIpB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EAIpB,MAAM,2BAA2B,CAAC;AAYnC,OAAO,KAAK,EAIV,YAAY,EACZ,UAAU,EACX,MAAM,aAAa,CAAC;AAMrB,2CAA2C;AAC3C,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,iBAAsB,GAC9B,cAAc,CAqBhB;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,MAAM,CAER"}
|
package/dist/extraction.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AstFactory, } from '@traqula/rules-sparql-1-1';
|
|
2
2
|
import { Parser } from '@traqula/parser-sparql-1-1';
|
|
3
3
|
import { Generator } from '@traqula/generator-sparql-1-1';
|
|
4
|
-
import { fieldNamed, irAlias, isInlineReference, labelSourceNameOf, referenceTypeNamed, rootTypeNamed, } from '@lde/search/adapter';
|
|
4
|
+
import { fieldNamed, irAlias, isInlineReference, labelSourceNameOf, localLookupTypeOf, referenceTypeNamed, rootTypeNamed, } from '@lde/search/adapter';
|
|
5
5
|
const factory = new AstFactory();
|
|
6
6
|
const parser = new Parser();
|
|
7
7
|
const generator = new Generator();
|
|
@@ -26,6 +26,15 @@ const generator = new Generator();
|
|
|
26
26
|
* nested template (`{ ?root <…/ref> ?r . ?r <…/field> ?v }`), recursing into
|
|
27
27
|
* the reference type to the schema’s declared depth. The referent-binding hop
|
|
28
28
|
* uses the source `path`; the emitted triples use the minted aliases.
|
|
29
|
+
* - **`local` lookups** ({@link ReferenceStrategy.local}): a reference that also
|
|
30
|
+
* stores what this document states about its referent gets its branch
|
|
31
|
+
* extended with the **target Root Type’s own** fields, read off the referent
|
|
32
|
+
* and emitted under that type’s aliases – the same recursion an inline
|
|
33
|
+
* reference makes, through a Root Type rather than a Reference Type, and the
|
|
34
|
+
* same reach {@link inlineFramingDepth} already frames for. `OPTIONAL`, so a
|
|
35
|
+
* referent the document states nothing about keeps its row and still stores
|
|
36
|
+
* its id. It subsumes the key hop below, the key field being one of the
|
|
37
|
+
* target’s own.
|
|
29
38
|
* - **references into a keyed type**: a reference naming a target that declares
|
|
30
39
|
* a `key` gets its branch extended with an `OPTIONAL` hop reading the
|
|
31
40
|
* referent’s key field, emitted under the **target’s** alias for it – so the
|
|
@@ -40,7 +49,7 @@ const generator = new Generator();
|
|
|
40
49
|
export function extractionQuery(searchType, schema, options = {}) {
|
|
41
50
|
const subjectVariable = options.subjectVariable ?? 'root';
|
|
42
51
|
const subject = factory.termVariable(subjectVariable, factory.gen());
|
|
43
|
-
const built = buildFor(searchType, subject, schema, { next: 0 });
|
|
52
|
+
const built = buildFor(searchType, subject, schema, { next: 0 }, new Set());
|
|
44
53
|
if (built.branches.length === 0) {
|
|
45
54
|
throw new Error(`Cannot generate an extraction CONSTRUCT for “${searchType.name}”: it declares no path-bearing field, so there is nothing to extract.`);
|
|
46
55
|
}
|
|
@@ -54,14 +63,22 @@ export function extractionQueryString(searchType, schema, options) {
|
|
|
54
63
|
/**
|
|
55
64
|
* Walk a type’s path-bearing fields off a subject variable, collecting the
|
|
56
65
|
* template triples (minted aliases) and one WHERE branch per field (source
|
|
57
|
-
* paths). Recurses
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
66
|
+
* paths). Recurses off a fresh referent variable for the two references that
|
|
67
|
+
* store a referent’s fields rather than only its id – an inline reference,
|
|
68
|
+
* through its Reference Type, and a {@link ReferenceStrategy.local} lookup,
|
|
69
|
+
* through its target Root Type – so the nested template keeps the
|
|
70
|
+
* `subject → referent → value` link in one CONSTRUCT.
|
|
71
|
+
*
|
|
72
|
+
* `visiting` is what terminates the second one. `searchSchema` rejects inline
|
|
73
|
+
* reference cycles, but nothing forbids two Root Types whose `local` lookups
|
|
74
|
+
* point at each other, so a type already on this path contributes no further
|
|
75
|
+
* hop – the same cut {@link inlineFramingDepth} makes, so the depth framed and
|
|
76
|
+
* the depth extracted stay the same number.
|
|
61
77
|
*/
|
|
62
|
-
function buildFor(searchType, subject, schema, counter) {
|
|
78
|
+
function buildFor(searchType, subject, schema, counter, visiting) {
|
|
63
79
|
const template = [];
|
|
64
80
|
const branches = [];
|
|
81
|
+
const onPath = new Set(visiting).add(searchType.name);
|
|
65
82
|
for (const field of searchType.fields) {
|
|
66
83
|
if (field.path === undefined) {
|
|
67
84
|
continue;
|
|
@@ -75,7 +92,7 @@ function buildFor(searchType, subject, schema, counter) {
|
|
|
75
92
|
}
|
|
76
93
|
const referent = factory.termVariable(`r${counter.next++}`, factory.gen());
|
|
77
94
|
template.push(factory.triple(subject, alias, referent));
|
|
78
|
-
const nested = buildFor(referenceType, referent, schema, counter);
|
|
95
|
+
const nested = buildFor(referenceType, referent, schema, counter, onPath);
|
|
79
96
|
template.push(...nested.template);
|
|
80
97
|
const patterns = [
|
|
81
98
|
factory.patternBgp([factory.triple(subject, sourcePath, referent)], factory.gen()),
|
|
@@ -93,17 +110,42 @@ function buildFor(searchType, subject, schema, counter) {
|
|
|
93
110
|
const patterns = [
|
|
94
111
|
factory.patternBgp([factory.triple(subject, sourcePath, value)], factory.gen()),
|
|
95
112
|
];
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
const local = localTargetOf(field, schema, onPath);
|
|
114
|
+
if (local === undefined) {
|
|
115
|
+
// Only where no local expansion follows: a `local` lookup reads the
|
|
116
|
+
// target’s every path-bearing field, and a keyed target’s key field is
|
|
117
|
+
// one of them, so emitting the hop as well would state it twice.
|
|
118
|
+
const keyed = keyedTargetOf(field, schema);
|
|
119
|
+
if (keyed !== undefined) {
|
|
120
|
+
const built = buildKeyHop(keyed.target, keyed.keyField, value, counter);
|
|
121
|
+
template.push(built.triple);
|
|
122
|
+
patterns.push(built.pattern);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const nested = buildFor(local, value, schema, counter, onPath);
|
|
127
|
+
template.push(...nested.template);
|
|
128
|
+
// `OPTIONAL`, unlike an inline reference’s conjoined nesting: this
|
|
129
|
+
// referent is stored by id whether or not the referring document says
|
|
130
|
+
// anything about it, and conjoining would drop both together.
|
|
131
|
+
if (nested.branches.length > 0) {
|
|
132
|
+
patterns.push(factory.patternOptional([factory.patternUnion(nested.branches, factory.gen())], factory.gen()));
|
|
133
|
+
}
|
|
101
134
|
}
|
|
102
135
|
branches.push(factory.patternGroup(patterns, factory.gen()));
|
|
103
136
|
}
|
|
104
137
|
}
|
|
105
138
|
return { template, branches };
|
|
106
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* The Root Type a {@link ReferenceStrategy.local} lookup expands into here, or
|
|
142
|
+
* `undefined` where the field declares none – or where that type is already on
|
|
143
|
+
* this path, which is where the recursion stops.
|
|
144
|
+
*/
|
|
145
|
+
function localTargetOf(field, schema, visiting) {
|
|
146
|
+
const local = localLookupTypeOf(field, schema);
|
|
147
|
+
return local === undefined || visiting.has(local.name) ? undefined : local;
|
|
148
|
+
}
|
|
107
149
|
/**
|
|
108
150
|
* The keyed Root Type a reference points at, with the field its key is read
|
|
109
151
|
* from: a `lookup`’s `target` or an `idOnly`’s `labelSource`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search-pipeline",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.2",
|
|
4
4
|
"description": "Search indexing as an @lde/pipeline instance: a Writer<Quad> that applies the @lde/search projection to extracted RDF and fans each document out to the transactional engine writer for its type's collection. Glue between the pipeline quad world and the search-engine document world; owns no projection or engine logic itself.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "git+https://github.com/ldelements/lde.git",
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
"!**/*.tsbuildinfo"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@lde/search": "^0.24.
|
|
28
|
+
"@lde/search": "^0.24.2",
|
|
29
29
|
"@traqula/generator-sparql-1-1": "^1.2.0",
|
|
30
30
|
"@traqula/parser-sparql-1-1": "^1.2.0",
|
|
31
31
|
"@traqula/rules-sparql-1-1": "^1.2.0",
|
|
32
32
|
"tslib": "^2.3.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@lde/search-typesense": "^0.29.
|
|
35
|
+
"@lde/search-typesense": "^0.29.2",
|
|
36
36
|
"@rdfjs/types": "^2.0.1",
|
|
37
37
|
"n3": "^2.4.0",
|
|
38
38
|
"testcontainers": "^12.1.0",
|