ochre-sdk 1.0.72 → 1.0.73
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 +22 -0
- package/dist/constants.mjs +0 -5
- package/dist/fetchers/gallery.mjs +11 -5
- package/dist/fetchers/item-children.mjs +4 -2
- package/dist/fetchers/item-links.mjs +10 -5
- package/dist/fetchers/item-ocr-data.d.mts +37 -0
- package/dist/fetchers/item-ocr-data.mjs +166 -0
- package/dist/fetchers/item.mjs +43 -58
- package/dist/fetchers/set/items.mjs +26 -12
- package/dist/fetchers/set/property-values.mjs +24 -14
- package/dist/fetchers/website-metadata.mjs +7 -3
- package/dist/fetchers/website.mjs +20 -3
- package/dist/helpers.d.mts +1 -5
- package/dist/helpers.mjs +1 -5
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/parsers/index.d.mts +3 -10
- package/dist/parsers/index.mjs +1 -75
- package/dist/query.d.mts +19 -28
- package/dist/query.mjs +104 -86
- package/dist/schemas.d.mts +7 -8
- package/dist/schemas.mjs +8 -10
- package/dist/types/index.d.mts +27 -57
- package/dist/utilities.d.mts +25 -1
- package/dist/utilities.mjs +41 -1
- package/dist/xml/schemas.d.mts +2 -7
- package/dist/xml/schemas.mjs +1 -39
- package/dist/xml/types.d.mts +1 -44
- package/package.json +2 -2
- package/dist/fetchers/ocr-matches.d.mts +0 -44
- package/dist/fetchers/ocr-matches.mjs +0 -134
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { XML_PARSER_OPTIONS } from "../constants.mjs";
|
|
2
|
-
import { createSchemaValidationError, getErrorOutput, stringLiteral } from "../utilities.mjs";
|
|
2
|
+
import { SUPPLEMENTAL_XQUERY_PROLOG, createSchemaValidationError, getErrorOutput, omitSupplemental, stringLiteral } from "../utilities.mjs";
|
|
3
3
|
import { iso639_3Schema } from "../schemas.mjs";
|
|
4
4
|
import { restoreXMLMetadata } from "../xml/metadata.mjs";
|
|
5
5
|
import { parseStringLike } from "../parsers/helpers.mjs";
|
|
@@ -41,6 +41,8 @@ function parseWebsiteMetadata(data, options) {
|
|
|
41
41
|
function buildXQuery(parameters) {
|
|
42
42
|
return String.raw`xquery version "1.0-ml";
|
|
43
43
|
|
|
44
|
+
${SUPPLEMENTAL_XQUERY_PROLOG}
|
|
45
|
+
|
|
44
46
|
declare function local:resource-items($resources) {
|
|
45
47
|
for $resource in $resources
|
|
46
48
|
return
|
|
@@ -131,8 +133,10 @@ return
|
|
|
131
133
|
$website/@belongsTo,
|
|
132
134
|
$website/@publicationDateTime,
|
|
133
135
|
$website/@languages,
|
|
134
|
-
$
|
|
135
|
-
|
|
136
|
+
${omitSupplemental(`(
|
|
137
|
+
$website/metadata,
|
|
138
|
+
local:metadata-tree($website/tree[1], $target-slug, "")
|
|
139
|
+
)`)}
|
|
136
140
|
}</ochre>`;
|
|
137
141
|
}
|
|
138
142
|
async function fetchWebsiteMetadata(abbreviation, options) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { XML_PARSER_OPTIONS } from "../constants.mjs";
|
|
2
|
-
import { createSchemaValidationError, getErrorOutput } from "../utilities.mjs";
|
|
2
|
+
import { SUPPLEMENTAL_XQUERY_PROLOG, createSchemaValidationError, getErrorOutput, omitSupplemental, stringLiteral } from "../utilities.mjs";
|
|
3
3
|
import { restoreXMLMetadata } from "../xml/metadata.mjs";
|
|
4
4
|
import { XMLWebsiteData } from "../xml/schemas.mjs";
|
|
5
5
|
import { parseWebsite } from "../parsers/website/index.mjs";
|
|
@@ -21,6 +21,20 @@ async function validateWebsiteCredentials(uuid, credentials, fetcher) {
|
|
|
21
21
|
})).ok;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
+
* Build an XQuery string to fetch a website tree document by abbreviation.
|
|
25
|
+
*
|
|
26
|
+
* @param abbreviation - The lowercased website abbreviation to match
|
|
27
|
+
* @returns An XQuery string
|
|
28
|
+
*/
|
|
29
|
+
function buildXQuery(abbreviation) {
|
|
30
|
+
return `xquery version "1.0-ml";
|
|
31
|
+
|
|
32
|
+
${SUPPLEMENTAL_XQUERY_PROLOG}
|
|
33
|
+
|
|
34
|
+
for $ochre in collection("ochre/tree")/ochre[tree/identification/abbreviation/content/string = ${stringLiteral(abbreviation)}]
|
|
35
|
+
return element ochre { $ochre/@*, ${omitSupplemental("$ochre/node()")} }`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
24
38
|
* Fetches and parses a website configuration from the OCHRE API.
|
|
25
39
|
*
|
|
26
40
|
* For password-protected or OCHRE-credential-protected websites, if no credentials
|
|
@@ -32,8 +46,11 @@ async function validateWebsiteCredentials(uuid, credentials, fetcher) {
|
|
|
32
46
|
async function fetchWebsite(abbreviation, options) {
|
|
33
47
|
try {
|
|
34
48
|
const fetcher = options?.fetch ?? fetch;
|
|
35
|
-
const
|
|
36
|
-
|
|
49
|
+
const response = await fetcher("https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery&xsl=none&lang=\"*\"", {
|
|
50
|
+
method: "POST",
|
|
51
|
+
body: buildXQuery(abbreviation.trim().toLocaleLowerCase("en-US")),
|
|
52
|
+
headers: { "Content-Type": "application/xquery" }
|
|
53
|
+
});
|
|
37
54
|
if (!response.ok) throw new Error("Failed to fetch website", { cause: response.statusText });
|
|
38
55
|
const dataRaw = await response.text();
|
|
39
56
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
package/dist/helpers.d.mts
CHANGED
|
@@ -7,10 +7,6 @@ type FlattenedItem<U, T extends LanguageCodes> = Omit<U, "properties"> & {
|
|
|
7
7
|
* The default page size to use for fetching paginated items
|
|
8
8
|
*/
|
|
9
9
|
declare const DEFAULT_PAGE_SIZE = 48;
|
|
10
|
-
/**
|
|
11
|
-
* The default cap on OCR matches returned per requested item
|
|
12
|
-
*/
|
|
13
|
-
declare const DEFAULT_MAX_OCR_MATCHES_PER_ITEM = 50;
|
|
14
10
|
/**
|
|
15
11
|
* Flatten the properties of an item
|
|
16
12
|
* @param item - The item whose properties to flatten
|
|
@@ -18,4 +14,4 @@ declare const DEFAULT_MAX_OCR_MATCHES_PER_ITEM = 50;
|
|
|
18
14
|
*/
|
|
19
15
|
declare function flattenItemProperties<U extends ItemCategory = ItemCategory, V extends ContainedItemCategory<U> = ContainedItemCategory<U>, T extends LanguageCodes = LanguageCodes, W extends ItemPayloadKind = "topLevel">(item: Item<U, V, T, W>): FlattenedItem<Item<U, V, T, W>, T>;
|
|
20
16
|
//#endregion
|
|
21
|
-
export {
|
|
17
|
+
export { DEFAULT_PAGE_SIZE, flattenItemProperties };
|
package/dist/helpers.mjs
CHANGED
|
@@ -5,10 +5,6 @@ import { flattenProperties } from "./utilities.mjs";
|
|
|
5
5
|
*/
|
|
6
6
|
const DEFAULT_PAGE_SIZE = 48;
|
|
7
7
|
/**
|
|
8
|
-
* The default cap on OCR matches returned per requested item
|
|
9
|
-
*/
|
|
10
|
-
const DEFAULT_MAX_OCR_MATCHES_PER_ITEM = 50;
|
|
11
|
-
/**
|
|
12
8
|
* Flatten the properties of an item
|
|
13
9
|
* @param item - The item whose properties to flatten
|
|
14
10
|
* @returns The item with the properties flattened
|
|
@@ -34,4 +30,4 @@ function flattenItemProperties(item) {
|
|
|
34
30
|
};
|
|
35
31
|
}
|
|
36
32
|
//#endregion
|
|
37
|
-
export {
|
|
33
|
+
export { DEFAULT_PAGE_SIZE, flattenItemProperties };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { MultilingualOptions, MultilingualString, MultilingualStringEntries, MultilingualStringEntry, MultilingualStringInput, MultilingualStringJSON, MultilingualStringObject, MultilingualStringText } from "./parsers/multilingual.mjs";
|
|
2
2
|
import { AccordionWebBlock, ContextTree, ContextTreeFilterLevel, ContextTreeLevel, ContextTreeLevelItem, ProtectedWebsite, Scope, Style, StylesheetCategory, StylesheetItem, WebAccordionItem, WebBlock, WebBlockByLayout, WebBlockItem, WebBlockLayout, WebElement, WebElementComponent, WebElementComponentName, WebElementComponentOf, WebElementOf, WebImage, WebSidebar, WebTitle, Webpage, Website, WebsiteMetadata, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteSegment, WebsiteType } from "./types/website.mjs";
|
|
3
|
-
import { AnyBibliography, AnyConcept, AnyItem, AnyPeriod, AnyPerson, AnyPropertyValue, AnyPropertyVariable, AnyResource, AnySet, AnySpatialUnit, AnyText, AnyTree, BaseItem, BaseItemLink, BelongsTo, Bibliography, BibliographyEntryInfo, BibliographyItemLink, BibliographySourceDocument, Concept, ConceptItemLink, ContainedItemCategory, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Context, ContextItem, ContextItemCategory, ContextNode, Coordinates, CoordinatesSource, DictionaryUnitItemLink, EmbeddedBibliography, EmbeddedConcept, EmbeddedItem, EmbeddedPeriod, EmbeddedPerson, EmbeddedPropertyValue, EmbeddedPropertyVariable, EmbeddedResource, EmbeddedSet, EmbeddedSpatialUnit, EmbeddedText, EmbeddedTree, Event, Gallery, Heading, HeadingItemCategory, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemCategoryWithEmbeddedItems, ItemContainerCategory, ItemLink, ItemLinkCategory, ItemLinks, ItemPayloadKind, ItemProperty, ItemWithoutEmbeddedItems, LanguageCodes, License, Metadata, Note, Observation,
|
|
3
|
+
import { AnyBibliography, AnyConcept, AnyItem, AnyPeriod, AnyPerson, AnyPropertyValue, AnyPropertyVariable, AnyResource, AnySet, AnySpatialUnit, AnyText, AnyTree, BaseItem, BaseItemLink, BelongsTo, Bibliography, BibliographyEntryInfo, BibliographyItemLink, BibliographySourceDocument, Concept, ConceptItemLink, ContainedItemCategory, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Context, ContextItem, ContextItemCategory, ContextNode, Coordinates, CoordinatesSource, DictionaryUnitItemLink, EmbeddedBibliography, EmbeddedConcept, EmbeddedItem, EmbeddedPeriod, EmbeddedPerson, EmbeddedPropertyValue, EmbeddedPropertyVariable, EmbeddedResource, EmbeddedSet, EmbeddedSpatialUnit, EmbeddedText, EmbeddedTree, Event, Gallery, Heading, HeadingItemCategory, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemCategoryWithEmbeddedItems, ItemContainerCategory, ItemLink, ItemLinkCategory, ItemLinks, ItemPayloadKind, ItemProperty, ItemWithoutEmbeddedItems, LanguageCodes, License, Metadata, Note, Observation, OcrString, Period, PeriodItemLink, Person, PersonItemLink, Prettify, Property, PropertyLike, PropertyRelation, PropertyValue, PropertyValueContent, PropertyValueDataType, PropertyValueItemLink, PropertyValueQueryItem, PropertyVariable, PropertyVariableItemLink, Query, QueryGroup, QueryLeaf, QueryablePropertyValueDataType, RecursiveItemCategory, Resource, ResourceItemLink, Section, Set, SetAttributeValueQueryItem, SetBibliography, SetConcept, SetItem, SetItemCategory, SetItemLink, SetItemProperty, SetItemSimplifiedProperty, SetItemsSort, SetItemsSortDirection, SetPeriod, SetResource, SetSpatialUnit, SetTree, SimplifiedProperty, SpatialUnit, SpatialUnitItemLink, Text, TextItemLink, TopLevelItem, Tree, TreeItemCategory, TreeItemLink } from "./types/index.mjs";
|
|
4
4
|
import { fetchGallery } from "./fetchers/gallery.mjs";
|
|
5
5
|
import { fetchItemChildren } from "./fetchers/item-children.mjs";
|
|
6
6
|
import { fetchItemLinks } from "./fetchers/item-links.mjs";
|
|
7
|
+
import { fetchItemOcrData } from "./fetchers/item-ocr-data.mjs";
|
|
7
8
|
import { defineLanguages, fetchItem, withLanguages } from "./fetchers/item.mjs";
|
|
8
|
-
import { fetchOcrMatches } from "./fetchers/ocr-matches.mjs";
|
|
9
9
|
import { fetchSetItems } from "./fetchers/set/items.mjs";
|
|
10
10
|
import { fetchSetPropertyValues } from "./fetchers/set/property-values.mjs";
|
|
11
11
|
import { fetchWebsiteMetadata } from "./fetchers/website-metadata.mjs";
|
|
12
12
|
import { fetchWebsite } from "./fetchers/website.mjs";
|
|
13
13
|
import { PropertyOptions, filterProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels } from "./getters.mjs";
|
|
14
|
-
import {
|
|
15
|
-
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 ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource,
|
|
14
|
+
import { DEFAULT_PAGE_SIZE, flattenItemProperties } from "./helpers.mjs";
|
|
15
|
+
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 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 Prettify, type Property, type PropertyLike, PropertyOptions, type PropertyRelation, 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 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 WebImage, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels, withLanguages };
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { filterProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels } from "./getters.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_PAGE_SIZE, flattenItemProperties } from "./helpers.mjs";
|
|
3
3
|
import { MultilingualString } from "./parsers/multilingual.mjs";
|
|
4
4
|
import { fetchGallery } from "./fetchers/gallery.mjs";
|
|
5
5
|
import { fetchItemChildren } from "./fetchers/item-children.mjs";
|
|
6
6
|
import { fetchItemLinks } from "./fetchers/item-links.mjs";
|
|
7
|
+
import { fetchItemOcrData } from "./fetchers/item-ocr-data.mjs";
|
|
7
8
|
import { defineLanguages, fetchItem, withLanguages } from "./fetchers/item.mjs";
|
|
8
|
-
import { fetchOcrMatches } from "./fetchers/ocr-matches.mjs";
|
|
9
9
|
import { fetchSetItems } from "./fetchers/set/items.mjs";
|
|
10
10
|
import { fetchSetPropertyValues } from "./fetchers/set/property-values.mjs";
|
|
11
11
|
import { fetchWebsiteMetadata } from "./fetchers/website-metadata.mjs";
|
|
12
12
|
import { fetchWebsite } from "./fetchers/website.mjs";
|
|
13
|
-
export {
|
|
13
|
+
export { DEFAULT_PAGE_SIZE, MultilingualString, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels, withLanguages };
|
package/dist/parsers/index.d.mts
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { Webpage } from "../types/website.mjs";
|
|
2
|
-
import { Bibliography, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Gallery, Identification, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemContainerCategory, ItemLinks, Metadata, Note,
|
|
3
|
-
import { XMLBibliography, XMLData, XMLDataItem, XMLGalleryData, XMLIdentification, XMLItemLinks, XMLLink, XMLMetadata, XMLNote,
|
|
2
|
+
import { Bibliography, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Gallery, Identification, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemContainerCategory, ItemLinks, Metadata, Note, Person, Property, Resource, SetItem, SetItemCategory, SimplifiedProperty } from "../types/index.mjs";
|
|
3
|
+
import { XMLBibliography, XMLData, XMLDataItem, XMLGalleryData, XMLIdentification, XMLItemLinks, XMLLink, XMLMetadata, XMLNote, XMLPerson, XMLProperty, XMLResource, XMLSetItems, XMLSimplifiedProperty } from "../xml/types.mjs";
|
|
4
4
|
import { ParserOptions, getParserOptions, parseStringLike } from "./helpers.mjs";
|
|
5
5
|
//#region src/parsers/index.d.ts
|
|
6
6
|
type RawOchre = XMLData["result"]["ochre"];
|
|
7
7
|
type ResourceViewParser<T extends ReadonlyArray<string>> = (view: XMLResource["view"], context: Pick<Resource<T, "topLevel">, "belongsTo" | "metadata">) => Webpage<T> | null;
|
|
8
8
|
type SetItemCategoryFromCategories<T extends ReadonlyArray<SetItemCategory> | undefined> = T extends ReadonlyArray<infer U> ? Extract<U, SetItemCategory> : SetItemCategory;
|
|
9
9
|
declare function parseIdentification<T extends ReadonlyArray<string>>(rawIdentification: XMLIdentification, options: ParserOptions<T>): Identification<T>;
|
|
10
|
-
/**
|
|
11
|
-
* Parse OCR matches returned by the OCHRE API
|
|
12
|
-
* @param rawOcrItems - The raw OCR match items
|
|
13
|
-
* @returns The parsed OCR matches, in request order
|
|
14
|
-
* @internal
|
|
15
|
-
*/
|
|
16
|
-
declare function parseOcrMatches(rawOcrItems: Array<XMLOcrMatchItem>): Array<OcrMatch>;
|
|
17
10
|
declare function parseNotes<T extends ReadonlyArray<string>>(rawNotes: {
|
|
18
11
|
note: Array<XMLNote>;
|
|
19
12
|
} | undefined, options: ParserOptions<T>): Array<Note<T>>;
|
|
@@ -68,4 +61,4 @@ declare function parseItem(rawData: XMLData, options: {
|
|
|
68
61
|
parseResourceView?: ResourceViewParser<ReadonlyArray<string>>;
|
|
69
62
|
}): Item<ItemCategory, SetItemCategory, ReadonlyArray<string>>;
|
|
70
63
|
//#endregion
|
|
71
|
-
export { type ParserOptions, RawOchre, getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes,
|
|
64
|
+
export { type ParserOptions, RawOchre, getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes, parsePersonList, parseProperties, parseSetItems, parseSimplifiedProperties, parseStringLike, resolveDefaultLanguage, resolveLanguages };
|
package/dist/parsers/index.mjs
CHANGED
|
@@ -430,79 +430,6 @@ function parseImageMap(rawImageMap) {
|
|
|
430
430
|
height: rawImageMap.height
|
|
431
431
|
};
|
|
432
432
|
}
|
|
433
|
-
function parseOcrVertices(rawVertices) {
|
|
434
|
-
const vertices = [];
|
|
435
|
-
if (rawVertices == null) return vertices;
|
|
436
|
-
for (const match of rawVertices.matchAll(/\(\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*\)/g)) {
|
|
437
|
-
const x = Number(match[1]);
|
|
438
|
-
const y = Number(match[2]);
|
|
439
|
-
vertices.push({
|
|
440
|
-
x: Number.isNaN(x) ? 0 : x,
|
|
441
|
-
y: Number.isNaN(y) ? 0 : y
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
return vertices;
|
|
445
|
-
}
|
|
446
|
-
function parseOcrWords(rawWords) {
|
|
447
|
-
return Array.from(rawWords ?? [], (rawWord) => ({
|
|
448
|
-
content: rawWord.CONTENT,
|
|
449
|
-
x: rawWord.HPOS,
|
|
450
|
-
y: rawWord.VPOS,
|
|
451
|
-
width: rawWord.WIDTH,
|
|
452
|
-
height: rawWord.HEIGHT,
|
|
453
|
-
vertices: parseOcrVertices(rawWord.VERTICES)
|
|
454
|
-
}));
|
|
455
|
-
}
|
|
456
|
-
function joinOcrWordContents(words) {
|
|
457
|
-
return Array.from(words, (word) => word.content).join(" ");
|
|
458
|
-
}
|
|
459
|
-
function parseOcrPage(rawPage) {
|
|
460
|
-
const blocks = Array.from(rawPage.TextBlock ?? [], (rawBlock) => ({ lines: Array.from(rawBlock.TextLine ?? [], (rawLine) => {
|
|
461
|
-
const words = parseOcrWords(rawLine.string);
|
|
462
|
-
return {
|
|
463
|
-
content: joinOcrWordContents(words),
|
|
464
|
-
words
|
|
465
|
-
};
|
|
466
|
-
}) }));
|
|
467
|
-
return {
|
|
468
|
-
number: rawPage.n ?? null,
|
|
469
|
-
fileName: rawPage.fileName ?? null,
|
|
470
|
-
width: rawPage.WIDTH ?? null,
|
|
471
|
-
height: rawPage.HEIGHT ?? null,
|
|
472
|
-
blocks
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
function parseOcr(rawOcr) {
|
|
476
|
-
return Array.from(rawOcr?.Page ?? [], (rawPage) => parseOcrPage(rawPage));
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Parse OCR matches returned by the OCHRE API
|
|
480
|
-
* @param rawOcrItems - The raw OCR match items
|
|
481
|
-
* @returns The parsed OCR matches, in request order
|
|
482
|
-
* @internal
|
|
483
|
-
*/
|
|
484
|
-
function parseOcrMatches(rawOcrItems) {
|
|
485
|
-
const matches = [];
|
|
486
|
-
for (const rawOcrItem of rawOcrItems) {
|
|
487
|
-
const rawMatches = rawOcrItem.ocrMatch ?? [];
|
|
488
|
-
for (const rawMatch of rawMatches) {
|
|
489
|
-
const words = parseOcrWords(rawMatch.string);
|
|
490
|
-
matches.push({
|
|
491
|
-
uuid: rawOcrItem.uuid,
|
|
492
|
-
resourceUuid: rawMatch.resourceUuid ?? null,
|
|
493
|
-
page: {
|
|
494
|
-
number: rawMatch.n ?? null,
|
|
495
|
-
fileName: rawMatch.fileName ?? null,
|
|
496
|
-
width: rawMatch.WIDTH ?? null,
|
|
497
|
-
height: rawMatch.HEIGHT ?? null
|
|
498
|
-
},
|
|
499
|
-
content: joinOcrWordContents(words),
|
|
500
|
-
words
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
return matches;
|
|
505
|
-
}
|
|
506
433
|
function parseNote(rawNote, options) {
|
|
507
434
|
const authors = Array.from(rawNote.authors?.author ?? [], (author) => parsePerson(author, options));
|
|
508
435
|
const content = rawNote.content == null ? multilingualFromText(parseXMLString(rawNote), options) : parseRequiredContentLike(rawNote, options);
|
|
@@ -1196,7 +1123,6 @@ function parseResource(rawResource, options) {
|
|
|
1196
1123
|
image: parseImage(rawResource.image, options),
|
|
1197
1124
|
document: parseContentLike(rawResource.document, options),
|
|
1198
1125
|
imageMap: parseImageMap(rawResource.imagemap),
|
|
1199
|
-
ocr: parseOcr(rawResource.ocr),
|
|
1200
1126
|
coordinates: parseCoordinates(rawResource.coordinates, options),
|
|
1201
1127
|
periods: parsePeriodList(rawResource.periods, options),
|
|
1202
1128
|
links: parseLinks(rawResource.links, options),
|
|
@@ -1399,4 +1325,4 @@ function parseItem(rawData, options) {
|
|
|
1399
1325
|
};
|
|
1400
1326
|
}
|
|
1401
1327
|
//#endregion
|
|
1402
|
-
export { getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes,
|
|
1328
|
+
export { getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes, parsePersonList, parseProperties, parseSetItems, parseSimplifiedProperties, parseStringLike, resolveDefaultLanguage, resolveLanguages };
|
package/dist/query.d.mts
CHANGED
|
@@ -1,40 +1,31 @@
|
|
|
1
1
|
import { Query } from "./types/index.mjs";
|
|
2
2
|
//#region src/query.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Error message for OCR queries nested inside an OR group
|
|
5
|
-
* @internal
|
|
6
|
-
*/
|
|
7
|
-
declare const OCR_DISJUNCTION_ERROR_MESSAGE = "OCR queries cannot be nested inside an OR group because they are resolved by a document join instead of a CTS query";
|
|
8
|
-
type OcrUuidBinding = {
|
|
9
|
-
name: string;
|
|
10
|
-
expression: string;
|
|
11
|
-
};
|
|
12
3
|
declare function buildAndCtsQueryExpression(queryExpressions: Array<string>): string | null;
|
|
4
|
+
declare function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids: Array<string>, belongsToCollectionPropertyVariableUuid: string): string | null;
|
|
13
5
|
/**
|
|
14
|
-
* Compile
|
|
6
|
+
* Compile a query tree into the CTS searches that resolve it
|
|
15
7
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
8
|
+
* OCR text is not carried by Set item projections, so an `ocrText` leaf cannot
|
|
9
|
+
* be a CTS term: it resolves to a document join whose UUID list can only be
|
|
10
|
+
* applied as an item path predicate, and path predicates only ever AND. To keep
|
|
11
|
+
* `ocrText` composable with `or` anyway, the tree is split on each distinct OCR
|
|
12
|
+
* text condition, one branch per assignment of "this item is in that match
|
|
13
|
+
* set". Every branch is a plain CTS search, and their union is the result.
|
|
14
|
+
* Branches that the assignment already rules out are dropped, so a query whose
|
|
15
|
+
* OCR text leaves are all conjunctive still compiles to a single search.
|
|
19
16
|
*/
|
|
20
|
-
declare function buildOcrTermQueryExpressions(parameters: {
|
|
21
|
-
value: string;
|
|
22
|
-
matchMode: "includes" | "exact";
|
|
23
|
-
isCaseSensitive: boolean;
|
|
24
|
-
}): Array<string>;
|
|
25
|
-
/**
|
|
26
|
-
* Whether a query tree nests an OCR leaf inside an OR group
|
|
27
|
-
* @internal
|
|
28
|
-
*/
|
|
29
|
-
declare function hasOcrQueryInDisjunction(query: Query, isInDisjunction?: boolean): boolean;
|
|
30
|
-
declare function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids: Array<string>, belongsToCollectionPropertyVariableUuid: string): string | null;
|
|
31
17
|
declare function buildQueryPlan(parameters: {
|
|
32
18
|
queries: Query | null;
|
|
33
19
|
}): {
|
|
34
20
|
prolog: string;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
ocrTextBindings: Array<{
|
|
22
|
+
name: string;
|
|
23
|
+
expression: string;
|
|
24
|
+
}>;
|
|
25
|
+
branches: Array<{
|
|
26
|
+
itemPredicates: string;
|
|
27
|
+
queryExpression: string | null;
|
|
28
|
+
}>;
|
|
38
29
|
};
|
|
39
30
|
//#endregion
|
|
40
|
-
export {
|
|
31
|
+
export { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan };
|
package/dist/query.mjs
CHANGED
|
@@ -12,11 +12,7 @@ const CTS_INCLUDES_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
|
12
12
|
const CTS_INCLUDES_TOKEN_WORD_REGEX = /^\p{L}+$/u;
|
|
13
13
|
const CTS_INCLUDES_TOKEN_REGEX = /[\p{L}\p{N}*?]+/gu;
|
|
14
14
|
const CTS_EXACT_TEXT_TOKEN_REGEX = /[\p{L}\p{N}]+/gu;
|
|
15
|
-
|
|
16
|
-
* Error message for OCR queries nested inside an OR group
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
const OCR_DISJUNCTION_ERROR_MESSAGE = "OCR queries cannot be nested inside an OR group because they are resolved by a document join instead of a CTS query";
|
|
15
|
+
const MAX_OCR_TEXT_CONDITIONS = 4;
|
|
20
16
|
const CONTENT_TARGET_CONTENT_ELEMENT_PATHS = {
|
|
21
17
|
title: [
|
|
22
18
|
"identification",
|
|
@@ -204,9 +200,6 @@ function buildNestedElementQuery(elementNames, queryExpression) {
|
|
|
204
200
|
function buildNotCtsQueryExpression(queryExpression) {
|
|
205
201
|
return `cts:not-query(${queryExpression})`;
|
|
206
202
|
}
|
|
207
|
-
function buildCtsNearQueryExpression(queryExpressions) {
|
|
208
|
-
return `cts:near-query((${queryExpressions.join(", ")}), ${queryExpressions.length - 1}, ("ordered"))`;
|
|
209
|
-
}
|
|
210
203
|
function buildAndCtsQueryExpressionInternal(queryExpressions) {
|
|
211
204
|
if (queryExpressions.length === 0) return "cts:true-query()";
|
|
212
205
|
if (queryExpressions.length === 1) return queryExpressions[0] ?? "cts:true-query()";
|
|
@@ -246,8 +239,7 @@ function buildRichTextContentQueryExpression(parameters) {
|
|
|
246
239
|
const { value, matchMode, isCaseSensitive, language } = parameters;
|
|
247
240
|
return buildAndCtsQueryExpressionInternal([buildContentLanguageQuery(language), matchMode === "exact" ? buildRichTextExactQueryExpression({
|
|
248
241
|
value,
|
|
249
|
-
isCaseSensitive
|
|
250
|
-
language
|
|
242
|
+
isCaseSensitive
|
|
251
243
|
}) : buildCtsWordQueryExpression({
|
|
252
244
|
value,
|
|
253
245
|
matchMode,
|
|
@@ -480,62 +472,83 @@ function buildItemStringQueryExpression(parameters) {
|
|
|
480
472
|
language
|
|
481
473
|
})]);
|
|
482
474
|
}
|
|
483
|
-
function
|
|
484
|
-
const { value, matchMode, isCaseSensitive } =
|
|
485
|
-
const
|
|
486
|
-
const terms = [];
|
|
487
|
-
for (const term of rawTerms) if (getWildcardStrippedValue(term) !== "") terms.push(term);
|
|
488
|
-
return terms;
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Compile one CTS query expression per OCR search term, in word order
|
|
492
|
-
*
|
|
493
|
-
* Highlighting matches each OCR word against these same per-term expressions,
|
|
494
|
-
* so hit locations always agree with what the filter matched.
|
|
495
|
-
* @internal
|
|
496
|
-
*/
|
|
497
|
-
function buildOcrTermQueryExpressions(parameters) {
|
|
498
|
-
const { value, matchMode, isCaseSensitive } = parameters;
|
|
499
|
-
const terms = tokenizeOcrSearchValue({
|
|
475
|
+
function buildOcrTextQueryExpression(query) {
|
|
476
|
+
const { value, matchMode, isCaseSensitive } = query;
|
|
477
|
+
const phraseQueryExpression = buildRichTextPhraseQueryExpression({
|
|
500
478
|
value,
|
|
501
|
-
matchMode,
|
|
502
479
|
isCaseSensitive
|
|
503
480
|
});
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
value: term,
|
|
481
|
+
if (matchMode === "exact") return buildNestedElementQuery(["ocrText"], phraseQueryExpression);
|
|
482
|
+
const terms = tokenizeIncludesSearchValue({
|
|
483
|
+
value,
|
|
508
484
|
isCaseSensitive
|
|
509
|
-
})
|
|
485
|
+
});
|
|
486
|
+
if (terms.length === 0) return "cts:false-query()";
|
|
487
|
+
const tokenizedQueryExpression = buildAndCtsQueryExpressionInternal(Array.from(terms, (term) => buildCtsWordQueryExpression({
|
|
510
488
|
value: term,
|
|
511
489
|
matchMode,
|
|
512
490
|
isCaseSensitive,
|
|
513
491
|
queryFamily: "text"
|
|
514
|
-
}));
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
492
|
+
})));
|
|
493
|
+
return buildNestedElementQuery(["ocrText"], shouldUseFullValueFallbackForIncludes({
|
|
494
|
+
value,
|
|
495
|
+
isCaseSensitive,
|
|
496
|
+
terms
|
|
497
|
+
}) ? buildOrCtsQueryExpressionInternal([phraseQueryExpression, tokenizedQueryExpression]) : tokenizedQueryExpression);
|
|
520
498
|
}
|
|
521
|
-
function
|
|
522
|
-
|
|
499
|
+
function getOcrTextConditionKey(query) {
|
|
500
|
+
return [
|
|
523
501
|
query.value,
|
|
524
502
|
query.matchMode,
|
|
525
503
|
query.isCaseSensitive ? "case-sensitive" : "case-insensitive"
|
|
526
504
|
].join("|");
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
505
|
+
}
|
|
506
|
+
function registerOcrTextCondition(context, query) {
|
|
507
|
+
const key = getOcrTextConditionKey(query);
|
|
508
|
+
if (context.ocrTextConditionIndexesByKey.has(key)) return;
|
|
509
|
+
context.ocrTextConditionIndexesByKey.set(key, context.ocrTextConditions.length);
|
|
510
|
+
context.ocrTextConditions.push({
|
|
511
|
+
variableName: `$ocrTextUuids${context.ocrTextConditions.length + 1}`,
|
|
512
|
+
bindingExpression: `for $ocrTextDocument in cts:search(doc(), ${buildOcrTextQueryExpression(query)})\n return document-uri($ocrTextDocument)`
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function collectOcrTextConditions(context, query) {
|
|
516
|
+
if (isQueryLeaf(query)) {
|
|
517
|
+
if (query.target === "ocrText") registerOcrTextCondition(context, query);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
for (const childQuery of getQueryGroupChildren(query)) collectOcrTextConditions(context, childQuery);
|
|
521
|
+
}
|
|
522
|
+
function isOcrTextLeafMatched(context, query, ocrTextValues) {
|
|
523
|
+
const conditionIndex = context.ocrTextConditionIndexesByKey.get(getOcrTextConditionKey(query));
|
|
524
|
+
const isMatched = conditionIndex != null && ocrTextValues[conditionIndex] === true;
|
|
525
|
+
return query.isNegated === true ? !isMatched : isMatched;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Enumerate every assignment of "this item is in the OCR text match set" across
|
|
529
|
+
* the compiled conditions, least significant position first
|
|
530
|
+
*/
|
|
531
|
+
function getOcrTextValueCombinations(count) {
|
|
532
|
+
return Array.from({ length: 2 ** count }, (_, index) => Array.from({ length: count }, (_, position) => (index >> position & 1) === 1));
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Resolve a query tree against one OCR text assignment, treating every CTS leaf
|
|
536
|
+
* as unknown. Only a definite `false` is actionable: it means the branch cannot
|
|
537
|
+
* match anything and can be dropped before it costs a `cts:search`.
|
|
538
|
+
*/
|
|
539
|
+
function evaluateOcrTextBranch(context, query, ocrTextValues) {
|
|
540
|
+
if (isQueryLeaf(query)) return query.target === "ocrText" ? isOcrTextLeafMatched(context, query, ocrTextValues) : null;
|
|
541
|
+
const isAndGroup = "and" in query;
|
|
542
|
+
let result = isAndGroup;
|
|
543
|
+
for (const childQuery of getQueryGroupChildren(query)) {
|
|
544
|
+
const childResult = evaluateOcrTextBranch(context, childQuery, ocrTextValues);
|
|
545
|
+
if (childResult === !isAndGroup) return !isAndGroup;
|
|
546
|
+
if (childResult == null) result = null;
|
|
536
547
|
}
|
|
537
|
-
|
|
538
|
-
|
|
548
|
+
return result;
|
|
549
|
+
}
|
|
550
|
+
function buildOcrTextItemPredicates(context, ocrTextValues) {
|
|
551
|
+
return Array.from(context.ocrTextConditions, (condition, index) => ocrTextValues[index] === true ? `[@uuid = ${condition.variableName}]` : `[not(@uuid = ${condition.variableName})]`).join("");
|
|
539
552
|
}
|
|
540
553
|
function getLeafSearchValue(query) {
|
|
541
554
|
switch (query.target) {
|
|
@@ -618,10 +631,8 @@ function createQueryCompilerContext() {
|
|
|
618
631
|
nextHelperSerial: 1,
|
|
619
632
|
helperNamesByKey: /* @__PURE__ */ new Map(),
|
|
620
633
|
helperDeclarations: [],
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
ocrBindings: [],
|
|
624
|
-
itemPredicates: []
|
|
634
|
+
ocrTextConditions: [],
|
|
635
|
+
ocrTextConditionIndexesByKey: /* @__PURE__ */ new Map()
|
|
625
636
|
};
|
|
626
637
|
}
|
|
627
638
|
function registerConstantHelper(parameters) {
|
|
@@ -818,24 +829,11 @@ function getQueryGroupChildren(query) {
|
|
|
818
829
|
function getQueryGroupOperator(query) {
|
|
819
830
|
return "and" in query ? "and" : "or";
|
|
820
831
|
}
|
|
821
|
-
function isDisjunctiveQueryGroup(query) {
|
|
822
|
-
return "or" in query && query.or.length > 1;
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* Whether a query tree nests an OCR leaf inside an OR group
|
|
826
|
-
* @internal
|
|
827
|
-
*/
|
|
828
|
-
function hasOcrQueryInDisjunction(query, isInDisjunction = false) {
|
|
829
|
-
if (isQueryLeaf(query)) return query.target === "ocr" && isInDisjunction;
|
|
830
|
-
const isChildInDisjunction = isInDisjunction || isDisjunctiveQueryGroup(query);
|
|
831
|
-
for (const childQuery of getQueryGroupChildren(query)) if (hasOcrQueryInDisjunction(childQuery, isChildInDisjunction)) return true;
|
|
832
|
-
return false;
|
|
833
|
-
}
|
|
834
832
|
function getCompatibleIncludesGroupLeaves(query) {
|
|
835
833
|
if (!("or" in query) || query.or.length <= 1) return null;
|
|
836
834
|
const leafQueries = [];
|
|
837
835
|
for (const childQuery of query.or) {
|
|
838
|
-
if (!isQueryLeaf(childQuery) || childQuery.target === "
|
|
836
|
+
if (!isQueryLeaf(childQuery) || childQuery.target === "ocrText") return null;
|
|
839
837
|
leafQueries.push(childQuery);
|
|
840
838
|
}
|
|
841
839
|
const firstQuery = leafQueries[0];
|
|
@@ -896,20 +894,15 @@ function buildIncludesGroupQueryExpression(context, queries) {
|
|
|
896
894
|
bodyExpression: buildOrCtsQueryExpressionInternal(exactMemberHelpers.map((helper) => helper.callExpression))
|
|
897
895
|
}).callExpression, tokenizedQueryExpression]);
|
|
898
896
|
}
|
|
899
|
-
function buildQueryNode(context, query,
|
|
897
|
+
function buildQueryNode(context, query, ocrTextValues) {
|
|
900
898
|
if (isQueryLeaf(query)) {
|
|
901
|
-
if (query.target === "
|
|
902
|
-
if (isInDisjunction) throw new Error(OCR_DISJUNCTION_ERROR_MESSAGE, { cause: query });
|
|
903
|
-
registerOcrItemPredicate(context, query);
|
|
904
|
-
return "cts:true-query()";
|
|
905
|
-
}
|
|
899
|
+
if (query.target === "ocrText") return isOcrTextLeafMatched(context, query, ocrTextValues) ? "cts:true-query()" : "cts:false-query()";
|
|
906
900
|
const queryExpression = buildLeafQueryExpression(context, query);
|
|
907
901
|
return query.isNegated === true ? buildNotCtsQueryExpression(queryExpression) : queryExpression;
|
|
908
902
|
}
|
|
909
903
|
const optimizedIncludesGroupQueries = getCompatibleIncludesGroupLeaves(query);
|
|
910
904
|
if (optimizedIncludesGroupQueries != null) return buildIncludesGroupQueryExpression(context, optimizedIncludesGroupQueries);
|
|
911
|
-
const
|
|
912
|
-
const childQueryExpressions = Array.from(getQueryGroupChildren(query), (childQuery) => buildQueryNode(context, childQuery, isChildInDisjunction));
|
|
905
|
+
const childQueryExpressions = Array.from(getQueryGroupChildren(query), (childQuery) => buildQueryNode(context, childQuery, ocrTextValues));
|
|
913
906
|
return (getQueryGroupOperator(query) === "and" ? buildAndCtsQueryExpressionInternal : buildOrCtsQueryExpressionInternal)(childQueryExpressions);
|
|
914
907
|
}
|
|
915
908
|
function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids, belongsToCollectionPropertyVariableUuid) {
|
|
@@ -923,22 +916,47 @@ function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids,
|
|
|
923
916
|
}))))
|
|
924
917
|
});
|
|
925
918
|
}
|
|
919
|
+
/**
|
|
920
|
+
* Compile a query tree into the CTS searches that resolve it
|
|
921
|
+
*
|
|
922
|
+
* OCR text is not carried by Set item projections, so an `ocrText` leaf cannot
|
|
923
|
+
* be a CTS term: it resolves to a document join whose UUID list can only be
|
|
924
|
+
* applied as an item path predicate, and path predicates only ever AND. To keep
|
|
925
|
+
* `ocrText` composable with `or` anyway, the tree is split on each distinct OCR
|
|
926
|
+
* text condition, one branch per assignment of "this item is in that match
|
|
927
|
+
* set". Every branch is a plain CTS search, and their union is the result.
|
|
928
|
+
* Branches that the assignment already rules out are dropped, so a query whose
|
|
929
|
+
* OCR text leaves are all conjunctive still compiles to a single search.
|
|
930
|
+
*/
|
|
926
931
|
function buildQueryPlan(parameters) {
|
|
927
932
|
const { queries } = parameters;
|
|
928
933
|
if (queries == null) return {
|
|
929
934
|
prolog: "",
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
935
|
+
ocrTextBindings: [],
|
|
936
|
+
branches: [{
|
|
937
|
+
itemPredicates: "",
|
|
938
|
+
queryExpression: null
|
|
939
|
+
}]
|
|
933
940
|
};
|
|
934
941
|
const context = createQueryCompilerContext();
|
|
935
|
-
|
|
942
|
+
collectOcrTextConditions(context, queries);
|
|
943
|
+
if (context.ocrTextConditions.length > MAX_OCR_TEXT_CONDITIONS) throw new Error(`A query cannot contain more than ${MAX_OCR_TEXT_CONDITIONS} distinct OCR text searches`, { cause: context.ocrTextConditions.length });
|
|
944
|
+
const branches = [];
|
|
945
|
+
for (const ocrTextValues of getOcrTextValueCombinations(context.ocrTextConditions.length)) {
|
|
946
|
+
if (evaluateOcrTextBranch(context, queries, ocrTextValues) === false) continue;
|
|
947
|
+
branches.push({
|
|
948
|
+
itemPredicates: buildOcrTextItemPredicates(context, ocrTextValues),
|
|
949
|
+
queryExpression: buildQueryNode(context, queries, ocrTextValues)
|
|
950
|
+
});
|
|
951
|
+
}
|
|
936
952
|
return {
|
|
937
953
|
prolog: context.helperDeclarations.join("\n\n"),
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
954
|
+
ocrTextBindings: Array.from(context.ocrTextConditions, (condition) => ({
|
|
955
|
+
name: condition.variableName,
|
|
956
|
+
expression: condition.bindingExpression
|
|
957
|
+
})),
|
|
958
|
+
branches
|
|
941
959
|
};
|
|
942
960
|
}
|
|
943
961
|
//#endregion
|
|
944
|
-
export {
|
|
962
|
+
export { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan };
|