@lde/search-typesense 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sweep.js DELETED
@@ -1,113 +0,0 @@
1
- // Pure deletion planning shared by the rebuild writers: which documents leave
2
- // a collection, expressed as source sets and Typesense filter strings. Kept
3
- // free of the Typesense client so the logic is unit-testable. This module owns
4
- // the private bookkeeping field names and resolves which field a collection
5
- // carries its provenance in, so stamping and every filter that reads it can
6
- // never disagree.
7
- import { datasetField, isInternalField } from '@lde/search/adapter';
8
- import { escapeFilterValue } from './query-compiler.js';
9
- /** The private field carrying the dataset IRI a document came from, for a type
10
- * that declares none of its own – see {@link provenanceField}. */
11
- export const SOURCE_FIELD = 'source';
12
- /** The document field carrying the id of the run that last wrote a document. */
13
- export const LAST_SEEN_FIELD = 'last_seen';
14
- /**
15
- * The field a collection carries its documents’ dataset IRI in – the one the
16
- * membership sweep enumerates, filters and deletes by.
17
- *
18
- * A type that declares a field over the dataset
19
- * ({@link datasetField `from: 'dataset'`}) *is* its provenance: the writer keeps
20
- * its bookkeeping on that field rather than stamping a private one beside it,
21
- * so the facet, the label resolution, any `derive` and the sweep all read one
22
- * column that cannot drift. A type declaring nothing – or declaring the dataset
23
- * only as an *internal* field, which the projection prunes before the writer
24
- * ever sees it – falls back to the private {@link SOURCE_FIELD}, and behaves
25
- * exactly as it always has.
26
- */
27
- export function provenanceField(searchType) {
28
- const declared = datasetField(searchType);
29
- return declared === undefined || isInternalField(declared)
30
- ? SOURCE_FIELD
31
- : declared.name;
32
- }
33
- /**
34
- * Sources whose documents must leave the index: indexed, but no longer part
35
- * of the run’s selection. Selection is membership, not processing – a dataset
36
- * skipped as unchanged is still selected, so its documents survive.
37
- *
38
- * @param indexedSources Source IRIs present in the collection
39
- * @param selectedSources Source IRIs the run’s selector produced
40
- */
41
- export function departedSources(indexedSources, selectedSources) {
42
- const selected = new Set(selectedSources);
43
- return [...indexedSources].filter((source) => !selected.has(source));
44
- }
45
- /**
46
- * Typesense filter matching a source’s documents that this run did not touch:
47
- * everything the source no longer contains, ready for a per-source sweep.
48
- *
49
- * @param sourceField The collection’s {@link provenanceField}
50
- * @param sourceIri The dataset IRI the documents carry in that field
51
- * @param runId The current run; documents it wrote carry it as `last_seen`
52
- */
53
- export function staleDocumentsFilter(sourceField, sourceIri, runId) {
54
- return `${sourceDocumentsFilter(sourceField, sourceIri)} && ${LAST_SEEN_FIELD}:!=${escapeFilterValue(runId)}`;
55
- }
56
- /**
57
- * Typesense filter matching all of a source’s documents, ready to drop a whole
58
- * source (a departed source’s membership sweep, or a Blue/green writer rolling
59
- * a failed dataset out of its not-yet-live collection).
60
- *
61
- * @param sourceField The collection’s {@link provenanceField}
62
- * @param sourceIri The dataset IRI the documents carry in that field
63
- */
64
- export function sourceDocumentsFilter(sourceField, sourceIri) {
65
- return `${sourceField}:=${escapeFilterValue(sourceIri)}`;
66
- }
67
- /**
68
- * Typesense filter matching the documents **this run** wrote for a source: the
69
- * inverse of {@link staleDocumentsFilter}. An In-place writer deletes these to
70
- * discard a source’s in-progress writes (the dump-fallback reset) without
71
- * touching its prior-run documents, which the success sweep or a failed run
72
- * still owns.
73
- *
74
- * @param sourceField The collection’s {@link provenanceField}
75
- * @param sourceIri The dataset IRI the documents carry in that field
76
- * @param runId The current run, stamped on its documents as `last_seen`
77
- */
78
- export function thisRunDocumentsFilter(sourceField, sourceIri, runId) {
79
- return `${sourceDocumentsFilter(sourceField, sourceIri)} && ${LAST_SEEN_FIELD}:=${escapeFilterValue(runId)}`;
80
- }
81
- /**
82
- * Typesense filters deleting every departed source’s documents, combined into
83
- * as few filters as fit: deletes travel in the URL query string, so each
84
- * filter stays under a conservative length budget rather than listing every
85
- * source in one string.
86
- *
87
- * @param sourceField The collection’s {@link provenanceField}
88
- * @param departed The departed source IRIs ({@link departedSources})
89
- */
90
- export function membershipSweepFilters(sourceField, departed) {
91
- const filters = [];
92
- let chunk = [];
93
- let chunkLength = 0;
94
- const flush = () => {
95
- if (chunk.length > 0) {
96
- filters.push(`${sourceField}:=[${chunk.join(',')}]`);
97
- chunk = [];
98
- chunkLength = 0;
99
- }
100
- };
101
- for (const source of departed) {
102
- const escaped = escapeFilterValue(source);
103
- if (chunkLength + escaped.length > MAX_FILTER_VALUES_LENGTH) {
104
- flush();
105
- }
106
- chunk.push(escaped);
107
- chunkLength += escaped.length + 1;
108
- }
109
- flush();
110
- return filters;
111
- }
112
- /** Stay well under Typesense’s ~4000-char URL query-string limit per delete. */
113
- const MAX_FILTER_VALUES_LENGTH = 3000;