ochre-sdk 1.1.1 → 1.1.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/README.md +20 -0
- package/dist/fetchers/container-items.d.mts +52 -0
- package/dist/fetchers/container-items.mjs +171 -0
- package/dist/fetchers/set/items.mjs +9 -148
- package/dist/fetchers/set/property-values.mjs +4 -3
- package/dist/fetchers/tree/items.d.mts +53 -0
- package/dist/fetchers/tree/items.mjs +38 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/query.d.mts +42 -9
- package/dist/query.mjs +37 -18
- package/dist/schemas.d.mts +28 -4
- package/dist/schemas.mjs +14 -3
- package/dist/types/index.d.mts +9 -0
- package/dist/xml/schemas.d.mts +30 -10
- package/dist/xml/schemas.mjs +3 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -66,6 +66,9 @@ present and `error` is `null`; on failure, the parsed value is `null` and
|
|
|
66
66
|
style, collection, and item-page configuration.
|
|
67
67
|
- `fetchSetItems(params, containedItemCategories, options)` fetches paginated
|
|
68
68
|
Set search results with typed query and sort support.
|
|
69
|
+
- `fetchTreeItems(params, containedItemCategories, options)` is the same for a
|
|
70
|
+
Tree, and is how to read a Tree too large to fetch whole. Items nested under
|
|
71
|
+
headings come back flat, in document order.
|
|
69
72
|
- `fetchSetPropertyValues(params, options)` fetches Set property-value facets
|
|
70
73
|
and optional bibliography/period attribute facets for the same query model.
|
|
71
74
|
|
|
@@ -149,6 +152,23 @@ const result = await fetchSetItems(
|
|
|
149
152
|
Use `fetchSetPropertyValues` with the same query shape when you need facet data
|
|
150
153
|
for a filtered result set.
|
|
151
154
|
|
|
155
|
+
`fetchTreeItems` takes the same `Query` tree and the same sort options, because
|
|
156
|
+
both fetchers compile the same query model against their container's searchable
|
|
157
|
+
path. The difference is what the payload carries: OCHRE publishes Tree items as
|
|
158
|
+
identification-only stubs unless the Tree is published with item properties, so
|
|
159
|
+
a `property` query or a `propertyValue` sort only works on a Tree that carries
|
|
160
|
+
them.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { fetchTreeItems } from "ochre-sdk";
|
|
164
|
+
|
|
165
|
+
const result = await fetchTreeItems(
|
|
166
|
+
{ treeScopeUuids: ["<tree-uuid>"], sort: { target: "title" }, page: 1 },
|
|
167
|
+
["concept"],
|
|
168
|
+
{ languages: ["eng"] },
|
|
169
|
+
);
|
|
170
|
+
```
|
|
171
|
+
|
|
152
172
|
### OCR Text Queries
|
|
153
173
|
|
|
154
174
|
The `ocr` target searches the OCR text layer of the Resource items in a Set. It takes no `language`, because OCR text carries none.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ItemCategory, Query, SetItem, SetItemsSort } from "../types/index.mjs";
|
|
2
|
+
import { XMLSetItems } from "../xml/types.mjs";
|
|
3
|
+
import { FetchRuntimeOptions } from "../parsers/helpers.mjs";
|
|
4
|
+
//#region src/fetchers/container-items.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Whether a container payload carries any item of a category
|
|
7
|
+
* @param items - The parsed `<items>` payload
|
|
8
|
+
* @param category - The category to look for
|
|
9
|
+
* @returns True when the payload carries at least one item of it
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function hasItemsCategory(items: XMLSetItems, category: ItemCategory): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Fetch one page of the items a Set or a Tree holds
|
|
15
|
+
*
|
|
16
|
+
* The only thing that differs between the two containers is the searchable
|
|
17
|
+
* path {@link compileContainerItemsQuery} picks, so counting, sorting,
|
|
18
|
+
* paginating, validating and parsing are written once here and the public
|
|
19
|
+
* fetchers are thin wrappers that name their own scope parameter.
|
|
20
|
+
* @param parameters - The request parameters
|
|
21
|
+
* @param parameters.container - Whether the scope UUIDs name Sets or Trees
|
|
22
|
+
* @param parameters.scopeUuids - The container UUIDs to search within
|
|
23
|
+
* @param parameters.belongsToCollectionScopeUuids - Collection scope UUIDs to narrow to
|
|
24
|
+
* @param parameters.queries - The query tree to filter by, or null to match every item
|
|
25
|
+
* @param parameters.sort - The sort applied before pagination
|
|
26
|
+
* @param parameters.page - The page number, 1-indexed
|
|
27
|
+
* @param parameters.pageSize - The number of items per page
|
|
28
|
+
* @param parameters.containedItemCategories - Categories the payload must carry
|
|
29
|
+
* @param parameters.label - What is being fetched, used in failure messages
|
|
30
|
+
* @param parameters.options - Fetch and parser options
|
|
31
|
+
* @returns The page of items, deduplicated by UUID
|
|
32
|
+
* @throws When the request fails, validation fails, or a category is missing
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function fetchContainerItems(parameters: {
|
|
36
|
+
container: "set" | "tree";
|
|
37
|
+
scopeUuids: Array<string>;
|
|
38
|
+
belongsToCollectionScopeUuids: Array<string>;
|
|
39
|
+
queries: Query | null;
|
|
40
|
+
sort: SetItemsSort;
|
|
41
|
+
page: number;
|
|
42
|
+
pageSize: number;
|
|
43
|
+
containedItemCategories?: ReadonlyArray<ItemCategory>;
|
|
44
|
+
label: string;
|
|
45
|
+
options?: FetchRuntimeOptions;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
totalCount: number;
|
|
48
|
+
page: number;
|
|
49
|
+
pageSize: number;
|
|
50
|
+
items: Array<SetItem<ItemCategory, ReadonlyArray<string>>>;
|
|
51
|
+
}>;
|
|
52
|
+
//#endregion
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { requestOchre } from "./request.mjs";
|
|
2
|
+
import { parseRequestedLanguages, resolveContentLanguages } from "../parsers/languages.mjs";
|
|
3
|
+
import { parseSetItems } from "../parsers/index.mjs";
|
|
4
|
+
import { XMLSetItemsData } from "../xml/schemas.mjs";
|
|
5
|
+
import { stringLiteral } from "../xquery.mjs";
|
|
6
|
+
import { compileContainerItemsQuery } from "../query.mjs";
|
|
7
|
+
//#region src/fetchers/container-items.ts
|
|
8
|
+
function hasArray(items) {
|
|
9
|
+
return items != null && items.length > 0;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Whether a container payload carries any item of a category
|
|
13
|
+
* @param items - The parsed `<items>` payload
|
|
14
|
+
* @param category - The category to look for
|
|
15
|
+
* @returns True when the payload carries at least one item of it
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
function hasItemsCategory(items, category) {
|
|
19
|
+
switch (category) {
|
|
20
|
+
case "tree": return hasArray(items.tree);
|
|
21
|
+
case "bibliography": return hasArray(items.bibliography);
|
|
22
|
+
case "concept": return hasArray(items.concept);
|
|
23
|
+
case "spatialUnit": return hasArray(items.spatialUnit);
|
|
24
|
+
case "period": return hasArray(items.period);
|
|
25
|
+
case "person": return hasArray(items.person);
|
|
26
|
+
case "propertyVariable": return hasArray(items.propertyVariable) || hasArray(items.variable);
|
|
27
|
+
case "propertyValue": return hasArray(items.propertyValue) || hasArray(items.value);
|
|
28
|
+
case "resource": return hasArray(items.resource);
|
|
29
|
+
case "text": return hasArray(items.text);
|
|
30
|
+
case "set": return hasArray(items.set);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function mapSortDirectionToXQuery(direction) {
|
|
34
|
+
return direction === "desc" ? "descending" : "ascending";
|
|
35
|
+
}
|
|
36
|
+
function buildStringOrderByClause(direction) {
|
|
37
|
+
return `($sortKey = "") ascending, lower-case($sortKey) ${direction}, $position ascending`;
|
|
38
|
+
}
|
|
39
|
+
function buildTypedOrderByClause(direction) {
|
|
40
|
+
return `empty($sortKey) ascending, $sortKey ${direction}, $position ascending`;
|
|
41
|
+
}
|
|
42
|
+
function buildPropertyValueValuePath(sort) {
|
|
43
|
+
return `$item//properties//property[label/@uuid=${stringLiteral(sort.propertyVariableUuid)}]/value[not(@i)]`;
|
|
44
|
+
}
|
|
45
|
+
function buildPropertyValueStringSortKeyExpression(sort) {
|
|
46
|
+
const languageLiteral = stringLiteral(sort.language ?? "eng");
|
|
47
|
+
return `string((for $v in ${buildPropertyValueValuePath(sort)}
|
|
48
|
+
let $candidate := string-join($v/content[@xml:lang=${languageLiteral}]/string, "")
|
|
49
|
+
where string-length($candidate) gt 0
|
|
50
|
+
return $candidate)[1])`;
|
|
51
|
+
}
|
|
52
|
+
function buildPropertyValueTypedSortKeyExpression(parameters) {
|
|
53
|
+
const { sort, dataType } = parameters;
|
|
54
|
+
const propertyValuePath = buildPropertyValueValuePath(sort);
|
|
55
|
+
switch (dataType) {
|
|
56
|
+
case "integer": return `(for $v in ${propertyValuePath}
|
|
57
|
+
let $candidate := normalize-space(string($v/@rawValue))
|
|
58
|
+
where $candidate castable as xs:integer
|
|
59
|
+
return xs:integer($candidate))[1]`;
|
|
60
|
+
case "decimal":
|
|
61
|
+
case "time": return `(for $v in ${propertyValuePath}
|
|
62
|
+
let $candidate := normalize-space(string($v/@rawValue))
|
|
63
|
+
where $candidate castable as xs:decimal
|
|
64
|
+
return xs:decimal($candidate))[1]`;
|
|
65
|
+
case "boolean": return `(for $v in ${propertyValuePath}
|
|
66
|
+
let $candidate := lower-case(normalize-space(string($v/@rawValue)))
|
|
67
|
+
where $candidate = ("true", "false", "1", "0")
|
|
68
|
+
return if ($candidate = ("true", "1")) then 1 else 0)[1]`;
|
|
69
|
+
case "date": return `(for $v in ${propertyValuePath}
|
|
70
|
+
let $candidate := normalize-space(string($v/@rawValue))
|
|
71
|
+
where $candidate castable as xs:date
|
|
72
|
+
return xs:date($candidate))[1]`;
|
|
73
|
+
case "dateTime": return `(for $v in ${propertyValuePath}
|
|
74
|
+
let $candidate := normalize-space(string($v/@rawValue))
|
|
75
|
+
where $candidate castable as xs:dateTime
|
|
76
|
+
return xs:dateTime($candidate))[1]`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function buildPropertyValueOrderByClause(parameters) {
|
|
80
|
+
const { dataType, direction } = parameters;
|
|
81
|
+
return (dataType === "string" || dataType === "IDREF" ? buildStringOrderByClause : buildTypedOrderByClause)(direction);
|
|
82
|
+
}
|
|
83
|
+
function buildOrderedItemsClause(sort) {
|
|
84
|
+
if (sort.target === "none") return "let $orderedItems := $items";
|
|
85
|
+
const direction = mapSortDirectionToXQuery(sort.direction);
|
|
86
|
+
if (sort.target === "title") return `let $orderedItems :=
|
|
87
|
+
for $item at $position in $items
|
|
88
|
+
let $sortKey := ${`string-join($item/identification/label/content[@xml:lang=${stringLiteral(sort.language ?? "eng")}]/string, "")`}
|
|
89
|
+
stable order by ${buildStringOrderByClause(direction)}
|
|
90
|
+
return $item`;
|
|
91
|
+
if (sort.target === "date") return `let $orderedItems :=
|
|
92
|
+
for $item at $position in $items
|
|
93
|
+
let $sortKey := string(($item/@date, $item/interpretations/interpretation/@date)[1])
|
|
94
|
+
stable order by ${buildStringOrderByClause(direction)}
|
|
95
|
+
return $item`;
|
|
96
|
+
return `let $orderedItems :=
|
|
97
|
+
for $item at $position in $items
|
|
98
|
+
let $sortKey := ${sort.dataType === "string" || sort.dataType === "IDREF" ? buildPropertyValueStringSortKeyExpression(sort) : buildPropertyValueTypedSortKeyExpression({
|
|
99
|
+
sort,
|
|
100
|
+
dataType: sort.dataType
|
|
101
|
+
})}
|
|
102
|
+
stable order by ${buildPropertyValueOrderByClause({
|
|
103
|
+
dataType: sort.dataType,
|
|
104
|
+
direction
|
|
105
|
+
})}
|
|
106
|
+
return $item`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Fetch one page of the items a Set or a Tree holds
|
|
110
|
+
*
|
|
111
|
+
* The only thing that differs between the two containers is the searchable
|
|
112
|
+
* path {@link compileContainerItemsQuery} picks, so counting, sorting,
|
|
113
|
+
* paginating, validating and parsing are written once here and the public
|
|
114
|
+
* fetchers are thin wrappers that name their own scope parameter.
|
|
115
|
+
* @param parameters - The request parameters
|
|
116
|
+
* @param parameters.container - Whether the scope UUIDs name Sets or Trees
|
|
117
|
+
* @param parameters.scopeUuids - The container UUIDs to search within
|
|
118
|
+
* @param parameters.belongsToCollectionScopeUuids - Collection scope UUIDs to narrow to
|
|
119
|
+
* @param parameters.queries - The query tree to filter by, or null to match every item
|
|
120
|
+
* @param parameters.sort - The sort applied before pagination
|
|
121
|
+
* @param parameters.page - The page number, 1-indexed
|
|
122
|
+
* @param parameters.pageSize - The number of items per page
|
|
123
|
+
* @param parameters.containedItemCategories - Categories the payload must carry
|
|
124
|
+
* @param parameters.label - What is being fetched, used in failure messages
|
|
125
|
+
* @param parameters.options - Fetch and parser options
|
|
126
|
+
* @returns The page of items, deduplicated by UUID
|
|
127
|
+
* @throws When the request fails, validation fails, or a category is missing
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
async function fetchContainerItems(parameters) {
|
|
131
|
+
const { container, scopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize, containedItemCategories, label, options } = parameters;
|
|
132
|
+
const requestedLanguages = parseRequestedLanguages(options?.languages);
|
|
133
|
+
const startPosition = (page - 1) * pageSize + 1;
|
|
134
|
+
const output = await requestOchre({
|
|
135
|
+
xquery: compileContainerItemsQuery({
|
|
136
|
+
container,
|
|
137
|
+
scopeUuids,
|
|
138
|
+
belongsToCollectionScopeUuids,
|
|
139
|
+
queries,
|
|
140
|
+
body: ({ items, omitSupplemental }) => ` let $totalCount := count(${items})
|
|
141
|
+
${buildOrderedItemsClause(sort)}
|
|
142
|
+
let $pagedItems := subsequence($orderedItems, ${startPosition}, ${pageSize})
|
|
143
|
+
|
|
144
|
+
return <items totalCount="{$totalCount}" page="${page}" pageSize="${pageSize}">{
|
|
145
|
+
${omitSupplemental("$pagedItems")}
|
|
146
|
+
}</items>`
|
|
147
|
+
}),
|
|
148
|
+
schema: XMLSetItemsData,
|
|
149
|
+
label,
|
|
150
|
+
options
|
|
151
|
+
});
|
|
152
|
+
if (containedItemCategories != null) {
|
|
153
|
+
const missingCategories = containedItemCategories.filter((category) => !hasItemsCategory(output.result.ochre.items, category));
|
|
154
|
+
if (missingCategories.length > 0) throw new Error(`No items found for item categories: ${missingCategories.join(", ")}`, { cause: missingCategories });
|
|
155
|
+
}
|
|
156
|
+
const parserOptions = { languages: resolveContentLanguages(output.result.ochre.items, requestedLanguages) };
|
|
157
|
+
const items = parseSetItems(output.result.ochre.items, {
|
|
158
|
+
containedItemCategories,
|
|
159
|
+
languages: parserOptions.languages
|
|
160
|
+
});
|
|
161
|
+
const itemsByUuid = /* @__PURE__ */ new Map();
|
|
162
|
+
for (const item of items) if (!itemsByUuid.has(item.uuid)) itemsByUuid.set(item.uuid, item);
|
|
163
|
+
return {
|
|
164
|
+
totalCount: output.result.ochre.items.totalCount,
|
|
165
|
+
page: output.result.ochre.items.page,
|
|
166
|
+
pageSize: output.result.ochre.items.pageSize,
|
|
167
|
+
items: itemsByUuid.values().toArray()
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
export { fetchContainerItems, hasItemsCategory };
|
|
@@ -1,163 +1,24 @@
|
|
|
1
1
|
import { getErrorOutput } from "../../errors.mjs";
|
|
2
|
-
import { requestOchre } from "../request.mjs";
|
|
3
2
|
import { setItemsParametersSchema } from "../../schemas.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { parseSetItems } from "../../parsers/index.mjs";
|
|
6
|
-
import { XMLSetItemsData } from "../../xml/schemas.mjs";
|
|
7
|
-
import { stringLiteral } from "../../xquery.mjs";
|
|
8
|
-
import { compileSetItemsQuery } from "../../query.mjs";
|
|
3
|
+
import { fetchContainerItems } from "../container-items.mjs";
|
|
9
4
|
import * as v from "valibot";
|
|
10
5
|
//#region src/fetchers/set/items.ts
|
|
11
|
-
function hasArray(items) {
|
|
12
|
-
return items != null && items.length > 0;
|
|
13
|
-
}
|
|
14
|
-
function hasSetItemsCategory(items, category) {
|
|
15
|
-
switch (category) {
|
|
16
|
-
case "tree": return hasArray(items.tree);
|
|
17
|
-
case "bibliography": return hasArray(items.bibliography);
|
|
18
|
-
case "concept": return hasArray(items.concept);
|
|
19
|
-
case "spatialUnit": return hasArray(items.spatialUnit);
|
|
20
|
-
case "period": return hasArray(items.period);
|
|
21
|
-
case "person": return hasArray(items.person);
|
|
22
|
-
case "propertyVariable": return hasArray(items.propertyVariable) || hasArray(items.variable);
|
|
23
|
-
case "propertyValue": return hasArray(items.propertyValue) || hasArray(items.value);
|
|
24
|
-
case "resource": return hasArray(items.resource);
|
|
25
|
-
case "text": return hasArray(items.text);
|
|
26
|
-
case "set": return hasArray(items.set);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function mapSortDirectionToXQuery(direction) {
|
|
30
|
-
return direction === "desc" ? "descending" : "ascending";
|
|
31
|
-
}
|
|
32
|
-
function buildStringOrderByClause(direction) {
|
|
33
|
-
return `($sortKey = "") ascending, lower-case($sortKey) ${direction}, $position ascending`;
|
|
34
|
-
}
|
|
35
|
-
function buildTypedOrderByClause(direction) {
|
|
36
|
-
return `empty($sortKey) ascending, $sortKey ${direction}, $position ascending`;
|
|
37
|
-
}
|
|
38
|
-
function buildPropertyValueValuePath(sort) {
|
|
39
|
-
return `$item//properties//property[label/@uuid=${stringLiteral(sort.propertyVariableUuid)}]/value[not(@i)]`;
|
|
40
|
-
}
|
|
41
|
-
function buildPropertyValueStringSortKeyExpression(sort) {
|
|
42
|
-
const languageLiteral = stringLiteral(sort.language ?? "eng");
|
|
43
|
-
return `string((for $v in ${buildPropertyValueValuePath(sort)}
|
|
44
|
-
let $candidate := string-join($v/content[@xml:lang=${languageLiteral}]/string, "")
|
|
45
|
-
where string-length($candidate) gt 0
|
|
46
|
-
return $candidate)[1])`;
|
|
47
|
-
}
|
|
48
|
-
function buildPropertyValueTypedSortKeyExpression(parameters) {
|
|
49
|
-
const { sort, dataType } = parameters;
|
|
50
|
-
const propertyValuePath = buildPropertyValueValuePath(sort);
|
|
51
|
-
switch (dataType) {
|
|
52
|
-
case "integer": return `(for $v in ${propertyValuePath}
|
|
53
|
-
let $candidate := normalize-space(string($v/@rawValue))
|
|
54
|
-
where $candidate castable as xs:integer
|
|
55
|
-
return xs:integer($candidate))[1]`;
|
|
56
|
-
case "decimal":
|
|
57
|
-
case "time": return `(for $v in ${propertyValuePath}
|
|
58
|
-
let $candidate := normalize-space(string($v/@rawValue))
|
|
59
|
-
where $candidate castable as xs:decimal
|
|
60
|
-
return xs:decimal($candidate))[1]`;
|
|
61
|
-
case "boolean": return `(for $v in ${propertyValuePath}
|
|
62
|
-
let $candidate := lower-case(normalize-space(string($v/@rawValue)))
|
|
63
|
-
where $candidate = ("true", "false", "1", "0")
|
|
64
|
-
return if ($candidate = ("true", "1")) then 1 else 0)[1]`;
|
|
65
|
-
case "date": return `(for $v in ${propertyValuePath}
|
|
66
|
-
let $candidate := normalize-space(string($v/@rawValue))
|
|
67
|
-
where $candidate castable as xs:date
|
|
68
|
-
return xs:date($candidate))[1]`;
|
|
69
|
-
case "dateTime": return `(for $v in ${propertyValuePath}
|
|
70
|
-
let $candidate := normalize-space(string($v/@rawValue))
|
|
71
|
-
where $candidate castable as xs:dateTime
|
|
72
|
-
return xs:dateTime($candidate))[1]`;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function buildPropertyValueOrderByClause(parameters) {
|
|
76
|
-
const { dataType, direction } = parameters;
|
|
77
|
-
return (dataType === "string" || dataType === "IDREF" ? buildStringOrderByClause : buildTypedOrderByClause)(direction);
|
|
78
|
-
}
|
|
79
|
-
function buildOrderedItemsClause(sort) {
|
|
80
|
-
if (sort.target === "none") return "let $orderedItems := $items";
|
|
81
|
-
const direction = mapSortDirectionToXQuery(sort.direction);
|
|
82
|
-
if (sort.target === "title") return `let $orderedItems :=
|
|
83
|
-
for $item at $position in $items
|
|
84
|
-
let $sortKey := ${`string-join($item/identification/label/content[@xml:lang=${stringLiteral(sort.language ?? "eng")}]/string, "")`}
|
|
85
|
-
stable order by ${buildStringOrderByClause(direction)}
|
|
86
|
-
return $item`;
|
|
87
|
-
return `let $orderedItems :=
|
|
88
|
-
for $item at $position in $items
|
|
89
|
-
let $sortKey := ${sort.dataType === "string" || sort.dataType === "IDREF" ? buildPropertyValueStringSortKeyExpression(sort) : buildPropertyValueTypedSortKeyExpression({
|
|
90
|
-
sort,
|
|
91
|
-
dataType: sort.dataType
|
|
92
|
-
})}
|
|
93
|
-
stable order by ${buildPropertyValueOrderByClause({
|
|
94
|
-
dataType: sort.dataType,
|
|
95
|
-
direction
|
|
96
|
-
})}
|
|
97
|
-
return $item`;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Build an XQuery string to fetch Set items from the OCHRE API
|
|
101
|
-
* @param parameters - The parameters for the fetch
|
|
102
|
-
* @param parameters.setScopeUuids - An array of Set scope UUIDs to filter by
|
|
103
|
-
* @param parameters.belongsToCollectionScopeUuids - An array of collection scope UUIDs to filter by
|
|
104
|
-
* @param parameters.queries - Recursive query tree used to filter matching items
|
|
105
|
-
* @param parameters.sort - Optional sorting configuration applied before pagination.
|
|
106
|
-
* For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
|
|
107
|
-
* @param parameters.page - The page number (1-indexed)
|
|
108
|
-
* @param parameters.pageSize - The number of items per page
|
|
109
|
-
* @returns An XQuery string
|
|
110
|
-
*/
|
|
111
|
-
function buildXQuery(parameters) {
|
|
112
|
-
const { queries, sort, setScopeUuids, belongsToCollectionScopeUuids, page, pageSize } = parameters;
|
|
113
|
-
const startPosition = (page - 1) * pageSize + 1;
|
|
114
|
-
return compileSetItemsQuery({
|
|
115
|
-
setScopeUuids,
|
|
116
|
-
belongsToCollectionScopeUuids,
|
|
117
|
-
queries,
|
|
118
|
-
body: ({ items, omitSupplemental }) => ` let $totalCount := count(${items})
|
|
119
|
-
${buildOrderedItemsClause(sort)}
|
|
120
|
-
let $pagedItems := subsequence($orderedItems, ${startPosition}, ${pageSize})
|
|
121
|
-
|
|
122
|
-
return <items totalCount="{$totalCount}" page="${page}" pageSize="${pageSize}">{
|
|
123
|
-
${omitSupplemental("$pagedItems")}
|
|
124
|
-
}</items>`
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
6
|
async function fetchSetItems(parameters, containedItemCategories, options) {
|
|
128
7
|
try {
|
|
129
8
|
const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = v.parse(setItemsParametersSchema, parameters);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
setScopeUuids,
|
|
9
|
+
return {
|
|
10
|
+
...await fetchContainerItems({
|
|
11
|
+
container: "set",
|
|
12
|
+
scopeUuids: setScopeUuids,
|
|
134
13
|
belongsToCollectionScopeUuids,
|
|
135
14
|
queries,
|
|
136
15
|
sort,
|
|
137
16
|
page,
|
|
138
|
-
pageSize
|
|
17
|
+
pageSize,
|
|
18
|
+
containedItemCategories,
|
|
19
|
+
label: "OCHRE Set items",
|
|
20
|
+
options
|
|
139
21
|
}),
|
|
140
|
-
schema: XMLSetItemsData,
|
|
141
|
-
label: "OCHRE Set items",
|
|
142
|
-
options
|
|
143
|
-
});
|
|
144
|
-
if (containedItemCategories != null) {
|
|
145
|
-
const missingCategories = containedItemCategories.filter((category) => !hasSetItemsCategory(output.result.ochre.items, category));
|
|
146
|
-
if (missingCategories.length > 0) throw new Error(`No Set items found for item categories: ${missingCategories.join(", ")}`, { cause: missingCategories });
|
|
147
|
-
}
|
|
148
|
-
const languages = resolveContentLanguages(output.result.ochre.items, requestedLanguages);
|
|
149
|
-
const items = parseSetItems(output.result.ochre.items, {
|
|
150
|
-
containedItemCategories,
|
|
151
|
-
languages
|
|
152
|
-
});
|
|
153
|
-
const itemsByUuid = /* @__PURE__ */ new Map();
|
|
154
|
-
for (const item of items) if (!itemsByUuid.has(item.uuid)) itemsByUuid.set(item.uuid, item);
|
|
155
|
-
const uniqueItems = itemsByUuid.values().toArray();
|
|
156
|
-
return {
|
|
157
|
-
totalCount: output.result.ochre.items.totalCount,
|
|
158
|
-
page: output.result.ochre.items.page,
|
|
159
|
-
pageSize: output.result.ochre.items.pageSize,
|
|
160
|
-
items: uniqueItems,
|
|
161
22
|
error: null,
|
|
162
23
|
detailedError: null
|
|
163
24
|
};
|
|
@@ -5,7 +5,7 @@ import { MultilingualString } from "../../parsers/multilingual.mjs";
|
|
|
5
5
|
import { setPropertyValuesParametersSchema } from "../../schemas.mjs";
|
|
6
6
|
import { parseXMLContent } from "../../parsers/string.mjs";
|
|
7
7
|
import { stringLiteral } from "../../xquery.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { compileContainerItemsQuery, getItemFilterQueries, getPropertyFacetSelectors } from "../../query.mjs";
|
|
9
9
|
import * as v from "valibot";
|
|
10
10
|
//#region src/fetchers/set/property-values.ts
|
|
11
11
|
function getLabelContentLanguages(content) {
|
|
@@ -367,8 +367,9 @@ let $period-values :=
|
|
|
367
367
|
}
|
|
368
368
|
return queryBlocks;
|
|
369
369
|
}
|
|
370
|
-
return
|
|
371
|
-
|
|
370
|
+
return compileContainerItemsQuery({
|
|
371
|
+
container: "set",
|
|
372
|
+
scopeUuids: setScopeUuids,
|
|
372
373
|
belongsToCollectionScopeUuids,
|
|
373
374
|
queries: getItemFilterQueries(queries),
|
|
374
375
|
declarations: xqueryDeclarations,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Query, SetItem, SetItemsSort, TreeItemCategory } from "../../types/index.mjs";
|
|
2
|
+
import { FetchBaseOptions, FetchLanguages } from "../../parsers/helpers.mjs";
|
|
3
|
+
//#region src/fetchers/tree/items.d.ts
|
|
4
|
+
type FetchTreeItemsCategory<TContainedItemCategories extends ReadonlyArray<TreeItemCategory> | undefined> = TContainedItemCategories extends ReadonlyArray<infer U> ? Extract<U, TreeItemCategory> : TreeItemCategory;
|
|
5
|
+
/**
|
|
6
|
+
* Fetches and parses Tree items from the OCHRE API
|
|
7
|
+
*
|
|
8
|
+
* The counterpart of {@link fetchSetItems} for a Tree, and the way to read a
|
|
9
|
+
* Tree too large to fetch whole: a Tree of tens of thousands of items is one
|
|
10
|
+
* OCHRE document, so counting, filtering and sorting run inside it rather than
|
|
11
|
+
* over one document per item.
|
|
12
|
+
*
|
|
13
|
+
* Items nested under headings are returned flat, in document order, because a
|
|
14
|
+
* heading groups items for display rather than identifying them. What the
|
|
15
|
+
* returned items carry is whatever the Tree payload carries: OCHRE publishes
|
|
16
|
+
* Tree items as identification-only stubs unless the Tree is published with
|
|
17
|
+
* item properties, so a `property` query or a `propertyValue` sort only works
|
|
18
|
+
* on a Tree that carries them.
|
|
19
|
+
*
|
|
20
|
+
* @param parameters - The parameters for the fetch
|
|
21
|
+
* @param parameters.treeScopeUuids - The Tree scope UUIDs to filter by
|
|
22
|
+
* @param parameters.queries - Recursive query tree used to filter matching items
|
|
23
|
+
* @param parameters.sort - Optional sorting configuration applied before pagination.
|
|
24
|
+
* For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
|
|
25
|
+
* @param parameters.page - The page number (1-indexed)
|
|
26
|
+
* @param parameters.pageSize - The number of items per page
|
|
27
|
+
* @param containedItemCategories - The categories of the items to fetch
|
|
28
|
+
* @param options - Options for the fetch
|
|
29
|
+
* @param options.fetch - The fetch function to use
|
|
30
|
+
* @returns The parsed Tree items or null if the fetch/parse fails
|
|
31
|
+
*/
|
|
32
|
+
export declare function fetchTreeItems<const TContainedItemCategories extends ReadonlyArray<TreeItemCategory> | undefined = undefined, const TLanguages extends ReadonlyArray<string> | undefined = undefined>(parameters: {
|
|
33
|
+
treeScopeUuids: Array<string>;
|
|
34
|
+
queries?: Query | null;
|
|
35
|
+
sort?: SetItemsSort;
|
|
36
|
+
page: number;
|
|
37
|
+
pageSize?: number;
|
|
38
|
+
}, containedItemCategories?: TContainedItemCategories, options?: FetchBaseOptions<TLanguages>): Promise<{
|
|
39
|
+
totalCount: number;
|
|
40
|
+
page: number;
|
|
41
|
+
pageSize: number;
|
|
42
|
+
items: Array<SetItem<FetchTreeItemsCategory<TContainedItemCategories>, FetchLanguages<TLanguages>>>;
|
|
43
|
+
error: null;
|
|
44
|
+
detailedError: null;
|
|
45
|
+
} | {
|
|
46
|
+
totalCount: null;
|
|
47
|
+
page: null;
|
|
48
|
+
pageSize: null;
|
|
49
|
+
items: null;
|
|
50
|
+
error: string;
|
|
51
|
+
detailedError: string;
|
|
52
|
+
}>;
|
|
53
|
+
//#endregion
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getErrorOutput } from "../../errors.mjs";
|
|
2
|
+
import { treeItemsParametersSchema } from "../../schemas.mjs";
|
|
3
|
+
import { fetchContainerItems } from "../container-items.mjs";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
//#region src/fetchers/tree/items.ts
|
|
6
|
+
async function fetchTreeItems(parameters, containedItemCategories, options) {
|
|
7
|
+
try {
|
|
8
|
+
const { treeScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = v.parse(treeItemsParametersSchema, parameters);
|
|
9
|
+
const { items, ...pagination } = await fetchContainerItems({
|
|
10
|
+
container: "tree",
|
|
11
|
+
scopeUuids: treeScopeUuids,
|
|
12
|
+
belongsToCollectionScopeUuids,
|
|
13
|
+
queries,
|
|
14
|
+
sort,
|
|
15
|
+
page,
|
|
16
|
+
pageSize,
|
|
17
|
+
containedItemCategories,
|
|
18
|
+
label: "OCHRE Tree items",
|
|
19
|
+
options
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
...pagination,
|
|
23
|
+
items,
|
|
24
|
+
error: null,
|
|
25
|
+
detailedError: null
|
|
26
|
+
};
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return {
|
|
29
|
+
totalCount: null,
|
|
30
|
+
page: null,
|
|
31
|
+
pageSize: null,
|
|
32
|
+
items: null,
|
|
33
|
+
...getErrorOutput(error, "Failed to fetch Tree items")
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { fetchTreeItems };
|
package/dist/index.d.mts
CHANGED
|
@@ -9,9 +9,10 @@ import { fetchItemOcrData } from "./fetchers/item-ocr-data.mjs";
|
|
|
9
9
|
import { fetchItem } from "./fetchers/item.mjs";
|
|
10
10
|
import { fetchSetItems } from "./fetchers/set/items.mjs";
|
|
11
11
|
import { fetchSetPropertyValues } from "./fetchers/set/property-values.mjs";
|
|
12
|
+
import { fetchTreeItems } from "./fetchers/tree/items.mjs";
|
|
12
13
|
import { fetchWebsiteMetadata } from "./fetchers/website-metadata.mjs";
|
|
13
14
|
import { fetchWebsite } from "./fetchers/website.mjs";
|
|
14
15
|
import { PropertyOptions, PropertySelector, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel } from "./getters.mjs";
|
|
15
16
|
import { flattenItemProperties } from "./helpers.mjs";
|
|
16
17
|
import { defineLanguages } from "./parsers/languages.mjs";
|
|
17
|
-
export { type AccordionWebBlock, type AnyBibliography, type AnyConcept, type AnyItem, type AnyPeriod, type AnyPerson, type AnyPropertyValue, type AnyPropertyVariable, type AnyResource, type AnySet, type AnySpatialUnit, type AnyText, type AnyTree, type BaseItem, type BaseItemLink, type BelongsTo, type Bibliography, type BibliographyEntryInfo, type BibliographyItemLink, type BibliographySourceDocument, type Concept, type ConceptItemLink, type ContainedItemCategory, type ContainedItemCategoryFromOption, type ContainedItemCategoryOption, type Context, type ContextItem, type ContextItemCategory, type ContextNode, type ContextTree, type ContextTreeFilterLevel, type ContextTreeFilterVariant, type ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource, DEFAULT_PAGE_SIZE, type DictionaryUnitItemLink, type EmbeddedBibliography, type EmbeddedConcept, type EmbeddedItem, type EmbeddedPeriod, type EmbeddedPerson, type EmbeddedPropertyValue, type EmbeddedPropertyVariable, type EmbeddedResource, type EmbeddedSet, type EmbeddedSpatialUnit, type EmbeddedText, type EmbeddedTree, type Event, type Gallery, type Heading, type HeadingItemCategory, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type Item, type ItemCategory, type ItemCategoryFromOption, type ItemCategoryOption, type ItemCategoryWithEmbeddedItems, type ItemContainerCategory, type ItemLink, type ItemLinkCategory, type ItemLinks, type ItemPayloadKind, type ItemProperty, type ItemWithoutEmbeddedItems, type LanguageCodes, type License, type Metadata, type MultilingualOptions, MultilingualString, type MultilingualStringEntries, type MultilingualStringEntry, type MultilingualStringInput, type MultilingualStringJSON, type MultilingualStringObject, type MultilingualStringText, type Note, type Observation, type OcrString, type Period, type PeriodItemLink, type Person, type PersonItemLink, type Property, type PropertyLike, type PropertyOptions, type PropertyRelation, type PropertySelector, type PropertyValue, type PropertyValueContent, type PropertyValueDataType, type PropertyValueItemLink, type PropertyValueQueryItem, type PropertyVariable, type PropertyVariableItemLink, type ProtectedWebsite, type Query, type QueryGroup, type QueryLeaf, type QueryablePropertyValueDataType, type RecursiveItemCategory, type Resource, type ResourceItemLink, type ResponsiveStyles, type Scope, type Section, type Set, type SetAttributeValueQueryItem, type SetBibliography, type SetConcept, type SetItem, type SetItemCategory, type SetItemLink, type SetItemProperty, type SetItemSimplifiedProperty, type SetItemsSort, type SetItemsSortDirection, type SetPeriod, type SetResource, type SetSpatialUnit, type SetTree, type SimplifiedProperty, type SpatialUnit, type SpatialUnitItemLink, type Style, type StylesheetCategory, type StylesheetItem, type Text, type TextItemLink, type TopLevelItem, type Tree, type TreeItemCategory, type TreeItemLink, type WebAccordionItem, type WebBlock, type WebBlockByLayout, type WebBlockItem, type WebBlockLayout, type WebElement, type WebElementComponent, type WebElementComponentName, type WebElementComponentOf, type WebElementOf, type WebIiifViewer, type WebImage, type WebLoadingVariant, type WebOptions, type WebSectionDisplay, type WebSectionVariant, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePrivacy, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, flattenItemProperties, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel };
|
|
18
|
+
export { type AccordionWebBlock, type AnyBibliography, type AnyConcept, type AnyItem, type AnyPeriod, type AnyPerson, type AnyPropertyValue, type AnyPropertyVariable, type AnyResource, type AnySet, type AnySpatialUnit, type AnyText, type AnyTree, type BaseItem, type BaseItemLink, type BelongsTo, type Bibliography, type BibliographyEntryInfo, type BibliographyItemLink, type BibliographySourceDocument, type Concept, type ConceptItemLink, type ContainedItemCategory, type ContainedItemCategoryFromOption, type ContainedItemCategoryOption, type Context, type ContextItem, type ContextItemCategory, type ContextNode, type ContextTree, type ContextTreeFilterLevel, type ContextTreeFilterVariant, type ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource, DEFAULT_PAGE_SIZE, type DictionaryUnitItemLink, type EmbeddedBibliography, type EmbeddedConcept, type EmbeddedItem, type EmbeddedPeriod, type EmbeddedPerson, type EmbeddedPropertyValue, type EmbeddedPropertyVariable, type EmbeddedResource, type EmbeddedSet, type EmbeddedSpatialUnit, type EmbeddedText, type EmbeddedTree, type Event, type Gallery, type Heading, type HeadingItemCategory, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type Item, type ItemCategory, type ItemCategoryFromOption, type ItemCategoryOption, type ItemCategoryWithEmbeddedItems, type ItemContainerCategory, type ItemLink, type ItemLinkCategory, type ItemLinks, type ItemPayloadKind, type ItemProperty, type ItemWithoutEmbeddedItems, type LanguageCodes, type License, type Metadata, type MultilingualOptions, MultilingualString, type MultilingualStringEntries, type MultilingualStringEntry, type MultilingualStringInput, type MultilingualStringJSON, type MultilingualStringObject, type MultilingualStringText, type Note, type Observation, type OcrString, type Period, type PeriodItemLink, type Person, type PersonItemLink, type Property, type PropertyLike, type PropertyOptions, type PropertyRelation, type PropertySelector, type PropertyValue, type PropertyValueContent, type PropertyValueDataType, type PropertyValueItemLink, type PropertyValueQueryItem, type PropertyVariable, type PropertyVariableItemLink, type ProtectedWebsite, type Query, type QueryGroup, type QueryLeaf, type QueryablePropertyValueDataType, type RecursiveItemCategory, type Resource, type ResourceItemLink, type ResponsiveStyles, type Scope, type Section, type Set, type SetAttributeValueQueryItem, type SetBibliography, type SetConcept, type SetItem, type SetItemCategory, type SetItemLink, type SetItemProperty, type SetItemSimplifiedProperty, type SetItemsSort, type SetItemsSortDirection, type SetPeriod, type SetResource, type SetSpatialUnit, type SetTree, type SimplifiedProperty, type SpatialUnit, type SpatialUnitItemLink, type Style, type StylesheetCategory, type StylesheetItem, type Text, type TextItemLink, type TopLevelItem, type Tree, type TreeItemCategory, type TreeItemLink, type WebAccordionItem, type WebBlock, type WebBlockByLayout, type WebBlockItem, type WebBlockLayout, type WebElement, type WebElementComponent, type WebElementComponentName, type WebElementComponentOf, type WebElementOf, type WebIiifViewer, type WebImage, type WebLoadingVariant, type WebOptions, type WebSectionDisplay, type WebSectionVariant, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePrivacy, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItems, fetchSetPropertyValues, fetchTreeItems, fetchWebsite, fetchWebsiteMetadata, flattenItemProperties, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel };
|
package/dist/index.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { fetchItemOcrData } from "./fetchers/item-ocr-data.mjs";
|
|
|
10
10
|
import { fetchItem } from "./fetchers/item.mjs";
|
|
11
11
|
import { fetchSetItems } from "./fetchers/set/items.mjs";
|
|
12
12
|
import { fetchSetPropertyValues } from "./fetchers/set/property-values.mjs";
|
|
13
|
+
import { fetchTreeItems } from "./fetchers/tree/items.mjs";
|
|
13
14
|
import { fetchWebsiteMetadata } from "./fetchers/website-metadata.mjs";
|
|
14
15
|
import { fetchWebsite } from "./fetchers/website.mjs";
|
|
15
|
-
export { DEFAULT_PAGE_SIZE, MultilingualString, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, flattenItemProperties, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel };
|
|
16
|
+
export { DEFAULT_PAGE_SIZE, MultilingualString, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItems, fetchSetPropertyValues, fetchTreeItems, fetchWebsite, fetchWebsiteMetadata, flattenItemProperties, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel };
|
package/dist/query.d.mts
CHANGED
|
@@ -2,12 +2,38 @@ import { PropertyRelation, Query } from "./types/index.mjs";
|
|
|
2
2
|
import { OchreQueryContext } from "./xquery.mjs";
|
|
3
3
|
//#region src/query.d.ts
|
|
4
4
|
export declare function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids: ReadonlyArray<string>, belongsToCollectionPropertyVariableUuid: string): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* The scope variable and searchable path of each item container
|
|
7
|
+
*
|
|
8
|
+
* A path has to stay inline in `cts:search`: binding it to a variable first
|
|
9
|
+
* materializes the sequence and makes every query `XDMP-UNSEARCHABLE`, even a
|
|
10
|
+
* plain word query. Each references its own scope variable, which
|
|
11
|
+
* {@link compileContainerItemsQuery} declares.
|
|
12
|
+
*
|
|
13
|
+
* A Tree nests its items under headings to any depth, so its path walks the
|
|
14
|
+
* descendant axis and then keeps only the nodes a heading or `items` holds
|
|
15
|
+
* directly, which is what distinguishes an item from the elements inside one.
|
|
16
|
+
* Excluding `heading` matters twice: a heading is not an item, and searching
|
|
17
|
+
* over headings would match every item under a heading whose own text matches.
|
|
18
|
+
* The union form `items/(* | heading/*)` is deliberately not used, because
|
|
19
|
+
* MarkLogic rejects a union as `XDMP-UNSEARCHABLE`.
|
|
20
|
+
*/
|
|
21
|
+
declare const ITEMS_CONTAINERS: {
|
|
22
|
+
readonly set: {
|
|
23
|
+
readonly scopeVariable: "$setScopeUuids";
|
|
24
|
+
readonly itemsExpression: "doc()/ochre/set[@uuid = $setScopeUuids]/items/*";
|
|
25
|
+
};
|
|
26
|
+
readonly tree: {
|
|
27
|
+
readonly scopeVariable: "$treeScopeUuids";
|
|
28
|
+
readonly itemsExpression: "doc()/ochre/tree[@uuid = $treeScopeUuids]/items/descendant::*[not(self::heading)][parent::items or parent::heading]";
|
|
29
|
+
};
|
|
30
|
+
};
|
|
5
31
|
/**
|
|
6
32
|
* Compile a query tree into the clauses that bind the matching Set items
|
|
7
33
|
*
|
|
8
34
|
* The returned `itemsClause` binds {@link ITEMS_VARIABLE} and has to be placed
|
|
9
35
|
* inside an XQuery body, with `prolog` declared ahead of it.
|
|
10
|
-
* {@link
|
|
36
|
+
* {@link compileContainerItemsQuery} does both and is what fetchers should use;
|
|
11
37
|
* this is exposed for tests that assert on the compiled CTS.
|
|
12
38
|
* @param parameters - The plan parameters
|
|
13
39
|
* @param parameters.queries - The query tree to compile, or null to match every item
|
|
@@ -30,15 +56,21 @@ export declare function buildQueryPlan(parameters: {
|
|
|
30
56
|
}>;
|
|
31
57
|
};
|
|
32
58
|
/**
|
|
33
|
-
*
|
|
59
|
+
* The OCHRE item containers a paginated item query can run over
|
|
60
|
+
*/
|
|
61
|
+
export type ItemsContainer = keyof typeof ITEMS_CONTAINERS;
|
|
62
|
+
/**
|
|
63
|
+
* Compile an item query over a Set or a Tree into a complete XQuery document
|
|
34
64
|
*
|
|
35
65
|
* Owns everything a caller would otherwise have to know and restate: the
|
|
36
|
-
* version declaration, the
|
|
37
|
-
*
|
|
38
|
-
* that it is only declared when non-empty, the `<ochre>`
|
|
39
|
-
* of the variable holding the matching items. The body
|
|
66
|
+
* version declaration, the scope variable, the supplemental-stripping prolog,
|
|
67
|
+
* the inline searchable path for the container, where the compiled helper
|
|
68
|
+
* prolog goes and that it is only declared when non-empty, the `<ochre>`
|
|
69
|
+
* wrapper, and the name of the variable holding the matching items. The body
|
|
70
|
+
* receives that name, so it is identical for either container.
|
|
40
71
|
* @param parameters - The query parameters
|
|
41
|
-
* @param parameters.
|
|
72
|
+
* @param parameters.container - Whether the scope UUIDs name Sets or Trees
|
|
73
|
+
* @param parameters.scopeUuids - The container UUIDs to search within
|
|
42
74
|
* @param parameters.belongsToCollectionScopeUuids - Collection scope UUIDs to narrow to
|
|
43
75
|
* @param parameters.queries - The query tree to compile, or null to match every item
|
|
44
76
|
* @param parameters.declarations - Extra prolog declarations, placed before the compiled prolog
|
|
@@ -46,8 +78,9 @@ export declare function buildQueryPlan(parameters: {
|
|
|
46
78
|
* @returns A complete XQuery document
|
|
47
79
|
* @internal
|
|
48
80
|
*/
|
|
49
|
-
export declare function
|
|
50
|
-
|
|
81
|
+
export declare function compileContainerItemsQuery(parameters: {
|
|
82
|
+
container: ItemsContainer;
|
|
83
|
+
scopeUuids: ReadonlyArray<string>;
|
|
51
84
|
belongsToCollectionScopeUuids: ReadonlyArray<string>;
|
|
52
85
|
queries: Query | null;
|
|
53
86
|
declarations?: ReadonlyArray<string>;
|
package/dist/query.mjs
CHANGED
|
@@ -1111,22 +1111,38 @@ function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids,
|
|
|
1111
1111
|
* @returns The prolog declaring the query helpers, and the `let` clauses binding `$items`
|
|
1112
1112
|
*/
|
|
1113
1113
|
const ITEMS_VARIABLE = "$items";
|
|
1114
|
-
const SET_SCOPE_VARIABLE = "$setScopeUuids";
|
|
1115
1114
|
/**
|
|
1116
|
-
* The
|
|
1115
|
+
* The scope variable and searchable path of each item container
|
|
1117
1116
|
*
|
|
1118
|
-
*
|
|
1117
|
+
* A path has to stay inline in `cts:search`: binding it to a variable first
|
|
1119
1118
|
* materializes the sequence and makes every query `XDMP-UNSEARCHABLE`, even a
|
|
1120
|
-
* plain word query.
|
|
1121
|
-
* {@link
|
|
1119
|
+
* plain word query. Each references its own scope variable, which
|
|
1120
|
+
* {@link compileContainerItemsQuery} declares.
|
|
1121
|
+
*
|
|
1122
|
+
* A Tree nests its items under headings to any depth, so its path walks the
|
|
1123
|
+
* descendant axis and then keeps only the nodes a heading or `items` holds
|
|
1124
|
+
* directly, which is what distinguishes an item from the elements inside one.
|
|
1125
|
+
* Excluding `heading` matters twice: a heading is not an item, and searching
|
|
1126
|
+
* over headings would match every item under a heading whose own text matches.
|
|
1127
|
+
* The union form `items/(* | heading/*)` is deliberately not used, because
|
|
1128
|
+
* MarkLogic rejects a union as `XDMP-UNSEARCHABLE`.
|
|
1122
1129
|
*/
|
|
1123
|
-
const
|
|
1130
|
+
const ITEMS_CONTAINERS = {
|
|
1131
|
+
set: {
|
|
1132
|
+
scopeVariable: "$setScopeUuids",
|
|
1133
|
+
itemsExpression: "doc()/ochre/set[@uuid = $setScopeUuids]/items/*"
|
|
1134
|
+
},
|
|
1135
|
+
tree: {
|
|
1136
|
+
scopeVariable: "$treeScopeUuids",
|
|
1137
|
+
itemsExpression: "doc()/ochre/tree[@uuid = $treeScopeUuids]/items/descendant::*[not(self::heading)][parent::items or parent::heading]"
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1124
1140
|
/**
|
|
1125
1141
|
* Compile a query tree into the clauses that bind the matching Set items
|
|
1126
1142
|
*
|
|
1127
1143
|
* The returned `itemsClause` binds {@link ITEMS_VARIABLE} and has to be placed
|
|
1128
1144
|
* inside an XQuery body, with `prolog` declared ahead of it.
|
|
1129
|
-
* {@link
|
|
1145
|
+
* {@link compileContainerItemsQuery} does both and is what fetchers should use;
|
|
1130
1146
|
* this is exposed for tests that assert on the compiled CTS.
|
|
1131
1147
|
* @param parameters - The plan parameters
|
|
1132
1148
|
* @param parameters.queries - The query tree to compile, or null to match every item
|
|
@@ -1178,15 +1194,17 @@ function buildQueryPlan(parameters) {
|
|
|
1178
1194
|
};
|
|
1179
1195
|
}
|
|
1180
1196
|
/**
|
|
1181
|
-
* Compile a Set
|
|
1197
|
+
* Compile an item query over a Set or a Tree into a complete XQuery document
|
|
1182
1198
|
*
|
|
1183
1199
|
* Owns everything a caller would otherwise have to know and restate: the
|
|
1184
|
-
* version declaration, the
|
|
1185
|
-
*
|
|
1186
|
-
* that it is only declared when non-empty, the `<ochre>`
|
|
1187
|
-
* of the variable holding the matching items. The body
|
|
1200
|
+
* version declaration, the scope variable, the supplemental-stripping prolog,
|
|
1201
|
+
* the inline searchable path for the container, where the compiled helper
|
|
1202
|
+
* prolog goes and that it is only declared when non-empty, the `<ochre>`
|
|
1203
|
+
* wrapper, and the name of the variable holding the matching items. The body
|
|
1204
|
+
* receives that name, so it is identical for either container.
|
|
1188
1205
|
* @param parameters - The query parameters
|
|
1189
|
-
* @param parameters.
|
|
1206
|
+
* @param parameters.container - Whether the scope UUIDs name Sets or Trees
|
|
1207
|
+
* @param parameters.scopeUuids - The container UUIDs to search within
|
|
1190
1208
|
* @param parameters.belongsToCollectionScopeUuids - Collection scope UUIDs to narrow to
|
|
1191
1209
|
* @param parameters.queries - The query tree to compile, or null to match every item
|
|
1192
1210
|
* @param parameters.declarations - Extra prolog declarations, placed before the compiled prolog
|
|
@@ -1194,17 +1212,18 @@ function buildQueryPlan(parameters) {
|
|
|
1194
1212
|
* @returns A complete XQuery document
|
|
1195
1213
|
* @internal
|
|
1196
1214
|
*/
|
|
1197
|
-
function
|
|
1198
|
-
const {
|
|
1215
|
+
function compileContainerItemsQuery(parameters) {
|
|
1216
|
+
const { container, scopeUuids, belongsToCollectionScopeUuids, queries, declarations = [], body } = parameters;
|
|
1217
|
+
const { scopeVariable, itemsExpression } = ITEMS_CONTAINERS[container];
|
|
1199
1218
|
const plan = buildQueryPlan({
|
|
1200
1219
|
queries,
|
|
1201
|
-
baseItemsExpression:
|
|
1220
|
+
baseItemsExpression: itemsExpression,
|
|
1202
1221
|
scopeQueryExpression: buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids, BELONGS_TO_COLLECTION_UUID)
|
|
1203
1222
|
});
|
|
1204
1223
|
return compileOchreQuery({
|
|
1205
1224
|
declarations: [
|
|
1206
1225
|
...declarations,
|
|
1207
|
-
`declare variable ${
|
|
1226
|
+
`declare variable ${scopeVariable} := (${Array.from(scopeUuids, (uuid) => stringLiteral(uuid)).join(", ")});`,
|
|
1208
1227
|
...plan.prolog === "" ? [] : [plan.prolog]
|
|
1209
1228
|
],
|
|
1210
1229
|
body: (context) => `<ochre>{
|
|
@@ -1268,4 +1287,4 @@ function getPropertyFacetSelectors(queries) {
|
|
|
1268
1287
|
return selectors.values().toArray();
|
|
1269
1288
|
}
|
|
1270
1289
|
//#endregion
|
|
1271
|
-
export { buildBelongsToCollectionQueryExpression, buildQueryPlan,
|
|
1290
|
+
export { buildBelongsToCollectionQueryExpression, buildQueryPlan, compileContainerItemsQuery, getItemFilterQueries, getPropertyFacetSelectors };
|
package/dist/schemas.d.mts
CHANGED
|
@@ -65,12 +65,32 @@ export declare const itemOcrDataParametersSchema: v.ObjectSchema<{
|
|
|
65
65
|
readonly matchMode: v.OptionalSchema<v.PicklistSchema<["includes", "exact"], undefined>, "includes">;
|
|
66
66
|
readonly isCaseSensitive: v.GenericSchema<unknown, boolean>;
|
|
67
67
|
}, undefined>;
|
|
68
|
-
/**
|
|
69
|
-
* Schema for validating Set items parameters
|
|
70
|
-
* @internal
|
|
71
|
-
*/
|
|
72
68
|
export declare const setItemsParametersSchema: v.ObjectSchema<{
|
|
69
|
+
readonly belongsToCollectionScopeUuids: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, readonly []>;
|
|
70
|
+
readonly queries: v.OptionalSchema<v.NullableSchema<v.GenericSchema<unknown, Query>, undefined>, null>;
|
|
71
|
+
readonly sort: v.OptionalSchema<v.VariantSchema<"target", [v.StrictObjectSchema<{
|
|
72
|
+
readonly target: v.LiteralSchema<"none", undefined>;
|
|
73
|
+
}, undefined>, v.StrictObjectSchema<{
|
|
74
|
+
readonly target: v.LiteralSchema<"title", undefined>;
|
|
75
|
+
readonly direction: v.OptionalSchema<v.PicklistSchema<["asc", "desc"], undefined>, "asc">;
|
|
76
|
+
readonly language: v.GenericSchema<unknown, string>;
|
|
77
|
+
}, undefined>, v.StrictObjectSchema<{
|
|
78
|
+
readonly target: v.LiteralSchema<"date", undefined>;
|
|
79
|
+
readonly direction: v.OptionalSchema<v.PicklistSchema<["asc", "desc"], undefined>, "asc">;
|
|
80
|
+
}, undefined>, v.StrictObjectSchema<{
|
|
81
|
+
readonly target: v.LiteralSchema<"propertyValue", undefined>;
|
|
82
|
+
readonly propertyVariableUuid: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>;
|
|
83
|
+
readonly dataType: v.PicklistSchema<readonly ["string", "integer", "decimal", "boolean", "date", "dateTime", "time", "IDREF"], undefined>;
|
|
84
|
+
readonly direction: v.OptionalSchema<v.PicklistSchema<["asc", "desc"], undefined>, "asc">;
|
|
85
|
+
readonly language: v.GenericSchema<unknown, string>;
|
|
86
|
+
}, undefined>], undefined>, {
|
|
87
|
+
readonly target: "none";
|
|
88
|
+
}>;
|
|
89
|
+
readonly page: v.OptionalSchema<v.GenericSchema<unknown, number>, 1>;
|
|
90
|
+
readonly pageSize: v.OptionalSchema<v.GenericSchema<unknown, number>, 48>;
|
|
73
91
|
readonly setScopeUuids: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, v.MinLengthAction<string[], 1, "At least one set scope UUID is required">]>;
|
|
92
|
+
}, undefined>;
|
|
93
|
+
export declare const treeItemsParametersSchema: v.ObjectSchema<{
|
|
74
94
|
readonly belongsToCollectionScopeUuids: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, readonly []>;
|
|
75
95
|
readonly queries: v.OptionalSchema<v.NullableSchema<v.GenericSchema<unknown, Query>, undefined>, null>;
|
|
76
96
|
readonly sort: v.OptionalSchema<v.VariantSchema<"target", [v.StrictObjectSchema<{
|
|
@@ -79,6 +99,9 @@ export declare const setItemsParametersSchema: v.ObjectSchema<{
|
|
|
79
99
|
readonly target: v.LiteralSchema<"title", undefined>;
|
|
80
100
|
readonly direction: v.OptionalSchema<v.PicklistSchema<["asc", "desc"], undefined>, "asc">;
|
|
81
101
|
readonly language: v.GenericSchema<unknown, string>;
|
|
102
|
+
}, undefined>, v.StrictObjectSchema<{
|
|
103
|
+
readonly target: v.LiteralSchema<"date", undefined>;
|
|
104
|
+
readonly direction: v.OptionalSchema<v.PicklistSchema<["asc", "desc"], undefined>, "asc">;
|
|
82
105
|
}, undefined>, v.StrictObjectSchema<{
|
|
83
106
|
readonly target: v.LiteralSchema<"propertyValue", undefined>;
|
|
84
107
|
readonly propertyVariableUuid: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>;
|
|
@@ -90,5 +113,6 @@ export declare const setItemsParametersSchema: v.ObjectSchema<{
|
|
|
90
113
|
}>;
|
|
91
114
|
readonly page: v.OptionalSchema<v.GenericSchema<unknown, number>, 1>;
|
|
92
115
|
readonly pageSize: v.OptionalSchema<v.GenericSchema<unknown, number>, 48>;
|
|
116
|
+
readonly treeScopeUuids: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, v.MinLengthAction<string[], 1, "At least one tree scope UUID is required">]>;
|
|
93
117
|
}, undefined>;
|
|
94
118
|
//#endregion
|
package/dist/schemas.mjs
CHANGED
|
@@ -195,6 +195,10 @@ const setItemsSortSchema = v.optional(v.variant("target", [
|
|
|
195
195
|
direction: sortDirectionSchema,
|
|
196
196
|
language: defaultString("eng")
|
|
197
197
|
}),
|
|
198
|
+
v.strictObject({
|
|
199
|
+
target: v.literal("date"),
|
|
200
|
+
direction: sortDirectionSchema
|
|
201
|
+
}),
|
|
198
202
|
v.strictObject({
|
|
199
203
|
target: v.literal("propertyValue"),
|
|
200
204
|
propertyVariableUuid: uuidSchema,
|
|
@@ -243,13 +247,20 @@ const itemOcrDataParametersSchema = v.object({
|
|
|
243
247
|
* Schema for validating Set items parameters
|
|
244
248
|
* @internal
|
|
245
249
|
*/
|
|
246
|
-
const
|
|
247
|
-
setScopeUuids: v.pipe(v.array(uuidSchema), v.minLength(1, "At least one set scope UUID is required")),
|
|
250
|
+
const containerItemsParametersEntries = {
|
|
248
251
|
belongsToCollectionScopeUuids: v.optional(v.array(uuidSchema), []),
|
|
249
252
|
queries: setQueriesSchema,
|
|
250
253
|
sort: setItemsSortSchema,
|
|
251
254
|
page: v.optional(positiveNumber("Page must be positive"), 1),
|
|
252
255
|
pageSize: v.optional(positiveNumber("Page size must be positive"), 48)
|
|
256
|
+
};
|
|
257
|
+
const setItemsParametersSchema = v.object({
|
|
258
|
+
setScopeUuids: v.pipe(v.array(uuidSchema), v.minLength(1, "At least one set scope UUID is required")),
|
|
259
|
+
...containerItemsParametersEntries
|
|
260
|
+
});
|
|
261
|
+
const treeItemsParametersSchema = v.object({
|
|
262
|
+
treeScopeUuids: v.pipe(v.array(uuidSchema), v.minLength(1, "At least one tree scope UUID is required")),
|
|
263
|
+
...containerItemsParametersEntries
|
|
253
264
|
});
|
|
254
265
|
//#endregion
|
|
255
|
-
export { componentSchema, gallerySchema, isPseudoUuid, iso639_3Schema, itemOcrDataParametersSchema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
|
|
266
|
+
export { componentSchema, gallerySchema, isPseudoUuid, iso639_3Schema, itemOcrDataParametersSchema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, treeItemsParametersSchema, uuidSchema };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -779,6 +779,15 @@ export type SetItemsSort = {
|
|
|
779
779
|
target: "title";
|
|
780
780
|
direction?: SetItemsSortDirection;
|
|
781
781
|
language?: string;
|
|
782
|
+
} |
|
|
783
|
+
/**
|
|
784
|
+
* Sort on the item's own date, falling back to its first interpretation's
|
|
785
|
+
* date. A Concept carries no date of its own and dates its interpretations
|
|
786
|
+
* instead, so the two together are the one date an item has.
|
|
787
|
+
*/
|
|
788
|
+
{
|
|
789
|
+
target: "date";
|
|
790
|
+
direction?: SetItemsSortDirection;
|
|
782
791
|
} | {
|
|
783
792
|
target: "propertyValue";
|
|
784
793
|
propertyVariableUuid: string;
|
package/dist/xml/schemas.d.mts
CHANGED
|
@@ -1816,7 +1816,7 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
1816
1816
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
1817
1817
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
1818
1818
|
}, "XMLString: Shape error">], undefined>, undefined>, undefined>;
|
|
1819
|
-
readonly identification: v.OptionalSchema<v.ObjectSchema<{
|
|
1819
|
+
readonly identification: v.OptionalSchema<v.OptionalSchema<v.ObjectSchema<{
|
|
1820
1820
|
readonly label: v.UnionSchema<[v.ObjectSchema<{
|
|
1821
1821
|
readonly content: v.ArraySchema<v.ObjectSchema<{
|
|
1822
1822
|
readonly links: v.OptionalSchema<v.LazySchema<v.GenericSchema<unknown, XMLLink$1>>, undefined>;
|
|
@@ -1914,7 +1914,11 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
1914
1914
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
1915
1915
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
1916
1916
|
}, "XMLString: Shape error">, v.StringSchema<"XMLIdentification: website is string and optional">], undefined>, undefined>;
|
|
1917
|
-
}, "XMLIdentification: Shape error">,
|
|
1917
|
+
}, "XMLIdentification: Shape error">, {
|
|
1918
|
+
readonly label: {
|
|
1919
|
+
readonly content: readonly [];
|
|
1920
|
+
};
|
|
1921
|
+
}>, undefined>;
|
|
1918
1922
|
readonly context: v.OptionalSchema<v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.ObjectSchema<{
|
|
1919
1923
|
readonly context: v.ArraySchema<v.UnionSchema<[v.ObjectWithRestSchema<{
|
|
1920
1924
|
readonly project: v.ObjectSchema<{
|
|
@@ -2213,7 +2217,7 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
2213
2217
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
2214
2218
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
2215
2219
|
}, "XMLString: Shape error">], undefined>, undefined>;
|
|
2216
|
-
readonly identification: v.ObjectSchema<{
|
|
2220
|
+
readonly identification: v.OptionalSchema<v.ObjectSchema<{
|
|
2217
2221
|
readonly label: v.UnionSchema<[v.ObjectSchema<{
|
|
2218
2222
|
readonly content: v.ArraySchema<v.ObjectSchema<{
|
|
2219
2223
|
readonly links: v.OptionalSchema<v.LazySchema<v.GenericSchema<unknown, XMLLink$1>>, undefined>;
|
|
@@ -2311,7 +2315,11 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
2311
2315
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
2312
2316
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
2313
2317
|
}, "XMLString: Shape error">, v.StringSchema<"XMLIdentification: website is string and optional">], undefined>, undefined>;
|
|
2314
|
-
}, "XMLIdentification: Shape error"
|
|
2318
|
+
}, "XMLIdentification: Shape error">, {
|
|
2319
|
+
readonly label: {
|
|
2320
|
+
readonly content: readonly [];
|
|
2321
|
+
};
|
|
2322
|
+
}>;
|
|
2315
2323
|
readonly context: v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.ObjectSchema<{
|
|
2316
2324
|
readonly context: v.ArraySchema<v.UnionSchema<[v.ObjectWithRestSchema<{
|
|
2317
2325
|
readonly project: v.ObjectSchema<{
|
|
@@ -2961,7 +2969,7 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
2961
2969
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
2962
2970
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
2963
2971
|
}, "XMLString: Shape error">], undefined>, undefined>, undefined>;
|
|
2964
|
-
readonly identification: v.OptionalSchema<v.ObjectSchema<{
|
|
2972
|
+
readonly identification: v.OptionalSchema<v.OptionalSchema<v.ObjectSchema<{
|
|
2965
2973
|
readonly label: v.UnionSchema<[v.ObjectSchema<{
|
|
2966
2974
|
readonly content: v.ArraySchema<v.ObjectSchema<{
|
|
2967
2975
|
readonly links: v.OptionalSchema<v.LazySchema<v.GenericSchema<unknown, XMLLink$1>>, undefined>;
|
|
@@ -3059,7 +3067,11 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
3059
3067
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
3060
3068
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
3061
3069
|
}, "XMLString: Shape error">, v.StringSchema<"XMLIdentification: website is string and optional">], undefined>, undefined>;
|
|
3062
|
-
}, "XMLIdentification: Shape error">,
|
|
3070
|
+
}, "XMLIdentification: Shape error">, {
|
|
3071
|
+
readonly label: {
|
|
3072
|
+
readonly content: readonly [];
|
|
3073
|
+
};
|
|
3074
|
+
}>, undefined>;
|
|
3063
3075
|
readonly context: v.OptionalSchema<v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.ObjectSchema<{
|
|
3064
3076
|
readonly context: v.ArraySchema<v.UnionSchema<[v.ObjectWithRestSchema<{
|
|
3065
3077
|
readonly project: v.ObjectSchema<{
|
|
@@ -3351,7 +3363,7 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
3351
3363
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
3352
3364
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
3353
3365
|
}, "XMLString: Shape error">], undefined>, undefined>;
|
|
3354
|
-
readonly identification: v.ObjectSchema<{
|
|
3366
|
+
readonly identification: v.OptionalSchema<v.ObjectSchema<{
|
|
3355
3367
|
readonly label: v.UnionSchema<[v.ObjectSchema<{
|
|
3356
3368
|
readonly content: v.ArraySchema<v.ObjectSchema<{
|
|
3357
3369
|
readonly links: v.OptionalSchema<v.LazySchema<v.GenericSchema<unknown, XMLLink$1>>, undefined>;
|
|
@@ -3449,7 +3461,11 @@ export declare const XMLGalleryData: v.ObjectSchema<{
|
|
|
3449
3461
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
3450
3462
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
3451
3463
|
}, "XMLString: Shape error">, v.StringSchema<"XMLIdentification: website is string and optional">], undefined>, undefined>;
|
|
3452
|
-
}, "XMLIdentification: Shape error"
|
|
3464
|
+
}, "XMLIdentification: Shape error">, {
|
|
3465
|
+
readonly label: {
|
|
3466
|
+
readonly content: readonly [];
|
|
3467
|
+
};
|
|
3468
|
+
}>;
|
|
3453
3469
|
readonly context: v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.ObjectSchema<{
|
|
3454
3470
|
readonly context: v.ArraySchema<v.UnionSchema<[v.ObjectWithRestSchema<{
|
|
3455
3471
|
readonly project: v.ObjectSchema<{
|
|
@@ -5668,7 +5684,7 @@ export declare const XMLWebsiteData: v.ObjectSchema<{
|
|
|
5668
5684
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
5669
5685
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
5670
5686
|
}, "XMLString: Shape error">], undefined>, undefined>;
|
|
5671
|
-
readonly identification: v.ObjectSchema<{
|
|
5687
|
+
readonly identification: v.OptionalSchema<v.ObjectSchema<{
|
|
5672
5688
|
readonly label: v.UnionSchema<[v.ObjectSchema<{
|
|
5673
5689
|
readonly content: v.ArraySchema<v.ObjectSchema<{
|
|
5674
5690
|
readonly links: v.OptionalSchema<v.LazySchema<v.GenericSchema<unknown, XMLLink$1>>, undefined>;
|
|
@@ -5766,7 +5782,11 @@ export declare const XMLWebsiteData: v.ObjectSchema<{
|
|
|
5766
5782
|
rend: v.OptionalSchema<v.StringSchema<"XMLString: rend is string and optional">, undefined>;
|
|
5767
5783
|
whitespace: v.OptionalSchema<v.StringSchema<"XMLString: whitespace is string and optional">, undefined>;
|
|
5768
5784
|
}, "XMLString: Shape error">, v.StringSchema<"XMLIdentification: website is string and optional">], undefined>, undefined>;
|
|
5769
|
-
}, "XMLIdentification: Shape error"
|
|
5785
|
+
}, "XMLIdentification: Shape error">, {
|
|
5786
|
+
readonly label: {
|
|
5787
|
+
readonly content: readonly [];
|
|
5788
|
+
};
|
|
5789
|
+
}>;
|
|
5770
5790
|
readonly context: v.OptionalSchema<v.ArraySchema<v.UnionSchema<[v.ObjectSchema<{
|
|
5771
5791
|
readonly context: v.ArraySchema<v.UnionSchema<[v.ObjectWithRestSchema<{
|
|
5772
5792
|
readonly project: v.ObjectSchema<{
|
package/dist/xml/schemas.mjs
CHANGED
|
@@ -286,7 +286,7 @@ const XMLBaseItem = v.object({
|
|
|
286
286
|
availability: v.optional(v.object({ license: XMLLicense })),
|
|
287
287
|
copyright: v.optional(v.union([XMLContent, XMLString])),
|
|
288
288
|
watermark: v.optional(v.union([XMLContent, XMLString])),
|
|
289
|
-
identification: XMLIdentification,
|
|
289
|
+
identification: v.optional(XMLIdentification, { label: { content: [] } }),
|
|
290
290
|
context: v.optional(XMLContext),
|
|
291
291
|
creators: v.optional(v.object({ creator: v.array(v.lazy(() => XMLPerson)) }, "XMLBaseItem: creators is object with creator array of XMLPerson")),
|
|
292
292
|
description: v.optional(XMLContent),
|
|
@@ -402,7 +402,8 @@ const XMLHeading = v.intersect([v.object({
|
|
|
402
402
|
v.optional(v.object({ propertyValue: v.array(v.lazy(() => XMLPropertyValue)) })),
|
|
403
403
|
v.optional(v.object({ resource: v.array(v.union([v.lazy(() => XMLResource), v.object({ resource: v.array(v.lazy(() => XMLResource)) })])) })),
|
|
404
404
|
v.optional(v.object({ text: v.array(v.lazy(() => XMLText)) })),
|
|
405
|
-
v.optional(v.object({ set: v.array(v.lazy(() => XMLSet)) }))
|
|
405
|
+
v.optional(v.object({ set: v.array(v.lazy(() => XMLSet)) })),
|
|
406
|
+
v.object({})
|
|
406
407
|
])]);
|
|
407
408
|
const XMLTree = v.object({
|
|
408
409
|
...XMLBaseItem.entries,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ochre-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",
|
|
@@ -47,18 +47,18 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"fast-equals": "^6.0.3",
|
|
49
49
|
"fast-xml-parser": "^5.11.1",
|
|
50
|
-
"valibot": "^1.
|
|
50
|
+
"valibot": "^1.5.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@antfu/eslint-config": "^9.5.1",
|
|
54
|
-
"@types/node": "^24.13.
|
|
54
|
+
"@types/node": "^24.13.4",
|
|
55
55
|
"bumpp": "^12.3.0",
|
|
56
|
-
"eslint": "^10.
|
|
56
|
+
"eslint": "^10.10.0",
|
|
57
57
|
"eslint-plugin-erasable-syntax-only": "^0.7.1",
|
|
58
58
|
"eslint-plugin-slop": "^0.1.3",
|
|
59
59
|
"eslint-plugin-sonarjs": "^4.2.0",
|
|
60
|
-
"knip": "^6.
|
|
61
|
-
"oxfmt": "^0.
|
|
60
|
+
"knip": "^6.35.1",
|
|
61
|
+
"oxfmt": "^0.67.0",
|
|
62
62
|
"tsdown": "^0.23.0",
|
|
63
63
|
"typescript": "^6.0.3",
|
|
64
64
|
"vitest": "^5.0.0"
|