@lde/search-typesense 0.27.4 → 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/import.js DELETED
@@ -1,60 +0,0 @@
1
- /** Documents imported per Typesense request unless a writer is told otherwise. */
2
- export const DEFAULT_BATCH_SIZE = 1000;
3
- /**
4
- * Accumulates documents across writes and upserts them into a collection in
5
- * fixed-size batches, so many small writes (one dataset at a time) still land
6
- * as few Typesense requests. Call {@link flush} to import the remainder.
7
- */
8
- export class BatchImporter {
9
- client;
10
- collection;
11
- batchSize;
12
- buffer = [];
13
- constructor(client, collection, batchSize) {
14
- this.client = client;
15
- this.collection = collection;
16
- this.batchSize = batchSize;
17
- }
18
- /** Add a stream of documents, importing a batch whenever one fills up. */
19
- async add(documents) {
20
- for await (const document of documents) {
21
- this.buffer.push(document);
22
- if (this.buffer.length >= this.batchSize) {
23
- await this.importBuffer();
24
- }
25
- }
26
- }
27
- /** Import any remaining documents. */
28
- async flush() {
29
- if (this.buffer.length > 0) {
30
- await this.importBuffer();
31
- }
32
- }
33
- async importBuffer() {
34
- const batch = this.buffer;
35
- this.buffer = [];
36
- await importBatch(this.client, this.collection, batch);
37
- }
38
- }
39
- /**
40
- * Create-or-replace one batch of whole documents, keyed on `id`, throwing if any
41
- * individual document fails (Typesense’s bulk import otherwise reports
42
- * per-document failures without rejecting).
43
- */
44
- export async function importBatch(client, collection, batch) {
45
- const results = (await client
46
- .collections(collection)
47
- .documents()
48
- .import(batch, {
49
- action: 'upsert',
50
- // Collect per-document outcomes instead of throwing the client’s opaque
51
- // ImportError, so we can report which documents failed and why.
52
- throwOnFail: false,
53
- }));
54
- const failures = results.filter((result) => !result.success);
55
- if (failures.length > 0) {
56
- throw new Error(`Typesense upsert into “${collection}” failed for ${failures.length}/${results.length} documents: ${failures
57
- .map((failure) => failure.error)
58
- .join('; ')}`);
59
- }
60
- }
package/dist/sweep.d.ts DELETED
@@ -1,70 +0,0 @@
1
- import type { SearchType } from '@lde/search';
2
- /** The private field carrying the dataset IRI a document came from, for a type
3
- * that declares none of its own – see {@link provenanceField}. */
4
- export declare const SOURCE_FIELD = "source";
5
- /** The document field carrying the id of the run that last wrote a document. */
6
- export declare const LAST_SEEN_FIELD = "last_seen";
7
- /**
8
- * The field a collection carries its documents’ dataset IRI in – the one the
9
- * membership sweep enumerates, filters and deletes by.
10
- *
11
- * A type that declares a field over the dataset
12
- * ({@link datasetField `from: 'dataset'`}) *is* its provenance: the writer keeps
13
- * its bookkeeping on that field rather than stamping a private one beside it,
14
- * so the facet, the label resolution, any `derive` and the sweep all read one
15
- * column that cannot drift. A type declaring nothing – or declaring the dataset
16
- * only as an *internal* field, which the projection prunes before the writer
17
- * ever sees it – falls back to the private {@link SOURCE_FIELD}, and behaves
18
- * exactly as it always has.
19
- */
20
- export declare function provenanceField(searchType: SearchType): string;
21
- /**
22
- * Sources whose documents must leave the index: indexed, but no longer part
23
- * of the run’s selection. Selection is membership, not processing – a dataset
24
- * skipped as unchanged is still selected, so its documents survive.
25
- *
26
- * @param indexedSources Source IRIs present in the collection
27
- * @param selectedSources Source IRIs the run’s selector produced
28
- */
29
- export declare function departedSources(indexedSources: Iterable<string>, selectedSources: Iterable<string>): string[];
30
- /**
31
- * Typesense filter matching a source’s documents that this run did not touch:
32
- * everything the source no longer contains, ready for a per-source sweep.
33
- *
34
- * @param sourceField The collection’s {@link provenanceField}
35
- * @param sourceIri The dataset IRI the documents carry in that field
36
- * @param runId The current run; documents it wrote carry it as `last_seen`
37
- */
38
- export declare function staleDocumentsFilter(sourceField: string, sourceIri: string, runId: string): string;
39
- /**
40
- * Typesense filter matching all of a source’s documents, ready to drop a whole
41
- * source (a departed source’s membership sweep, or a Blue/green writer rolling
42
- * a failed dataset out of its not-yet-live collection).
43
- *
44
- * @param sourceField The collection’s {@link provenanceField}
45
- * @param sourceIri The dataset IRI the documents carry in that field
46
- */
47
- export declare function sourceDocumentsFilter(sourceField: string, sourceIri: string): string;
48
- /**
49
- * Typesense filter matching the documents **this run** wrote for a source: the
50
- * inverse of {@link staleDocumentsFilter}. An In-place writer deletes these to
51
- * discard a source’s in-progress writes (the dump-fallback reset) without
52
- * touching its prior-run documents, which the success sweep or a failed run
53
- * still owns.
54
- *
55
- * @param sourceField The collection’s {@link provenanceField}
56
- * @param sourceIri The dataset IRI the documents carry in that field
57
- * @param runId The current run, stamped on its documents as `last_seen`
58
- */
59
- export declare function thisRunDocumentsFilter(sourceField: string, sourceIri: string, runId: string): string;
60
- /**
61
- * Typesense filters deleting every departed source’s documents, combined into
62
- * as few filters as fit: deletes travel in the URL query string, so each
63
- * filter stays under a conservative length budget rather than listing every
64
- * source in one string.
65
- *
66
- * @param sourceField The collection’s {@link provenanceField}
67
- * @param departed The departed source IRIs ({@link departedSources})
68
- */
69
- export declare function membershipSweepFilters(sourceField: string, departed: readonly string[]): string[];
70
- //# sourceMappingURL=sweep.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sweep.d.ts","sourceRoot":"","sources":["../src/sweep.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C;mEACmE;AACnE,eAAO,MAAM,YAAY,WAAW,CAAC;AAErC,gFAAgF;AAChF,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAK9D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,EAChC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,GAChC,MAAM,EAAE,CAGV;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,EAAE,CAqBV"}
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;