ochre-sdk 1.0.13 → 1.0.15
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/constants.d.mts +17 -0
- package/dist/constants.mjs +85 -0
- package/dist/fetchers/gallery.d.mts +38 -0
- package/dist/fetchers/gallery.mjs +91 -0
- package/dist/fetchers/item-links.d.mts +32 -0
- package/dist/fetchers/item-links.mjs +120 -0
- package/dist/fetchers/item.d.mts +74 -0
- package/dist/fetchers/item.mjs +146 -0
- package/dist/fetchers/set/items.d.mts +48 -0
- package/dist/fetchers/set/items.mjs +268 -0
- package/dist/fetchers/set/property-values.d.mts +46 -0
- package/dist/fetchers/set/property-values.mjs +514 -0
- package/dist/fetchers/website.d.mts +25 -0
- package/dist/fetchers/website.mjs +38 -0
- package/dist/getters.d.mts +193 -0
- package/dist/getters.mjs +341 -0
- package/dist/helpers.d.mts +18 -0
- package/dist/helpers.mjs +33 -0
- package/dist/index.d.mts +12 -1971
- package/dist/index.mjs +9 -7236
- package/dist/parsers/helpers.d.mts +27 -0
- package/dist/parsers/helpers.mjs +53 -0
- package/dist/parsers/index.d.mts +65 -0
- package/dist/parsers/index.mjs +1338 -0
- package/dist/parsers/mdx.d.mts +4 -0
- package/dist/parsers/mdx.mjs +9 -0
- package/dist/parsers/multilingual.d.mts +189 -0
- package/dist/parsers/multilingual.mjs +410 -0
- package/dist/parsers/string.d.mts +29 -0
- package/dist/parsers/string.mjs +445 -0
- package/dist/parsers/website/index.d.mts +20 -0
- package/dist/parsers/website/index.mjs +1245 -0
- package/dist/parsers/website/reader.d.mts +29 -0
- package/dist/parsers/website/reader.mjs +75 -0
- package/dist/query.d.mts +13 -0
- package/dist/query.mjs +827 -0
- package/dist/schemas.d.mts +79 -0
- package/dist/schemas.mjs +223 -0
- package/dist/types/index.d.mts +840 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/website.d.mts +501 -0
- package/dist/types/website.mjs +1 -0
- package/dist/utils.d.mts +34 -0
- package/dist/utils.mjs +172 -0
- package/dist/xml/metadata.d.mts +5 -0
- package/dist/xml/metadata.mjs +30 -0
- package/dist/xml/schemas.d.mts +13 -0
- package/dist/xml/schemas.mjs +849 -0
- package/dist/xml/types.d.mts +901 -0
- package/dist/xml/types.mjs +1 -0
- package/package.json +19 -17
package/dist/query.mjs
ADDED
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
import { stringLiteral } from "./utils.mjs";
|
|
2
|
+
//#region src/query.ts
|
|
3
|
+
const CTS_INCLUDES_STOP_WORDS = new Set([
|
|
4
|
+
"and",
|
|
5
|
+
"at",
|
|
6
|
+
"in",
|
|
7
|
+
"it",
|
|
8
|
+
"of",
|
|
9
|
+
"the",
|
|
10
|
+
"to"
|
|
11
|
+
]);
|
|
12
|
+
const CTS_INCLUDES_TOKEN_WORD_REGEX = /^\p{L}+$/u;
|
|
13
|
+
const CTS_INCLUDES_TOKEN_REGEX = /[\p{L}\p{N}*?]+/gu;
|
|
14
|
+
const CTS_EXACT_TEXT_TOKEN_REGEX = /[\p{L}\p{N}]+/gu;
|
|
15
|
+
const CONTENT_TARGET_CONTENT_ELEMENT_PATHS = {
|
|
16
|
+
title: [
|
|
17
|
+
"identification",
|
|
18
|
+
"label",
|
|
19
|
+
"content"
|
|
20
|
+
],
|
|
21
|
+
description: ["description", "content"],
|
|
22
|
+
image: [
|
|
23
|
+
"image",
|
|
24
|
+
"identification",
|
|
25
|
+
"label",
|
|
26
|
+
"content"
|
|
27
|
+
],
|
|
28
|
+
periods: [
|
|
29
|
+
"periods",
|
|
30
|
+
"period",
|
|
31
|
+
"identification",
|
|
32
|
+
"label",
|
|
33
|
+
"content"
|
|
34
|
+
],
|
|
35
|
+
bibliography: [
|
|
36
|
+
"bibliographies",
|
|
37
|
+
"bibliography",
|
|
38
|
+
"identification",
|
|
39
|
+
"label",
|
|
40
|
+
"content"
|
|
41
|
+
]
|
|
42
|
+
};
|
|
43
|
+
function tokenizeIncludesSearchValue(params) {
|
|
44
|
+
const { value, isCaseSensitive } = params;
|
|
45
|
+
const rawTerms = (isCaseSensitive ? value : value.toLowerCase()).match(CTS_INCLUDES_TOKEN_REGEX) ?? [];
|
|
46
|
+
const terms = [];
|
|
47
|
+
for (const term of rawTerms) {
|
|
48
|
+
if (term.includes("*") || term.includes("?")) {
|
|
49
|
+
if (term.replaceAll("*", "").replaceAll("?", "") !== "") terms.push(term);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const normalizedTerm = term.toLowerCase();
|
|
53
|
+
if (normalizedTerm !== "" && !CTS_INCLUDES_STOP_WORDS.has(normalizedTerm)) terms.push(term);
|
|
54
|
+
}
|
|
55
|
+
return terms;
|
|
56
|
+
}
|
|
57
|
+
function tokenizeExactTextSearchValue(params) {
|
|
58
|
+
const { value, isCaseSensitive } = params;
|
|
59
|
+
const rawTerms = (isCaseSensitive ? value : value.toLowerCase()).match(CTS_EXACT_TEXT_TOKEN_REGEX) ?? [];
|
|
60
|
+
const terms = [];
|
|
61
|
+
for (const term of rawTerms) if (term !== "") terms.push(term);
|
|
62
|
+
return terms;
|
|
63
|
+
}
|
|
64
|
+
function hasWildcardCharacters(value) {
|
|
65
|
+
return value.includes("*") || value.includes("?");
|
|
66
|
+
}
|
|
67
|
+
function getWildcardStrippedValue(value) {
|
|
68
|
+
return value.replaceAll("*", "").replaceAll("?", "");
|
|
69
|
+
}
|
|
70
|
+
function shouldUseStemmedTextSearch(value) {
|
|
71
|
+
const wildcardStrippedValue = getWildcardStrippedValue(value);
|
|
72
|
+
return wildcardStrippedValue.length >= 3 && CTS_INCLUDES_TOKEN_WORD_REGEX.test(wildcardStrippedValue);
|
|
73
|
+
}
|
|
74
|
+
function shouldUseFullValueFallbackForIncludes(params) {
|
|
75
|
+
const { value, isCaseSensitive, terms } = params;
|
|
76
|
+
if (terms.length <= 1) return false;
|
|
77
|
+
const tokenSource = isCaseSensitive ? value : value.toLowerCase();
|
|
78
|
+
if (/[^\p{L}\p{N}\s*?]/u.test(tokenSource)) return true;
|
|
79
|
+
const rawSpaceTerms = tokenSource.trim().split(/\s+/u).filter(Boolean);
|
|
80
|
+
if (rawSpaceTerms.length !== terms.length) return true;
|
|
81
|
+
for (const rawTerm of rawSpaceTerms) {
|
|
82
|
+
const wildcardStrippedTerm = getWildcardStrippedValue(rawTerm);
|
|
83
|
+
if (hasWildcardCharacters(rawTerm)) return true;
|
|
84
|
+
if (!CTS_INCLUDES_TOKEN_WORD_REGEX.test(wildcardStrippedTerm)) return true;
|
|
85
|
+
if (CTS_INCLUDES_STOP_WORDS.has(rawTerm.toLowerCase())) return true;
|
|
86
|
+
}
|
|
87
|
+
for (const [index, rawTerm] of rawSpaceTerms.entries()) if (rawTerm !== (terms[index] ?? "")) return true;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
function buildWordQueryOptionsExpression(params) {
|
|
91
|
+
const { matchMode, isCaseSensitive, queryFamily, language, isWildcarded } = params;
|
|
92
|
+
const { isStemmed } = params;
|
|
93
|
+
const options = [
|
|
94
|
+
isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
95
|
+
matchMode === "exact" ? "diacritic-sensitive" : "diacritic-insensitive",
|
|
96
|
+
matchMode === "exact" ? "punctuation-sensitive" : "punctuation-insensitive",
|
|
97
|
+
matchMode === "exact" ? "whitespace-sensitive" : "whitespace-insensitive"
|
|
98
|
+
];
|
|
99
|
+
if (matchMode === "exact") options.push("unstemmed", "unwildcarded");
|
|
100
|
+
else if (queryFamily === "text") {
|
|
101
|
+
options.push(isStemmed ? "stemmed" : "unstemmed", isWildcarded ? "wildcarded" : "unwildcarded");
|
|
102
|
+
if (isStemmed && language != null && language !== "") options.push(`lang=${language}`);
|
|
103
|
+
}
|
|
104
|
+
return `(${options.map((option) => stringLiteral(option)).join(", ")})`;
|
|
105
|
+
}
|
|
106
|
+
function buildRichTextPhraseOptionsExpression(params) {
|
|
107
|
+
const { isCaseSensitive } = params;
|
|
108
|
+
return `(${[
|
|
109
|
+
isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
110
|
+
"diacritic-sensitive",
|
|
111
|
+
"punctuation-insensitive",
|
|
112
|
+
"whitespace-insensitive",
|
|
113
|
+
"unstemmed",
|
|
114
|
+
"unwildcarded"
|
|
115
|
+
].map((option) => stringLiteral(option)).join(", ")})`;
|
|
116
|
+
}
|
|
117
|
+
function buildCtsWordQueryExpression(params) {
|
|
118
|
+
const { value, matchMode, isCaseSensitive, queryFamily, language } = params;
|
|
119
|
+
const isWildcarded = matchMode === "includes" && hasWildcardCharacters(value);
|
|
120
|
+
const isStemmed = matchMode === "includes" && queryFamily === "text" && !isWildcarded && shouldUseStemmedTextSearch(value);
|
|
121
|
+
return `cts:word-query(${stringLiteral(value)}, ${buildWordQueryOptionsExpression({
|
|
122
|
+
matchMode,
|
|
123
|
+
isCaseSensitive,
|
|
124
|
+
queryFamily,
|
|
125
|
+
language,
|
|
126
|
+
isWildcarded,
|
|
127
|
+
isStemmed
|
|
128
|
+
})})`;
|
|
129
|
+
}
|
|
130
|
+
function buildRichTextPhraseQueryExpression(params) {
|
|
131
|
+
const { value, isCaseSensitive } = params;
|
|
132
|
+
return `cts:word-query(${stringLiteral(value)}, ${buildRichTextPhraseOptionsExpression({ isCaseSensitive })})`;
|
|
133
|
+
}
|
|
134
|
+
function buildRichTextExactQueryExpression(params) {
|
|
135
|
+
const { value, isCaseSensitive } = params;
|
|
136
|
+
const phraseQuery = buildRichTextPhraseQueryExpression({
|
|
137
|
+
value,
|
|
138
|
+
isCaseSensitive
|
|
139
|
+
});
|
|
140
|
+
const terms = tokenizeExactTextSearchValue({
|
|
141
|
+
value,
|
|
142
|
+
isCaseSensitive
|
|
143
|
+
});
|
|
144
|
+
if (terms.length <= 1) return phraseQuery;
|
|
145
|
+
return buildOrCtsQueryExpressionInternal([phraseQuery, buildAndCtsQueryExpressionInternal(terms.map((term) => buildRichTextPhraseQueryExpression({
|
|
146
|
+
value: term,
|
|
147
|
+
isCaseSensitive
|
|
148
|
+
})))]);
|
|
149
|
+
}
|
|
150
|
+
function buildCtsElementWordQueryExpression(params) {
|
|
151
|
+
const { elementName, value, matchMode, isCaseSensitive, queryFamily, language } = params;
|
|
152
|
+
const isWildcarded = matchMode === "includes" && hasWildcardCharacters(value);
|
|
153
|
+
const isStemmed = matchMode === "includes" && queryFamily === "text" && !isWildcarded && shouldUseStemmedTextSearch(value);
|
|
154
|
+
return `cts:element-word-query(xs:QName("${elementName}"), ${stringLiteral(value)}, ${buildWordQueryOptionsExpression({
|
|
155
|
+
matchMode,
|
|
156
|
+
isCaseSensitive,
|
|
157
|
+
queryFamily,
|
|
158
|
+
language,
|
|
159
|
+
isWildcarded,
|
|
160
|
+
isStemmed
|
|
161
|
+
})})`;
|
|
162
|
+
}
|
|
163
|
+
function buildCtsElementAttributeWordQueryExpression(params) {
|
|
164
|
+
const { elementName, attributeName, value, matchMode, isCaseSensitive, queryFamily, language } = params;
|
|
165
|
+
const isWildcarded = matchMode === "includes" && hasWildcardCharacters(value);
|
|
166
|
+
const isStemmed = matchMode === "includes" && queryFamily === "text" && !isWildcarded && shouldUseStemmedTextSearch(value);
|
|
167
|
+
return `cts:element-attribute-word-query(xs:QName("${elementName}"), xs:QName("${attributeName}"), ${stringLiteral(value)}, ${buildWordQueryOptionsExpression({
|
|
168
|
+
matchMode,
|
|
169
|
+
isCaseSensitive,
|
|
170
|
+
queryFamily,
|
|
171
|
+
language,
|
|
172
|
+
isWildcarded,
|
|
173
|
+
isStemmed
|
|
174
|
+
})})`;
|
|
175
|
+
}
|
|
176
|
+
function buildCtsElementValueQueryExpression(params) {
|
|
177
|
+
const { elementName, value, isCaseSensitive } = params;
|
|
178
|
+
return `cts:element-value-query(xs:QName("${elementName}"), ${stringLiteral(value)}, ${buildWordQueryOptionsExpression({
|
|
179
|
+
matchMode: "exact",
|
|
180
|
+
isCaseSensitive
|
|
181
|
+
})})`;
|
|
182
|
+
}
|
|
183
|
+
function buildCtsElementAttributeValueQueryExpression(params) {
|
|
184
|
+
const { elementName, attributeName, value, isCaseSensitive } = params;
|
|
185
|
+
return `cts:element-attribute-value-query(xs:QName("${elementName}"), xs:QName("${attributeName}"), ${stringLiteral(value)}, ${buildWordQueryOptionsExpression({
|
|
186
|
+
matchMode: "exact",
|
|
187
|
+
isCaseSensitive
|
|
188
|
+
})})`;
|
|
189
|
+
}
|
|
190
|
+
function buildPlainElementAttributeValueQueryExpression(params) {
|
|
191
|
+
const { elementName, attributeName, value } = params;
|
|
192
|
+
return `cts:element-attribute-value-query(xs:QName("${elementName}"), xs:QName("${attributeName}"), ${stringLiteral(value)})`;
|
|
193
|
+
}
|
|
194
|
+
function buildNestedElementQuery(elementNames, queryExpression) {
|
|
195
|
+
let wrappedQueryExpression = queryExpression;
|
|
196
|
+
for (const elementName of elementNames.toReversed()) wrappedQueryExpression = `cts:element-query(xs:QName("${elementName}"), ${wrappedQueryExpression})`;
|
|
197
|
+
return wrappedQueryExpression;
|
|
198
|
+
}
|
|
199
|
+
function buildNotCtsQueryExpression(queryExpression) {
|
|
200
|
+
return `cts:not-query(${queryExpression})`;
|
|
201
|
+
}
|
|
202
|
+
function buildAndCtsQueryExpressionInternal(queryExpressions) {
|
|
203
|
+
if (queryExpressions.length === 0) return "cts:true-query()";
|
|
204
|
+
if (queryExpressions.length === 1) return queryExpressions[0] ?? "cts:true-query()";
|
|
205
|
+
return `cts:and-query((${queryExpressions.join(", ")}))`;
|
|
206
|
+
}
|
|
207
|
+
function buildOrCtsQueryExpressionInternal(queryExpressions) {
|
|
208
|
+
if (queryExpressions.length === 0) return "cts:false-query()";
|
|
209
|
+
if (queryExpressions.length === 1) return queryExpressions[0] ?? "cts:false-query()";
|
|
210
|
+
return `cts:or-query((${queryExpressions.join(", ")}))`;
|
|
211
|
+
}
|
|
212
|
+
function buildAndCtsQueryExpression(queryExpressions) {
|
|
213
|
+
if (queryExpressions.length === 0) return null;
|
|
214
|
+
return buildAndCtsQueryExpressionInternal(queryExpressions);
|
|
215
|
+
}
|
|
216
|
+
function buildContentLanguageQuery(language) {
|
|
217
|
+
return buildPlainElementAttributeValueQueryExpression({
|
|
218
|
+
elementName: "content",
|
|
219
|
+
attributeName: "xml:lang",
|
|
220
|
+
value: language
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function buildPropertyLabelQuery(propertyVariable) {
|
|
224
|
+
return buildPlainElementAttributeValueQueryExpression({
|
|
225
|
+
elementName: "label",
|
|
226
|
+
attributeName: "uuid",
|
|
227
|
+
value: propertyVariable
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function buildValueNotInheritedQuery() {
|
|
231
|
+
return buildNotCtsQueryExpression(buildPlainElementAttributeValueQueryExpression({
|
|
232
|
+
elementName: "value",
|
|
233
|
+
attributeName: "inherited",
|
|
234
|
+
value: "true"
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
function buildValueNotIdRefQuery() {
|
|
238
|
+
return buildNotCtsQueryExpression(buildPlainElementAttributeValueQueryExpression({
|
|
239
|
+
elementName: "value",
|
|
240
|
+
attributeName: "dataType",
|
|
241
|
+
value: "IDREF"
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
function buildRichTextContentQueryExpression(params) {
|
|
245
|
+
const { value, matchMode, isCaseSensitive, language } = params;
|
|
246
|
+
return buildAndCtsQueryExpressionInternal([buildContentLanguageQuery(language), matchMode === "exact" ? buildRichTextExactQueryExpression({
|
|
247
|
+
value,
|
|
248
|
+
isCaseSensitive,
|
|
249
|
+
language
|
|
250
|
+
}) : buildCtsWordQueryExpression({
|
|
251
|
+
value,
|
|
252
|
+
matchMode,
|
|
253
|
+
isCaseSensitive,
|
|
254
|
+
queryFamily: "text",
|
|
255
|
+
language
|
|
256
|
+
})]);
|
|
257
|
+
}
|
|
258
|
+
function buildValueContentInnerQuery(params) {
|
|
259
|
+
const { language, value, matchMode, isCaseSensitive } = params;
|
|
260
|
+
return buildNestedElementQuery(["content"], buildRichTextContentQueryExpression({
|
|
261
|
+
language,
|
|
262
|
+
value,
|
|
263
|
+
matchMode,
|
|
264
|
+
isCaseSensitive
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
267
|
+
function buildValueDirectTextInnerQuery(params) {
|
|
268
|
+
const { value, matchMode, isCaseSensitive } = params;
|
|
269
|
+
const directTextQuery = matchMode === "exact" ? buildCtsElementValueQueryExpression({
|
|
270
|
+
elementName: "value",
|
|
271
|
+
value,
|
|
272
|
+
isCaseSensitive
|
|
273
|
+
}) : buildCtsElementWordQueryExpression({
|
|
274
|
+
elementName: "value",
|
|
275
|
+
value,
|
|
276
|
+
matchMode,
|
|
277
|
+
isCaseSensitive,
|
|
278
|
+
queryFamily: "raw"
|
|
279
|
+
});
|
|
280
|
+
return buildAndCtsQueryExpressionInternal([buildNotCtsQueryExpression(buildNestedElementQuery(["content"], "cts:true-query()")), directTextQuery]);
|
|
281
|
+
}
|
|
282
|
+
function buildValueRawValueInnerQuery(params) {
|
|
283
|
+
const { value, matchMode, isCaseSensitive } = params;
|
|
284
|
+
if (matchMode === "exact") return buildCtsElementAttributeValueQueryExpression({
|
|
285
|
+
elementName: "value",
|
|
286
|
+
attributeName: "rawValue",
|
|
287
|
+
value,
|
|
288
|
+
isCaseSensitive
|
|
289
|
+
});
|
|
290
|
+
return buildCtsElementAttributeWordQueryExpression({
|
|
291
|
+
elementName: "value",
|
|
292
|
+
attributeName: "rawValue",
|
|
293
|
+
value,
|
|
294
|
+
matchMode,
|
|
295
|
+
isCaseSensitive,
|
|
296
|
+
queryFamily: "raw"
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
function buildNotesQueryExpression(params) {
|
|
300
|
+
const { value, matchMode, isCaseSensitive, language } = params;
|
|
301
|
+
return buildNestedElementQuery([
|
|
302
|
+
"notes",
|
|
303
|
+
"note",
|
|
304
|
+
"content"
|
|
305
|
+
], buildRichTextContentQueryExpression({
|
|
306
|
+
value,
|
|
307
|
+
matchMode,
|
|
308
|
+
isCaseSensitive,
|
|
309
|
+
language
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
function buildContentTargetQueryExpression(params) {
|
|
313
|
+
const { target, value, matchMode, isCaseSensitive, language } = params;
|
|
314
|
+
const contentElementPath = CONTENT_TARGET_CONTENT_ELEMENT_PATHS[target];
|
|
315
|
+
return buildNestedElementQuery(contentElementPath, buildRichTextContentQueryExpression({
|
|
316
|
+
value,
|
|
317
|
+
matchMode,
|
|
318
|
+
isCaseSensitive,
|
|
319
|
+
language
|
|
320
|
+
}));
|
|
321
|
+
}
|
|
322
|
+
function buildPropertyQueryExpression(params) {
|
|
323
|
+
const { propertyVariable, queryExpression } = params;
|
|
324
|
+
const propertyQueryExpressions = [queryExpression];
|
|
325
|
+
if (propertyVariable != null) propertyQueryExpressions.unshift(buildPropertyLabelQuery(propertyVariable));
|
|
326
|
+
return buildNestedElementQuery(["properties", "property"], buildAndCtsQueryExpressionInternal(propertyQueryExpressions));
|
|
327
|
+
}
|
|
328
|
+
function buildPropertyTextMatchQueryExpression(params) {
|
|
329
|
+
const { propertyVariable, valueFilters = [], contentQueryExpression, rawValueQueryExpression, bareValueQueryExpression } = params;
|
|
330
|
+
const letBindings = [];
|
|
331
|
+
const valueMatchReferences = [];
|
|
332
|
+
if (contentQueryExpression != null) {
|
|
333
|
+
letBindings.push(`let $contentQuery := ${contentQueryExpression}`);
|
|
334
|
+
valueMatchReferences.push("$contentQuery");
|
|
335
|
+
}
|
|
336
|
+
if (rawValueQueryExpression != null) {
|
|
337
|
+
letBindings.push(`let $rawValueQuery := ${rawValueQueryExpression}`);
|
|
338
|
+
valueMatchReferences.push("$rawValueQuery");
|
|
339
|
+
}
|
|
340
|
+
if (bareValueQueryExpression != null) {
|
|
341
|
+
letBindings.push(`let $bareValueQuery := ${bareValueQueryExpression}`);
|
|
342
|
+
valueMatchReferences.push("$bareValueQuery");
|
|
343
|
+
}
|
|
344
|
+
const valueQueryExpressions = [...valueFilters];
|
|
345
|
+
if (valueMatchReferences.length > 0) valueQueryExpressions.push(buildOrCtsQueryExpressionInternal(valueMatchReferences));
|
|
346
|
+
const propertyQueryExpressions = [];
|
|
347
|
+
if (propertyVariable != null) propertyQueryExpressions.push(buildPropertyLabelQuery(propertyVariable));
|
|
348
|
+
propertyQueryExpressions.push(buildNestedElementQuery(["value"], buildAndCtsQueryExpressionInternal(valueQueryExpressions)));
|
|
349
|
+
const propertyQueryExpression = buildNestedElementQuery(["properties", "property"], buildAndCtsQueryExpressionInternal(propertyQueryExpressions));
|
|
350
|
+
if (letBindings.length === 0) return propertyQueryExpression;
|
|
351
|
+
return `(${letBindings.join("\n ")}\n return ${propertyQueryExpression})`;
|
|
352
|
+
}
|
|
353
|
+
function buildPropertyPresenceQueryExpression(params) {
|
|
354
|
+
return buildPropertyQueryExpression({
|
|
355
|
+
propertyVariable: params.propertyVariable,
|
|
356
|
+
queryExpression: "cts:true-query()"
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
function buildPropertyStringQueryExpression(params) {
|
|
360
|
+
const { propertyVariable, value, matchMode, isCaseSensitive, language } = params;
|
|
361
|
+
return buildPropertyTextMatchQueryExpression({
|
|
362
|
+
propertyVariable,
|
|
363
|
+
valueFilters: [buildValueNotInheritedQuery()],
|
|
364
|
+
contentQueryExpression: buildValueContentInnerQuery({
|
|
365
|
+
language,
|
|
366
|
+
value,
|
|
367
|
+
matchMode,
|
|
368
|
+
isCaseSensitive
|
|
369
|
+
}),
|
|
370
|
+
rawValueQueryExpression: buildValueRawValueInnerQuery({
|
|
371
|
+
value,
|
|
372
|
+
matchMode,
|
|
373
|
+
isCaseSensitive
|
|
374
|
+
}),
|
|
375
|
+
bareValueQueryExpression: buildValueDirectTextInnerQuery({
|
|
376
|
+
value,
|
|
377
|
+
matchMode,
|
|
378
|
+
isCaseSensitive
|
|
379
|
+
})
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
function buildPropertyScalarQueryExpression(params) {
|
|
383
|
+
const { propertyVariable, value, matchMode, isCaseSensitive } = params;
|
|
384
|
+
return buildPropertyQueryExpression({
|
|
385
|
+
propertyVariable,
|
|
386
|
+
queryExpression: buildNestedElementQuery(["value"], buildOrCtsQueryExpressionInternal([buildValueRawValueInnerQuery({
|
|
387
|
+
value,
|
|
388
|
+
matchMode,
|
|
389
|
+
isCaseSensitive
|
|
390
|
+
}), buildValueDirectTextInnerQuery({
|
|
391
|
+
value,
|
|
392
|
+
matchMode,
|
|
393
|
+
isCaseSensitive
|
|
394
|
+
})]))
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
function buildPropertyAllQueryExpression(params) {
|
|
398
|
+
const { query, value, matchMode } = params;
|
|
399
|
+
return buildPropertyTextMatchQueryExpression({
|
|
400
|
+
propertyVariable: query.propertyVariable,
|
|
401
|
+
valueFilters: [buildValueNotIdRefQuery()],
|
|
402
|
+
contentQueryExpression: buildValueContentInnerQuery({
|
|
403
|
+
language: query.language,
|
|
404
|
+
value,
|
|
405
|
+
matchMode,
|
|
406
|
+
isCaseSensitive: query.isCaseSensitive
|
|
407
|
+
}),
|
|
408
|
+
rawValueQueryExpression: buildValueRawValueInnerQuery({
|
|
409
|
+
value,
|
|
410
|
+
matchMode,
|
|
411
|
+
isCaseSensitive: query.isCaseSensitive
|
|
412
|
+
}),
|
|
413
|
+
bareValueQueryExpression: buildValueDirectTextInnerQuery({
|
|
414
|
+
value,
|
|
415
|
+
matchMode,
|
|
416
|
+
isCaseSensitive: query.isCaseSensitive
|
|
417
|
+
})
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function buildPropertyIdRefQueryExpression(params) {
|
|
421
|
+
const { propertyVariable, value } = params;
|
|
422
|
+
return buildPropertyQueryExpression({
|
|
423
|
+
propertyVariable,
|
|
424
|
+
queryExpression: buildNestedElementQuery(["value"], buildPlainElementAttributeValueQueryExpression({
|
|
425
|
+
elementName: "value",
|
|
426
|
+
attributeName: "uuid",
|
|
427
|
+
value
|
|
428
|
+
}))
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
function buildPropertyDateRangeQueryExpression(query) {
|
|
432
|
+
const rangeQueryExpressions = [];
|
|
433
|
+
if (query.from != null) rangeQueryExpressions.push(`cts:element-attribute-range-query(xs:QName("value"), xs:QName("rawValue"), ">=", ${stringLiteral(query.from)})`);
|
|
434
|
+
if (query.to != null) rangeQueryExpressions.push(`cts:element-attribute-range-query(xs:QName("value"), xs:QName("rawValue"), "<=", ${stringLiteral(query.to)})`);
|
|
435
|
+
return buildPropertyQueryExpression({
|
|
436
|
+
propertyVariable: query.propertyVariable,
|
|
437
|
+
queryExpression: buildNestedElementQuery(["value"], buildAndCtsQueryExpressionInternal(rangeQueryExpressions))
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
function buildItemStringQueryExpression(params) {
|
|
441
|
+
const { value, matchMode, isCaseSensitive, language } = params;
|
|
442
|
+
return buildOrCtsQueryExpressionInternal([buildContentTargetQueryExpression({
|
|
443
|
+
target: "title",
|
|
444
|
+
value,
|
|
445
|
+
matchMode,
|
|
446
|
+
isCaseSensitive,
|
|
447
|
+
language
|
|
448
|
+
}), buildPropertyStringQueryExpression({
|
|
449
|
+
value,
|
|
450
|
+
matchMode,
|
|
451
|
+
isCaseSensitive,
|
|
452
|
+
language
|
|
453
|
+
})]);
|
|
454
|
+
}
|
|
455
|
+
function getLeafSearchValue(query) {
|
|
456
|
+
switch (query.target) {
|
|
457
|
+
case "string":
|
|
458
|
+
case "title":
|
|
459
|
+
case "description":
|
|
460
|
+
case "image":
|
|
461
|
+
case "periods":
|
|
462
|
+
case "bibliography":
|
|
463
|
+
case "notes": return query.value;
|
|
464
|
+
case "property": return "value" in query && query.value != null ? query.value : null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function buildLeafValueQueryExpression(params) {
|
|
468
|
+
const { query, value, matchMode } = params;
|
|
469
|
+
switch (query.target) {
|
|
470
|
+
case "string": return buildItemStringQueryExpression({
|
|
471
|
+
value,
|
|
472
|
+
matchMode,
|
|
473
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
474
|
+
language: query.language
|
|
475
|
+
});
|
|
476
|
+
case "notes": return buildNotesQueryExpression({
|
|
477
|
+
value,
|
|
478
|
+
matchMode,
|
|
479
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
480
|
+
language: query.language
|
|
481
|
+
});
|
|
482
|
+
case "title":
|
|
483
|
+
case "description":
|
|
484
|
+
case "image":
|
|
485
|
+
case "periods":
|
|
486
|
+
case "bibliography": return buildContentTargetQueryExpression({
|
|
487
|
+
target: query.target,
|
|
488
|
+
value,
|
|
489
|
+
matchMode,
|
|
490
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
491
|
+
language: query.language
|
|
492
|
+
});
|
|
493
|
+
case "property": switch (query.dataType) {
|
|
494
|
+
case "all": return buildPropertyAllQueryExpression({
|
|
495
|
+
query,
|
|
496
|
+
value,
|
|
497
|
+
matchMode
|
|
498
|
+
});
|
|
499
|
+
case "IDREF": return buildPropertyIdRefQueryExpression({
|
|
500
|
+
propertyVariable: query.propertyVariable,
|
|
501
|
+
value
|
|
502
|
+
});
|
|
503
|
+
case "string": return buildPropertyStringQueryExpression({
|
|
504
|
+
propertyVariable: query.propertyVariable,
|
|
505
|
+
value,
|
|
506
|
+
matchMode,
|
|
507
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
508
|
+
language: query.language
|
|
509
|
+
});
|
|
510
|
+
case "integer":
|
|
511
|
+
case "decimal":
|
|
512
|
+
case "time":
|
|
513
|
+
case "boolean":
|
|
514
|
+
case "date":
|
|
515
|
+
case "dateTime": return buildPropertyScalarQueryExpression({
|
|
516
|
+
propertyVariable: query.propertyVariable,
|
|
517
|
+
value,
|
|
518
|
+
matchMode,
|
|
519
|
+
isCaseSensitive: query.isCaseSensitive
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function indentBlock(value, spaces) {
|
|
525
|
+
const prefix = " ".repeat(spaces);
|
|
526
|
+
return value.split("\n").map((line) => line === "" ? line : `${prefix}${line}`).join("\n");
|
|
527
|
+
}
|
|
528
|
+
function createQueryCompilerContext() {
|
|
529
|
+
return {
|
|
530
|
+
nextHelperSerial: 1,
|
|
531
|
+
helperNamesByKey: /* @__PURE__ */ new Map(),
|
|
532
|
+
helperDeclarations: []
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function registerConstantHelper(params) {
|
|
536
|
+
const { context, key, bodyExpression } = params;
|
|
537
|
+
const existingName = context.helperNamesByKey.get(key);
|
|
538
|
+
if (existingName != null) return {
|
|
539
|
+
name: existingName,
|
|
540
|
+
callExpression: `${existingName}()`
|
|
541
|
+
};
|
|
542
|
+
const helperName = `local:queryHelper${context.nextHelperSerial}`;
|
|
543
|
+
context.nextHelperSerial += 1;
|
|
544
|
+
context.helperNamesByKey.set(key, helperName);
|
|
545
|
+
context.helperDeclarations.push(`declare function ${helperName}() as cts:query {\n${indentBlock(bodyExpression, 2)}\n};`);
|
|
546
|
+
return {
|
|
547
|
+
name: helperName,
|
|
548
|
+
callExpression: `${helperName}()`
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
function replaceSampleValueLiteral(expression, sampleValue, valueReference) {
|
|
552
|
+
return expression.replaceAll(stringLiteral(sampleValue), valueReference);
|
|
553
|
+
}
|
|
554
|
+
function registerParameterizedHelper(params) {
|
|
555
|
+
const { context, key, bodyExpression } = params;
|
|
556
|
+
const existingName = context.helperNamesByKey.get(key);
|
|
557
|
+
if (existingName != null) return {
|
|
558
|
+
name: existingName,
|
|
559
|
+
call: (valueExpression) => `${existingName}(${valueExpression})`
|
|
560
|
+
};
|
|
561
|
+
const helperName = `local:queryHelper${context.nextHelperSerial}`;
|
|
562
|
+
context.nextHelperSerial += 1;
|
|
563
|
+
context.helperNamesByKey.set(key, helperName);
|
|
564
|
+
context.helperDeclarations.push(`declare function ${helperName}($value as xs:string) as cts:query {\n${indentBlock(bodyExpression, 2)}\n};`);
|
|
565
|
+
return {
|
|
566
|
+
name: helperName,
|
|
567
|
+
call: (valueExpression) => `${helperName}(${valueExpression})`
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function getLeafHelperKey(params) {
|
|
571
|
+
const { query, matchMode, value } = params;
|
|
572
|
+
switch (query.target) {
|
|
573
|
+
case "string":
|
|
574
|
+
case "title":
|
|
575
|
+
case "description":
|
|
576
|
+
case "image":
|
|
577
|
+
case "periods":
|
|
578
|
+
case "bibliography":
|
|
579
|
+
case "notes": return [
|
|
580
|
+
"leaf",
|
|
581
|
+
matchMode,
|
|
582
|
+
query.target,
|
|
583
|
+
value,
|
|
584
|
+
query.isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
585
|
+
query.language
|
|
586
|
+
].join("|");
|
|
587
|
+
case "property": return [
|
|
588
|
+
"leaf",
|
|
589
|
+
matchMode,
|
|
590
|
+
query.target,
|
|
591
|
+
query.dataType,
|
|
592
|
+
query.propertyVariable ?? "",
|
|
593
|
+
value,
|
|
594
|
+
query.isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
595
|
+
query.language
|
|
596
|
+
].join("|");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function registerLeafHelper(params) {
|
|
600
|
+
const { context, query, matchMode, value } = params;
|
|
601
|
+
return registerConstantHelper({
|
|
602
|
+
context,
|
|
603
|
+
key: getLeafHelperKey({
|
|
604
|
+
query,
|
|
605
|
+
matchMode,
|
|
606
|
+
value
|
|
607
|
+
}),
|
|
608
|
+
bodyExpression: buildLeafValueQueryExpression({
|
|
609
|
+
query,
|
|
610
|
+
value,
|
|
611
|
+
matchMode
|
|
612
|
+
})
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
function getIncludesLeafHelperKey(params) {
|
|
616
|
+
const { query, value } = params;
|
|
617
|
+
const isWildcarded = hasWildcardCharacters(value);
|
|
618
|
+
const isStemmed = !isWildcarded && shouldUseStemmedTextSearch(value);
|
|
619
|
+
switch (query.target) {
|
|
620
|
+
case "string":
|
|
621
|
+
case "title":
|
|
622
|
+
case "description":
|
|
623
|
+
case "image":
|
|
624
|
+
case "periods":
|
|
625
|
+
case "bibliography":
|
|
626
|
+
case "notes": return [
|
|
627
|
+
"includes-helper",
|
|
628
|
+
query.target,
|
|
629
|
+
query.isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
630
|
+
query.language,
|
|
631
|
+
isWildcarded ? "wildcarded" : "unwildcarded",
|
|
632
|
+
isStemmed ? "stemmed" : "unstemmed"
|
|
633
|
+
].join("|");
|
|
634
|
+
case "property": return [
|
|
635
|
+
"includes-helper",
|
|
636
|
+
query.target,
|
|
637
|
+
query.dataType,
|
|
638
|
+
query.propertyVariable ?? "",
|
|
639
|
+
query.isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
640
|
+
query.language,
|
|
641
|
+
isWildcarded ? "wildcarded" : "unwildcarded",
|
|
642
|
+
isStemmed ? "stemmed" : "unstemmed"
|
|
643
|
+
].join("|");
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
function registerIncludesLeafHelper(params) {
|
|
647
|
+
const { context, query, sampleValue } = params;
|
|
648
|
+
return registerParameterizedHelper({
|
|
649
|
+
context,
|
|
650
|
+
key: getIncludesLeafHelperKey({
|
|
651
|
+
query,
|
|
652
|
+
value: sampleValue
|
|
653
|
+
}),
|
|
654
|
+
bodyExpression: replaceSampleValueLiteral(buildLeafValueQueryExpression({
|
|
655
|
+
query,
|
|
656
|
+
value: sampleValue,
|
|
657
|
+
matchMode: "includes"
|
|
658
|
+
}), sampleValue, "$value")
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
function buildLeafQueryExpression(context, query) {
|
|
662
|
+
if (query.target === "property" && query.dataType !== "date" && query.dataType !== "dateTime" && !("value" in query) && query.propertyVariable != null) return buildPropertyPresenceQueryExpression({ propertyVariable: query.propertyVariable });
|
|
663
|
+
if (query.target === "property" && (query.dataType === "date" || query.dataType === "dateTime") && query.value == null) return buildPropertyDateRangeQueryExpression(query);
|
|
664
|
+
const searchValue = getLeafSearchValue(query);
|
|
665
|
+
if (searchValue == null) throw new Error("Missing searchable value for query leaf", { cause: query });
|
|
666
|
+
const exactHelper = registerLeafHelper({
|
|
667
|
+
context,
|
|
668
|
+
query,
|
|
669
|
+
matchMode: "exact",
|
|
670
|
+
value: searchValue
|
|
671
|
+
});
|
|
672
|
+
if (query.matchMode === "exact") return exactHelper.callExpression;
|
|
673
|
+
const terms = tokenizeIncludesSearchValue({
|
|
674
|
+
value: searchValue,
|
|
675
|
+
isCaseSensitive: query.isCaseSensitive
|
|
676
|
+
});
|
|
677
|
+
if (terms.length === 0) return "cts:false-query()";
|
|
678
|
+
const includesHelper = registerIncludesLeafHelper({
|
|
679
|
+
context,
|
|
680
|
+
query,
|
|
681
|
+
sampleValue: terms[0] ?? ""
|
|
682
|
+
});
|
|
683
|
+
const tokenizedHelperCalls = [];
|
|
684
|
+
for (const term of terms) {
|
|
685
|
+
const termHelper = term === (terms[0] ?? "") ? includesHelper : registerIncludesLeafHelper({
|
|
686
|
+
context,
|
|
687
|
+
query,
|
|
688
|
+
sampleValue: term
|
|
689
|
+
});
|
|
690
|
+
tokenizedHelperCalls.push(termHelper.call(stringLiteral(term)));
|
|
691
|
+
}
|
|
692
|
+
const tokenizedQueryExpression = buildAndCtsQueryExpressionInternal(tokenizedHelperCalls);
|
|
693
|
+
if (!shouldUseFullValueFallbackForIncludes({
|
|
694
|
+
value: searchValue,
|
|
695
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
696
|
+
terms
|
|
697
|
+
})) return tokenizedQueryExpression;
|
|
698
|
+
return buildOrCtsQueryExpressionInternal([exactHelper.callExpression, tokenizedQueryExpression]);
|
|
699
|
+
}
|
|
700
|
+
function getGroupableIncludesValue(query) {
|
|
701
|
+
if (query.matchMode !== "includes" || query.isNegated === true) return null;
|
|
702
|
+
switch (query.target) {
|
|
703
|
+
case "string":
|
|
704
|
+
case "title":
|
|
705
|
+
case "description":
|
|
706
|
+
case "image":
|
|
707
|
+
case "periods":
|
|
708
|
+
case "bibliography":
|
|
709
|
+
case "notes": return query.value;
|
|
710
|
+
case "property":
|
|
711
|
+
if (!("value" in query) || query.value == null || query.dataType === "IDREF") return null;
|
|
712
|
+
return query.value;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
function isQueryLeaf(query) {
|
|
716
|
+
return "target" in query;
|
|
717
|
+
}
|
|
718
|
+
function getQueryGroupChildren(query) {
|
|
719
|
+
return "and" in query ? query.and : query.or;
|
|
720
|
+
}
|
|
721
|
+
function getQueryGroupOperator(query) {
|
|
722
|
+
return "and" in query ? "and" : "or";
|
|
723
|
+
}
|
|
724
|
+
function getCompatibleIncludesGroupLeaves(query) {
|
|
725
|
+
if (!("or" in query) || query.or.length <= 1) return null;
|
|
726
|
+
const leafQueries = [];
|
|
727
|
+
for (const childQuery of query.or) {
|
|
728
|
+
if (!isQueryLeaf(childQuery)) return null;
|
|
729
|
+
leafQueries.push(childQuery);
|
|
730
|
+
}
|
|
731
|
+
const firstQuery = leafQueries[0];
|
|
732
|
+
if (firstQuery == null) return null;
|
|
733
|
+
const groupValue = getGroupableIncludesValue(firstQuery);
|
|
734
|
+
if (groupValue == null) return null;
|
|
735
|
+
for (const leafQuery of leafQueries) if (getGroupableIncludesValue(leafQuery) !== groupValue || leafQuery.isCaseSensitive !== firstQuery.isCaseSensitive || leafQuery.language !== firstQuery.language) return null;
|
|
736
|
+
return leafQueries;
|
|
737
|
+
}
|
|
738
|
+
function buildIncludesGroupQueryExpression(context, queries) {
|
|
739
|
+
const firstQuery = queries[0];
|
|
740
|
+
if (firstQuery == null) throw new Error("Cannot build an includes group without queries", { cause: queries });
|
|
741
|
+
const groupValue = getGroupableIncludesValue(firstQuery);
|
|
742
|
+
if (groupValue == null) throw new Error("Cannot build an includes group without a search value", { cause: firstQuery });
|
|
743
|
+
const terms = tokenizeIncludesSearchValue({
|
|
744
|
+
value: groupValue,
|
|
745
|
+
isCaseSensitive: firstQuery.isCaseSensitive
|
|
746
|
+
});
|
|
747
|
+
if (terms.length === 0) return "cts:false-query()";
|
|
748
|
+
const tokenizedHelperCalls = [];
|
|
749
|
+
for (const term of terms) {
|
|
750
|
+
const memberHelpers = queries.map((query) => registerIncludesLeafHelper({
|
|
751
|
+
context,
|
|
752
|
+
query,
|
|
753
|
+
sampleValue: term
|
|
754
|
+
}));
|
|
755
|
+
const termGroupHelper = registerParameterizedHelper({
|
|
756
|
+
context,
|
|
757
|
+
key: [
|
|
758
|
+
"group",
|
|
759
|
+
"includes",
|
|
760
|
+
...memberHelpers.map((helper) => helper.name)
|
|
761
|
+
].join("|"),
|
|
762
|
+
bodyExpression: buildOrCtsQueryExpressionInternal(memberHelpers.map((helper) => helper.call("$value")))
|
|
763
|
+
});
|
|
764
|
+
tokenizedHelperCalls.push(termGroupHelper.call(stringLiteral(term)));
|
|
765
|
+
}
|
|
766
|
+
const tokenizedQueryExpression = buildAndCtsQueryExpressionInternal(tokenizedHelperCalls);
|
|
767
|
+
if (!shouldUseFullValueFallbackForIncludes({
|
|
768
|
+
value: groupValue,
|
|
769
|
+
isCaseSensitive: firstQuery.isCaseSensitive,
|
|
770
|
+
terms
|
|
771
|
+
})) return tokenizedQueryExpression;
|
|
772
|
+
const exactMemberHelpers = queries.map((query) => registerLeafHelper({
|
|
773
|
+
context,
|
|
774
|
+
query,
|
|
775
|
+
matchMode: "exact",
|
|
776
|
+
value: groupValue
|
|
777
|
+
}));
|
|
778
|
+
return buildOrCtsQueryExpressionInternal([registerConstantHelper({
|
|
779
|
+
context,
|
|
780
|
+
key: [
|
|
781
|
+
"group",
|
|
782
|
+
"exact",
|
|
783
|
+
groupValue,
|
|
784
|
+
...exactMemberHelpers.map((helper) => helper.name)
|
|
785
|
+
].join("|"),
|
|
786
|
+
bodyExpression: buildOrCtsQueryExpressionInternal(exactMemberHelpers.map((helper) => helper.callExpression))
|
|
787
|
+
}).callExpression, tokenizedQueryExpression]);
|
|
788
|
+
}
|
|
789
|
+
function buildQueryNode(context, query) {
|
|
790
|
+
if (isQueryLeaf(query)) {
|
|
791
|
+
const queryExpression = buildLeafQueryExpression(context, query);
|
|
792
|
+
return query.isNegated === true ? buildNotCtsQueryExpression(queryExpression) : queryExpression;
|
|
793
|
+
}
|
|
794
|
+
const optimizedIncludesGroupQueries = getCompatibleIncludesGroupLeaves(query);
|
|
795
|
+
if (optimizedIncludesGroupQueries != null) return buildIncludesGroupQueryExpression(context, optimizedIncludesGroupQueries);
|
|
796
|
+
const childQueryExpressions = [];
|
|
797
|
+
for (const childQuery of getQueryGroupChildren(query)) childQueryExpressions.push(buildQueryNode(context, childQuery));
|
|
798
|
+
return getQueryGroupOperator(query) === "and" ? buildAndCtsQueryExpressionInternal(childQueryExpressions) : buildOrCtsQueryExpressionInternal(childQueryExpressions);
|
|
799
|
+
}
|
|
800
|
+
function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids, belongsToCollectionPropertyVariableUuid) {
|
|
801
|
+
if (belongsToCollectionScopeUuids.length === 0) return null;
|
|
802
|
+
const collectionValueQueryExpressions = [];
|
|
803
|
+
for (const uuid of belongsToCollectionScopeUuids) collectionValueQueryExpressions.push(buildPlainElementAttributeValueQueryExpression({
|
|
804
|
+
elementName: "value",
|
|
805
|
+
attributeName: "uuid",
|
|
806
|
+
value: uuid
|
|
807
|
+
}));
|
|
808
|
+
return buildPropertyQueryExpression({
|
|
809
|
+
propertyVariable: belongsToCollectionPropertyVariableUuid,
|
|
810
|
+
queryExpression: buildNestedElementQuery(["value"], buildOrCtsQueryExpressionInternal(collectionValueQueryExpressions))
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
function buildQueryPlan(params) {
|
|
814
|
+
const { queries } = params;
|
|
815
|
+
if (queries == null) return {
|
|
816
|
+
prolog: "",
|
|
817
|
+
queryExpression: null
|
|
818
|
+
};
|
|
819
|
+
const context = createQueryCompilerContext();
|
|
820
|
+
const queryExpression = buildQueryNode(context, queries);
|
|
821
|
+
return {
|
|
822
|
+
prolog: context.helperDeclarations.join("\n\n"),
|
|
823
|
+
queryExpression
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
//#endregion
|
|
827
|
+
export { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan };
|