@nxgt/mongo-meilisearch 0.4.4 → 0.5.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/README.md +149 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +113 -2
- package/dist/index.js.map +5 -4
- package/dist/syncs/create-search-syncs.d.ts +13 -0
- package/dist/syncs/create-search-syncs.d.ts.map +1 -0
- package/dist/syncs/types.d.ts +89 -0
- package/dist/syncs/types.d.ts.map +1 -0
- package/docs/README.md +3 -1
- package/docs/guide/search-syncs/lifecycle.md +301 -0
- package/docs/guide/search-syncs/wiring.md +188 -0
- package/docs/roadmap.md +18 -0
- package/docs/troubleshooting.md +213 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,9 +1,49 @@
|
|
|
1
1
|
# @nxgt/mongo-meilisearch
|
|
2
2
|
|
|
3
|
-
Keeps
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Keeps [Meilisearch](https://www.meilisearch.com) indexes in step with MongoDB
|
|
4
|
+
collections: a typed transform from one to the other, a full reindex, and a
|
|
5
|
+
change stream that picks up where it stopped, its position kept in MongoDB.
|
|
6
|
+
`createSearchSyncs` does it for every collection an `openMongo` wires, from one
|
|
7
|
+
config and one `start()`; `createSearchSync` does it for one collection.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { bindIndex } from '@nxgt/meilisearch';
|
|
11
|
+
import { defineMongo, openMongo } from '@nxgt/mongo';
|
|
12
|
+
import { createSearchSyncs } from '@nxgt/mongo-meilisearch';
|
|
13
|
+
|
|
14
|
+
const mongo = await openMongo(defineMongo({ uri, collections })); // @nxgt/mongo
|
|
15
|
+
|
|
16
|
+
const search = createSearchSyncs(mongo, {
|
|
17
|
+
articles: {
|
|
18
|
+
index: bindIndex(meili, articleIndex), // @nxgt/meilisearch
|
|
19
|
+
// `article` is typed by the collection the key names, and the result
|
|
20
|
+
// by the index this entry carries. `null` keeps a document out.
|
|
21
|
+
transform: (article) =>
|
|
22
|
+
article.draft ? null : { id: String(article._id), title: article.title },
|
|
23
|
+
},
|
|
24
|
+
authors: {
|
|
25
|
+
index: bindIndex(meili, authorIndex),
|
|
26
|
+
transform: (author) => ({ id: String(author._id), name: author.name }),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await search.syncIndexes(); // every index, with its settings
|
|
31
|
+
const running = await search.start(); // reindexes the first time, then follows
|
|
32
|
+
running.failed.catch(exit); // await it or catch it — see Traps
|
|
33
|
+
// …
|
|
34
|
+
await running.close(); // flushes and stops every sync
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Each collection's sync is the `createSearchSync` below, unchanged. What
|
|
38
|
+
`createSearchSyncs` adds is the wiring: the collections come from the Mongo,
|
|
39
|
+
under the key they are exported under (the same one `mongo.db.articles`
|
|
40
|
+
answers to), so nothing is named twice, and the syncs are started and stopped
|
|
41
|
+
together. A key the Mongo wires no collection for does not compile, and is
|
|
42
|
+
refused by name at run time too. `createSearchSyncs` sends nothing:
|
|
43
|
+
`syncIndexes`, `reindexAll` and `start` do. See [Several
|
|
44
|
+
collections](#several-collections-createsearchsyncs) for its API.
|
|
45
|
+
|
|
46
|
+
## One collection at a time
|
|
7
47
|
|
|
8
48
|
```ts
|
|
9
49
|
import { createSearchSync } from '@nxgt/mongo-meilisearch';
|
|
@@ -359,10 +399,76 @@ before it could be read),
|
|
|
359
399
|
`cause`. Its constructor takes `(message, options: SearchSyncErrorOptions)`,
|
|
360
400
|
that is `{ code, sync, cause?, holder?, expiresAt? }`; both types are exported.
|
|
361
401
|
|
|
402
|
+
## Several collections: `createSearchSyncs`
|
|
403
|
+
|
|
404
|
+
```ts
|
|
405
|
+
function createSearchSyncs<C, const I extends IndexMap<I>>(
|
|
406
|
+
mongo: Mongo<C>,
|
|
407
|
+
config: SearchSyncsConfig<C, I>,
|
|
408
|
+
): SearchSyncs<I>;
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
`mongo` is what `@nxgt/mongo`'s `openMongo` returned, and `config` is one entry
|
|
412
|
+
per collection, under the key the Mongo wires it under. An entry is everything
|
|
413
|
+
`createSearchSync` takes **except `collection`**, which the Mongo already
|
|
414
|
+
holds: `index`, `transform`, `toIndexId` (optional while the index's ids are
|
|
415
|
+
strings, required otherwise), and optionally `name`, `stateCollection`,
|
|
416
|
+
`batchSize`, `flushIntervalMs`, `positionIntervalMs`, `leaseMs`, `pageSize` and
|
|
417
|
+
`onHistoryLost`.
|
|
418
|
+
|
|
419
|
+
`SearchSyncs<I>`:
|
|
420
|
+
|
|
421
|
+
| Member | |
|
|
422
|
+
| --- | --- |
|
|
423
|
+
| `syncs: { [K in keyof I]: SearchSync }` | each sync as `createSearchSync` built it, so anything this does not wrap is still reachable |
|
|
424
|
+
| `state()` | where each sync stands, under its key; `undefined` for one that never reindexed |
|
|
425
|
+
| `syncIndexes(options?)` | every index created and its settings applied where they differ: `@nxgt/meilisearch`'s `SyncReport` per key, `dryRun` and `wait` passed through. One after another; the first that throws stops the rest |
|
|
426
|
+
| `reindexAll()` | a `ReindexReport` per key. One after another, and the first that throws stops the rest |
|
|
427
|
+
| `start()` | every sync, resolving once they are all hearing changes; one that fails to start closes the ones already started |
|
|
428
|
+
|
|
429
|
+
`RunningSearchSyncs<I>`, also `AsyncDisposable`:
|
|
430
|
+
|
|
431
|
+
| Member | |
|
|
432
|
+
| --- | --- |
|
|
433
|
+
| `running: { [K in keyof I]: RunningSearchSync }` | each running sync, so its `ready`, its `closed` and its own `flush` are still reachable |
|
|
434
|
+
| `failed: Promise<never>` | rejects with the **first** sync that stops on an error, and never settles otherwise. A later failure is `close()`'s to report |
|
|
435
|
+
| `flush()` | sends what every sync holds, and records where each one is. Stops at the first that fails |
|
|
436
|
+
| `close()` | flushes, then stops every sync. Idempotent |
|
|
437
|
+
|
|
438
|
+
The types: `SearchSyncsConfig<C, I>` (a `SearchSyncEntry` per key of
|
|
439
|
+
`SoleCollections<C>`, and for a key the Mongo wires no collection for, a
|
|
440
|
+
refusal string that names it in place of the entry), `SearchSyncEntry<Col, I>`
|
|
441
|
+
(`Omit<SearchSyncOptions<Col, I>, 'collection'>`), `SoleCollections<C>` (what a
|
|
442
|
+
Mongo's sole database holds, by the name each definition is exported under;
|
|
443
|
+
`never` when it holds several), `IndexMap<I>` (the index definitions a config
|
|
444
|
+
names, from which `I` is inferred, which is what lets a `transform` be written
|
|
445
|
+
inline) and `ByKey<S, T>` (`{ readonly [K in keyof S]: T }`, the shape of every
|
|
446
|
+
per-key result).
|
|
447
|
+
|
|
448
|
+
What it does not do:
|
|
449
|
+
|
|
450
|
+
- **Follow several databases.** A Mongo that holds several gives `never` for
|
|
451
|
+
its keys, as `mongo.db` itself does, and `createSearchSyncs` throws naming
|
|
452
|
+
them. Build one `createSearchSyncs` per database, from a Mongo that wires
|
|
453
|
+
that database alone.
|
|
454
|
+
- **Coordinate processes on its own.** Each entry's sync takes the lease on its
|
|
455
|
+
name when it starts: a second process starting the same syncs is refused
|
|
456
|
+
with `RUNNING` for the first sync whose name is held, and starts nothing.
|
|
457
|
+
- **Own the Mongo.** Closing the search syncs stops them and nothing else:
|
|
458
|
+
the clients, the databases and the collections are the Mongo's, and
|
|
459
|
+
`mongo.close()` is still the caller's to make.
|
|
460
|
+
|
|
461
|
+
The [guides](docs/guide/search-syncs/wiring.md) cover the config and the
|
|
462
|
+
[lifecycle](docs/guide/search-syncs/lifecycle.md) in full.
|
|
463
|
+
|
|
362
464
|
## What does not compile
|
|
363
465
|
|
|
364
466
|
Each is a `@ts-expect-error` case in this package's type tests.
|
|
365
467
|
|
|
468
|
+
- A key the Mongo wires no collection for (the message names it), a key that
|
|
469
|
+
is a member of the driver's `Db`, such as `command`, and a Mongo that holds
|
|
470
|
+
more than one database: all `createSearchSyncs`'s. Its entries are
|
|
471
|
+
checked as below, the `transform` typed by the collection the key names.
|
|
366
472
|
- A transform that reads a field the collection's schema does not have.
|
|
367
473
|
- A transform that leaves out a field the index's document has, or gives an
|
|
368
474
|
id of the wrong type (an `ObjectId` for a string id). A field the document
|
|
@@ -420,9 +526,48 @@ Each is a `@ts-expect-error` case in this package's type tests.
|
|
|
420
526
|
`documents.delete` and `tasks.get`, plus `indexes.create` unless the index
|
|
421
527
|
already exists — the first write to an index that does not creates it.
|
|
422
528
|
|
|
529
|
+
Of `createSearchSyncs`:
|
|
530
|
+
|
|
531
|
+
- **A failure nobody handles is silent, not loud.** A sync that stops on an
|
|
532
|
+
error rejects `failed`, and `createSearchSyncs` takes that rejection itself,
|
|
533
|
+
as it takes each sync's own `closed`, so nothing ends the process and nothing
|
|
534
|
+
is printed. That index simply stops updating. `failed` is the only place the
|
|
535
|
+
failure surfaces, so handle it; unhandled, the first sign is stale search
|
|
536
|
+
results.
|
|
537
|
+
- **`failed` never resolves.** A clean stop is not an event to wait for, so
|
|
538
|
+
`await running.failed` after `close()` waits forever. It is for `catch`, or
|
|
539
|
+
for racing against your own shutdown.
|
|
540
|
+
- **A dropped collection leaves `failed` silent.** An invalidated stream is a
|
|
541
|
+
clean stop (`closed` *resolves* with `'invalidated'`), and `failed` forwards
|
|
542
|
+
failures only. That sync is dead and nothing settles. Watch
|
|
543
|
+
`running.running.<key>.closed` if a drop has to be noticed.
|
|
544
|
+
- **`close()` does not report the failure `failed` already carried.** That one
|
|
545
|
+
sync rejects its own `close` with what it stopped on, and it is swallowed, so
|
|
546
|
+
a caller does not hear it twice. Every *other* failure is thrown, including a
|
|
547
|
+
**second** sync that fell over after `failed` settled, and anything that goes
|
|
548
|
+
wrong *while* closing. If more than one throws, `close` reports the first.
|
|
549
|
+
- **A failed `start()` leaves nothing running.** The syncs already started are
|
|
550
|
+
closed before the error comes back.
|
|
551
|
+
- **`reindexAll()` and `flush()` stop at the first failure.** The keys already
|
|
552
|
+
done are lost with the rejection of `reindexAll`, because a reindex removes
|
|
553
|
+
what a collection no longer gives and a half-finished run is not a state to
|
|
554
|
+
keep going from: read the error, fix, run it again, since the reindexes that
|
|
555
|
+
succeeded are idempotent. A sync that has already fallen over rejects
|
|
556
|
+
`flush` at once and the ones after it are neither sent nor recorded, which is
|
|
557
|
+
safe on restart but not free. `close()` keeps going past a sync that fails.
|
|
558
|
+
- **Two `createSearchSyncs` over one collection are two syncs over one
|
|
559
|
+
index.** The default `name` is `<collection>:<index uid>`, so two built from
|
|
560
|
+
the same config share their resume point and their lease: the second is
|
|
561
|
+
refused with `RUNNING` while the first runs. Give `name` if you mean them to
|
|
562
|
+
differ.
|
|
563
|
+
|
|
423
564
|
## Documentation
|
|
424
565
|
|
|
425
566
|
- [Guide index](docs/README.md) — every page, and when to read it.
|
|
567
|
+
- [Wiring it over a Mongo](docs/guide/search-syncs/wiring.md) — the
|
|
568
|
+
`createSearchSyncs` config, its keys, and every option an entry takes.
|
|
569
|
+
- [The search syncs' lifecycle](docs/guide/search-syncs/lifecycle.md) —
|
|
570
|
+
`syncIndexes`, `reindexAll`, `start`, `failed`, `flush` and `close`.
|
|
426
571
|
- [The sync's lifecycle](docs/guide/sync-lifecycle.md) — the two definitions,
|
|
427
572
|
the transform, and every option with its default.
|
|
428
573
|
- [Reindexing](docs/guide/reindex.md) — the full fill, and what it removes.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { createSearchSync } from './sync/create-search-sync';
|
|
2
2
|
export { SearchSyncError, type SearchSyncErrorCode, type SearchSyncErrorOptions, } from './sync/errors';
|
|
3
3
|
export type { ReindexReport, RunningSearchSync, SearchSync, SearchSyncOptions, SearchSyncState, ToIndexId, Transform, } from './sync/types';
|
|
4
|
+
export { createSearchSyncs } from './syncs/create-search-syncs';
|
|
5
|
+
export type { ByKey, IndexMap, RunningSearchSyncs, SearchSyncEntry, SearchSyncs, SearchSyncsConfig, SoleCollections, } from './syncs/types';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACN,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,GAC3B,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,SAAS,GACT,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACN,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,GAC3B,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,YAAY,EACX,KAAK,EACL,QAAQ,EACR,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,eAAe,GACf,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -551,10 +551,121 @@ function createSearchSync(options) {
|
|
|
551
551
|
state: () => readState(ctx)
|
|
552
552
|
};
|
|
553
553
|
}
|
|
554
|
+
// src/syncs/create-search-syncs.ts
|
|
555
|
+
function soleScope(mongo) {
|
|
556
|
+
const names = Object.keys(mongo.databases);
|
|
557
|
+
if (names.length !== 1) {
|
|
558
|
+
throw new TypeError("createSearchSyncs: this Mongo holds " + `${names.length} databases (${names.join(", ")}), and ` + "createSearchSyncs follows the collections of one. Build one " + "`createSearchSyncs` per database, from a Mongo that wires that " + "database alone");
|
|
559
|
+
}
|
|
560
|
+
return mongo.db;
|
|
561
|
+
}
|
|
562
|
+
function collectionAt(scope, key) {
|
|
563
|
+
const collection = scope[key];
|
|
564
|
+
const definition = typeof collection === "object" && collection !== null ? collection.definition : undefined;
|
|
565
|
+
if (typeof definition !== "object" || definition === null || !("schema" in definition)) {
|
|
566
|
+
throw new TypeError(`createSearchSyncs: this Mongo wires no collection called "${key}"`);
|
|
567
|
+
}
|
|
568
|
+
return collection;
|
|
569
|
+
}
|
|
570
|
+
function createSearchSyncs(mongo, config) {
|
|
571
|
+
const scope = soleScope(mongo);
|
|
572
|
+
const keys = Object.keys(config);
|
|
573
|
+
const syncs = {};
|
|
574
|
+
const indexes = {};
|
|
575
|
+
for (const key of keys) {
|
|
576
|
+
const entry = config[key];
|
|
577
|
+
indexes[key] = entry["index"];
|
|
578
|
+
syncs[key] = createSearchSync({
|
|
579
|
+
...entry,
|
|
580
|
+
collection: collectionAt(scope, key)
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return {
|
|
584
|
+
syncs,
|
|
585
|
+
async state() {
|
|
586
|
+
const state = {};
|
|
587
|
+
for (const key of keys)
|
|
588
|
+
state[key] = await syncs[key].state();
|
|
589
|
+
return state;
|
|
590
|
+
},
|
|
591
|
+
async syncIndexes(options) {
|
|
592
|
+
const reports = {};
|
|
593
|
+
for (const key of keys)
|
|
594
|
+
reports[key] = await indexes[key].sync(options);
|
|
595
|
+
return reports;
|
|
596
|
+
},
|
|
597
|
+
async reindexAll() {
|
|
598
|
+
const reports = {};
|
|
599
|
+
for (const key of keys)
|
|
600
|
+
reports[key] = await syncs[key].reindex();
|
|
601
|
+
return reports;
|
|
602
|
+
},
|
|
603
|
+
async start() {
|
|
604
|
+
const running = {};
|
|
605
|
+
const started = [];
|
|
606
|
+
for (const key of keys) {
|
|
607
|
+
let one;
|
|
608
|
+
try {
|
|
609
|
+
one = await syncs[key].start();
|
|
610
|
+
} catch (error) {
|
|
611
|
+
await Promise.allSettled(started.map((it) => it.close()));
|
|
612
|
+
throw error;
|
|
613
|
+
}
|
|
614
|
+
one.closed.catch(() => {
|
|
615
|
+
return;
|
|
616
|
+
});
|
|
617
|
+
running[key] = one;
|
|
618
|
+
started.push(one);
|
|
619
|
+
}
|
|
620
|
+
return runningSyncs(running, started);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function runningSyncs(running, started) {
|
|
625
|
+
let closing;
|
|
626
|
+
let reported;
|
|
627
|
+
const failed = Promise.race(started.map((one) => one.closed.then(() => new Promise(() => {}), (reason) => {
|
|
628
|
+
reported ??= one;
|
|
629
|
+
throw reason;
|
|
630
|
+
})));
|
|
631
|
+
failed.catch(() => {
|
|
632
|
+
return;
|
|
633
|
+
});
|
|
634
|
+
const close = () => {
|
|
635
|
+
closing ??= (async () => {
|
|
636
|
+
let first;
|
|
637
|
+
let caught = false;
|
|
638
|
+
for (const one of started) {
|
|
639
|
+
try {
|
|
640
|
+
await one.close();
|
|
641
|
+
} catch (error) {
|
|
642
|
+
if (one === reported || caught)
|
|
643
|
+
continue;
|
|
644
|
+
first = error;
|
|
645
|
+
caught = true;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
if (caught)
|
|
649
|
+
throw first;
|
|
650
|
+
})();
|
|
651
|
+
return closing;
|
|
652
|
+
};
|
|
653
|
+
return {
|
|
654
|
+
running,
|
|
655
|
+
failed,
|
|
656
|
+
async flush() {
|
|
657
|
+
for (const one of started)
|
|
658
|
+
await one.flush();
|
|
659
|
+
},
|
|
660
|
+
close,
|
|
661
|
+
[Symbol.asyncDispose]: close
|
|
662
|
+
};
|
|
663
|
+
}
|
|
554
664
|
export {
|
|
555
665
|
SearchSyncError,
|
|
556
|
-
createSearchSync
|
|
666
|
+
createSearchSync,
|
|
667
|
+
createSearchSyncs
|
|
557
668
|
};
|
|
558
669
|
|
|
559
|
-
//# debugId=
|
|
670
|
+
//# debugId=C960A5123B6682B664756E2164756E21
|
|
560
671
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/run/reindex.ts", "../src/sync/batch.ts", "../src/sync/errors.ts", "../src/sync/documents.ts", "../src/sync/running.ts", "../src/sync/state.ts", "../src/run/lease.ts", "../src/sync/context.ts", "../src/run/follow.ts", "../src/sync/start.ts", "../src/sync/create-search-sync.ts"],
|
|
3
|
+
"sources": ["../src/run/reindex.ts", "../src/sync/batch.ts", "../src/sync/errors.ts", "../src/sync/documents.ts", "../src/sync/running.ts", "../src/sync/state.ts", "../src/run/lease.ts", "../src/sync/context.ts", "../src/run/follow.ts", "../src/sync/start.ts", "../src/sync/create-search-sync.ts", "../src/syncs/create-search-syncs.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import type { ResumeToken } from '@nxgt/mongo';\nimport { MeilisearchApiError } from 'meilisearch';\nimport { deleteIds, sendDocuments } from '../sync/batch';\nimport type { Doc, SyncContext } from '../sync/context';\nimport { entryOf, keyOf } from '../sync/documents';\nimport { failed } from '../sync/errors';\nimport { checkIdle } from '../sync/running';\nimport { saveState } from '../sync/state';\nimport type { ReindexReport } from '../sync/types';\nimport { confirmLease, type HeldLease, leaseLost, withLease } from './lease';\n\n/**\n * Where the collection's changes are now, without waiting for one: a new\n * stream's first read answers with its position. The server holds that read\n * for up to `maxAwaitTimeMS` — a second by default, measured.\n */\nasync function currentToken(ctx: SyncContext): Promise<ResumeToken> {\n\tconst stream = ctx.collection.raw.watch([], { maxAwaitTimeMS: 1 });\n\ttry {\n\t\tawait stream.tryNext();\n\t\treturn stream.resumeToken as unknown as ResumeToken;\n\t} finally {\n\t\tawait stream.close();\n\t}\n}\n\n/** Every live document through the transform, a page at a time. */\nasync function sendAll(\n\tctx: SyncContext,\n\twanted: Set<string>,\n\tlease: HeldLease,\n) {\n\tlet indexed = 0;\n\tlet skipped = 0;\n\tlet after: string | null | undefined;\n\tdo {\n\t\tconst page = await ctx.collection.paginateByCursor({\n\t\t\tafter,\n\t\t\tlimit: ctx.pageSize,\n\t\t});\n\t\tconst documents: Doc[] = [];\n\t\tfor (const document of page.items as Doc[]) {\n\t\t\tconst entry = await entryOf(ctx, document['_id'], document);\n\t\t\tif (entry.kind === 'delete') {\n\t\t\t\tskipped += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twanted.add(entry.key);\n\t\t\tdocuments.push(entry.document);\n\t\t}\n\t\tawait sendDocuments(ctx, documents);\n\t\tindexed += documents.length;\n\t\t// Found lost by a renewal: stop sending beside whoever holds it now.\n\t\tif (lease.lost) throw leaseLost(ctx);\n\t\tafter = page.nextCursor;\n\t} while (after);\n\treturn { indexed, skipped };\n}\n\nconst LIST_LIMIT = 1000;\n\n/** Nothing was ever written to it: an index that does not exist holds nothing. */\nconst missingIndex = (error: unknown) =>\n\terror instanceof MeilisearchApiError &&\n\terror.cause?.code === 'index_not_found';\n\n/** Takes out what the index holds and the collection no longer gives it. */\nasync function removeUnwanted(\n\tctx: SyncContext,\n\twanted: Set<string>,\n): Promise<number> {\n\tconst unwanted: unknown[] = [];\n\tfor (let offset = 0; ; offset += LIST_LIMIT) {\n\t\tconst page = await ctx.index.raw\n\t\t\t.getDocuments({ fields: [ctx.primaryKey], limit: LIST_LIMIT, offset })\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (missingIndex(error)) return undefined;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tif (!page) return 0;\n\t\tfor (const document of page.results as Doc[]) {\n\t\t\tconst id = document[ctx.primaryKey];\n\t\t\tif (!wanted.has(keyOf(id))) unwanted.push(id);\n\t\t}\n\t\tif (offset + LIST_LIMIT >= page.total) break;\n\t}\n\tawait deleteIds(ctx, unwanted);\n\treturn unwanted.length;\n}\n\n/**\n * A reindex, holding the sync's lease for as long as it runs: a follower in\n * another process would otherwise have what it just indexed removed, and\n * never send it again.\n */\nexport async function reindex(ctx: SyncContext): Promise<ReindexReport> {\n\tcheckIdle(ctx, 'reindex');\n\treturn withLease(ctx, 'reindex', (lease) => reindexHeld(ctx, lease));\n}\n\n/**\n * A reindex by a caller that holds the lease. What removes documents and what\n * records a point each go only once the server confirms the lease is still\n * this one's: after another process took it over, either would undo what\n * that process just did.\n */\nexport async function reindexHeld(\n\tctx: SyncContext,\n\tlease: HeldLease,\n): Promise<ReindexReport> {\n\ttry {\n\t\t// Taken first: a change made while the documents are read is followed\n\t\t// again from here, so it cannot fall between the two.\n\t\tconst token = await currentToken(ctx);\n\t\tconst wanted = new Set<string>();\n\t\tconst { indexed, skipped } = await sendAll(ctx, wanted, lease);\n\t\tawait confirmLease(ctx, lease);\n\t\tconst removed = await removeUnwanted(ctx, wanted);\n\t\tawait confirmLease(ctx, lease);\n\t\tawait saveState(ctx, token, true);\n\t\treturn { indexed, skipped, removed };\n\t} catch (error) {\n\t\tthrow failed(ctx.name, 'reindexing', error);\n\t}\n}\n",
|
|
6
6
|
"import type { Doc, SyncContext } from './context';\nimport type { Entry } from './documents';\n\n/**\n * How long a write may take to be applied. Meilisearch's own default is\n * five seconds, which a batch on a large index outlasts.\n */\nconst WAIT = { wait: { timeout: 120_000 } } as const;\n\nfunction chunks<T>(items: readonly T[], size: number): T[][] {\n\tconst out: T[][] = [];\n\tfor (let i = 0; i < items.length; i += size) {\n\t\tout.push(items.slice(i, i + size));\n\t}\n\treturn out;\n}\n\n/** Adds documents, `batchSize` at a time, each batch applied before the next. */\nexport async function sendDocuments(\n\tctx: SyncContext,\n\tdocuments: readonly Doc[],\n): Promise<void> {\n\tfor (const batch of chunks(documents, ctx.batchSize)) {\n\t\tawait ctx.index.add(batch, WAIT);\n\t}\n}\n\n/** Deletes documents by id, `batchSize` at a time. */\nexport async function deleteIds(\n\tctx: SyncContext,\n\tids: readonly unknown[],\n): Promise<void> {\n\tfor (const batch of chunks(ids, ctx.batchSize)) {\n\t\tawait ctx.index.delete(batch, WAIT);\n\t}\n}\n\n/**\n * Applies entries: one per id, so adds and deletes touch different\n * documents and their order does not matter.\n */\nexport async function send(\n\tctx: SyncContext,\n\tentries: readonly Entry[],\n): Promise<void> {\n\tconst documents: Doc[] = [];\n\tconst ids: unknown[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.kind === 'upsert') documents.push(entry.document);\n\t\telse ids.push(entry.id);\n\t}\n\tawait sendDocuments(ctx, documents);\n\tawait deleteIds(ctx, ids);\n}\n",
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
"import type { AnyIndexDefinition, TypedIndex } from '@nxgt/meilisearch';\nimport type { AnyCollectionDefinition, TypedCollection } from '@nxgt/mongo';\nimport type { Collection } from 'mongodb';\nimport type { LeaseDocument } from '../run/lease';\nimport type { SearchSyncOptions, SearchSyncState } from './types';\n\n/** Loosely typed: this layer works on any documents; the public types are what callers see. */\nexport type Doc = Record<string, unknown>;\n\n/**\n * What a sync works from, resolved once. Data, and the caller's own two\n * functions as they were given.\n */\nexport interface SyncContext {\n\treadonly name: string;\n\treadonly collection: TypedCollection<AnyCollectionDefinition>;\n\treadonly index: TypedIndex<AnyIndexDefinition>;\n\treadonly primaryKey: string;\n\treadonly state: Collection<SearchSyncState>;\n\t/** The same collection, for the lease documents it also holds. */\n\treadonly leases: Collection<LeaseDocument>;\n\t/** How long a lease lasts unrenewed, in ms. */\n\treadonly leaseMs: number;\n\treadonly batchSize: number;\n\treadonly flushIntervalMs: number;\n\treadonly positionIntervalMs: number;\n\treadonly pageSize: number;\n\treadonly onHistoryLost: 'reindex' | 'fail';\n\treadonly transform: (document: Doc) => unknown;\n\treadonly toIndexId: (id: unknown) => unknown;\n\t/**\n\t * Whether this sync is following changes in this process. A reindex\n\t * beside its own follower would remove what the follower has just\n\t * indexed, and the follower would never send it again.\n\t */\n\treadonly follower: { running: boolean };\n}\n\nconst DEFAULT_STATE_COLLECTION = 'nxgt_search_sync';\n\nfunction positive(option: string, value: number | undefined, fallback: number) {\n\tconst resolved = value ?? fallback;\n\tif (!Number.isInteger(resolved) || resolved < 1) {\n\t\tthrow new TypeError(\n\t\t\t`createSearchSync: ${option} must be a whole number above 0, not ${String(value)}`,\n\t\t);\n\t}\n\treturn resolved;\n}\n\nexport function createContext(\n\toptions: SearchSyncOptions<AnyCollectionDefinition, AnyIndexDefinition>,\n): SyncContext {\n\tconst { collection, index } = options;\n\tif (typeof options.transform !== 'function') {\n\t\tthrow new TypeError('createSearchSync: transform must be a function');\n\t}\n\tconst name = options.name ?? `${collection.collectionName}:${index.uid}`;\n\tif (name === '') {\n\t\tthrow new TypeError('createSearchSync: name must not be empty');\n\t}\n\tconst flushIntervalMs = options.flushIntervalMs ?? 1000;\n\tif (!Number.isInteger(flushIntervalMs) || flushIntervalMs < 0) {\n\t\tthrow new TypeError(\n\t\t\t`createSearchSync: flushIntervalMs must be a whole number of milliseconds, not ${String(options.flushIntervalMs)}`,\n\t\t);\n\t}\n\tconst stateCollection = options.stateCollection ?? DEFAULT_STATE_COLLECTION;\n\treturn {\n\t\tname,\n\t\tcollection,\n\t\tindex,\n\t\tprimaryKey: index.definition.primaryKey as string,\n\t\tstate: collection.db.collection<SearchSyncState>(stateCollection),\n\t\tleases: collection.db.collection<LeaseDocument>(stateCollection),\n\t\tleaseMs: positive('leaseMs', options.leaseMs, 30_000),\n\t\tbatchSize: positive('batchSize', options.batchSize, 500),\n\t\tpositionIntervalMs: positive(\n\t\t\t'positionIntervalMs',\n\t\t\toptions.positionIntervalMs,\n\t\t\t60_000,\n\t\t),\n\t\tflushIntervalMs,\n\t\tpageSize: positive('pageSize', options.pageSize, 100),\n\t\tonHistoryLost: options.onHistoryLost ?? 'reindex',\n\t\ttransform: options.transform as (document: Doc) => unknown,\n\t\ttoIndexId: (options.toIndexId ?? String) as (id: unknown) => unknown,\n\t\tfollower: { running: false },\n\t};\n}\n",
|
|
13
13
|
"import type {\n\tAnyCollectionDefinition,\n\tChangeOf,\n\tChangeSubscription,\n\tCloseReason,\n\tResumeToken,\n} from '@nxgt/mongo';\nimport { send } from '../sync/batch';\nimport type { Doc, SyncContext } from '../sync/context';\nimport { type Entry, entryOf } from '../sync/documents';\nimport { failed, type SearchSyncError } from '../sync/errors';\nimport { clearState, saveState } from '../sync/state';\nimport type { RunningSearchSync } from '../sync/types';\nimport { type HeldLease, keepLease, leaseLost, release } from './lease';\n\nconst noop = () => undefined;\n\n/** What a running sync holds between changes. */\ninterface Following {\n\treadonly pending: Map<string, Entry>;\n\t/** The token of the last change in `pending`. */\n\tlast: ResumeToken | undefined;\n\tsaved: ResumeToken;\n\t/** Changes whose handler has not queued them yet. */\n\tinFlight: number;\n\ttimer: ReturnType<typeof setTimeout> | undefined;\n\t/** Records where the stream is while nothing is being sent. */\n\tbeat: ReturnType<typeof setInterval> | undefined;\n\t/** Stops renewing the lease on the sync's name. */\n\tstopLease: () => void;\n\t/**\n\t * The stream was heard. Only then does `closed` let go of the lease: a\n\t * stream that never got ready leaves it to `start`, which may reindex and\n\t * open again on it after a lost history.\n\t */\n\theard: boolean;\n\t/** Flushes run one after the other. */\n\tchain: Promise<void>;\n\t/** The stream has stopped: what is queued no longer records anything. */\n\tdone: boolean;\n\tfailure: SearchSyncError | undefined;\n}\n\n/**\n * Sends what is pending, then records the token that covers it — or, with\n * nothing to send and no change being handled, where the stream is: a quiet\n * collection would otherwise keep a resume point until the server's history\n * no longer reaches it.\n */\nfunction flush(\n\tctx: SyncContext,\n\tf: Following,\n\tsubscription: ChangeSubscription,\n): Promise<void> {\n\tf.chain = f.chain.then(async () => {\n\t\tif (f.failure) throw f.failure;\n\t\tif (f.done) return;\n\t\tclearTimeout(f.timer);\n\t\tf.timer = undefined;\n\t\tconst entries = [...f.pending.values()];\n\t\tconst upTo = f.last;\n\t\tf.pending.clear();\n\t\ttry {\n\t\t\tif (entries.length > 0) await send(ctx, entries);\n\t\t\tconst idle = entries.length === 0 && f.inFlight === 0;\n\t\t\tconst at = upTo ?? (idle ? subscription.position : undefined);\n\t\t\tif (at && at !== f.saved) {\n\t\t\t\tawait saveState(ctx, at, false);\n\t\t\t\tf.saved = at;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tf.failure ??= failed(ctx.name, 'sending changes', error);\n\t\t\tthrow f.failure;\n\t\t}\n\t});\n\treturn f.chain;\n}\n\n/** A sync that has not heard anything yet, from `token`. */\nfunction following(token: ResumeToken): Following {\n\treturn {\n\t\tpending: new Map(),\n\t\tlast: undefined,\n\t\tsaved: token,\n\t\tinFlight: 0,\n\t\ttimer: undefined,\n\t\tbeat: undefined,\n\t\tstopLease: noop,\n\t\theard: false,\n\t\tchain: Promise.resolve(),\n\t\tdone: false,\n\t\tfailure: undefined,\n\t};\n}\n\n/** Stops everything a running sync does on its own. */\nfunction stopFollowing(ctx: SyncContext, f: Following): void {\n\tf.done = true;\n\tclearTimeout(f.timer);\n\tclearInterval(f.beat);\n\tf.stopLease();\n\tctx.follower.running = false;\n}\n\n/**\n * What `closed` settles to once the stream stops: the reason, or the failure\n * that stopped it — after the last queued flush, and with the lease let go.\n */\nfunction settle(\n\tctx: SyncContext,\n\tf: Following,\n\tsubscription: ChangeSubscription,\n\tlease: HeldLease,\n): Promise<CloseReason> {\n\tconst letGo = () => (f.heard ? release(ctx, lease) : Promise.resolve());\n\treturn subscription.closed.then(\n\t\tasync (reason) => {\n\t\t\tstopFollowing(ctx, f);\n\t\t\ttry {\n\t\t\t\t// A flush the timer or the beat had queued would otherwise record\n\t\t\t\t// a point after this.\n\t\t\t\tawait f.chain.catch(noop);\n\t\t\t\tif (f.failure) throw f.failure;\n\t\t\t\t// The collection is gone, and so is the point the stream stopped\n\t\t\t\t// at: what is recorded is older, and every later start would stop\n\t\t\t\t// here again. Forgetting it makes the next one reindex.\n\t\t\t\tif (reason === 'invalidated') await clearState(ctx);\n\t\t\t\treturn reason;\n\t\t\t} finally {\n\t\t\t\tawait letGo();\n\t\t\t}\n\t\t},\n\t\tasync (error: unknown) => {\n\t\t\tstopFollowing(ctx, f);\n\t\t\tawait letGo();\n\t\t\tthrow f.failure ?? failed(ctx.name, 'following changes', error);\n\t\t},\n\t);\n}\n\nexport async function open(\n\tctx: SyncContext,\n\ttoken: ResumeToken,\n\tlease: HeldLease,\n): Promise<RunningSearchSync> {\n\tconst f = following(token);\n\tconst handle = async (change: ChangeOf<AnyCollectionDefinition>) => {\n\t\tif (f.failure) throw f.failure;\n\t\tf.inFlight += 1;\n\t\tlet entry: Entry;\n\t\ttry {\n\t\t\tconst document =\n\t\t\t\tchange.type === 'delete' ? undefined : (change.document as Doc);\n\t\t\tentry = await entryOf(ctx, change.id, document);\n\t\t} catch (error) {\n\t\t\t// Kept, so `flush` and `close` report it as `closed` does.\n\t\t\tf.failure = failed(ctx.name, 'following changes', error);\n\t\t\tthrow f.failure;\n\t\t} finally {\n\t\t\tf.inFlight -= 1;\n\t\t}\n\t\tf.pending.set(entry.key, entry);\n\t\tf.last = change.resumeToken;\n\t\tif (f.pending.size >= ctx.batchSize) {\n\t\t\tawait flush(ctx, f, subscription);\n\t\t} else if (!f.timer) {\n\t\t\tf.timer = setTimeout(() => {\n\t\t\t\tflush(ctx, f, subscription).catch(() => subscription.close());\n\t\t\t}, ctx.flushIntervalMs);\n\t\t}\n\t};\n\tconst subscription = ctx.collection.onChange(handle, { startAfter: token });\n\tf.beat = setInterval(() => {\n\t\tflush(ctx, f, subscription).catch(() => subscription.close());\n\t}, ctx.positionIntervalMs);\n\t// A lease found gone means another process may be following this name:\n\t// stop at once, before anything else is sent or recorded beside it.\n\tf.stopLease = keepLease(ctx, lease, () => {\n\t\tif (f.failure) return;\n\t\tf.failure = leaseLost(ctx);\n\t\tvoid subscription.close();\n\t});\n\tconst closed = settle(ctx, f, subscription, lease);\n\ttry {\n\t\tawait subscription.ready;\n\t} catch (error) {\n\t\tstopFollowing(ctx, f);\n\t\tclosed.catch(noop);\n\t\tthrow error;\n\t}\n\tf.heard = true;\n\tctx.follower.running = true;\n\tconst close = async () => {\n\t\ttry {\n\t\t\tawait flush(ctx, f, subscription);\n\t\t} finally {\n\t\t\tawait subscription.close();\n\t\t\t// The lease is let go in `closed`'s handler: waited for, so a\n\t\t\t// `reindex` or a `start` right after this finds the name free. Not\n\t\t\t// from inside a change being handled, which `closed` waits for.\n\t\t\tif (f.inFlight === 0) await closed.then(noop, noop);\n\t\t}\n\t};\n\treturn {\n\t\tready: subscription.ready,\n\t\tclosed,\n\t\tflush: () => flush(ctx, f, subscription),\n\t\tclose,\n\t\t[Symbol.asyncDispose]: close,\n\t};\n}\n",
|
|
14
14
|
"import type { ResumeToken } from '@nxgt/mongo';\nimport { open } from '../run/follow';\nimport {\n\tacquire,\n\tconfirmLease,\n\ttype HeldLease,\n\tkeepLease,\n\trelease,\n} from '../run/lease';\nimport { reindexHeld } from '../run/reindex';\nimport type { SyncContext } from './context';\nimport { failed, SearchSyncError } from './errors';\nimport { checkIdle } from './running';\nimport { readState } from './state';\nimport type { RunningSearchSync } from './types';\n\n/** The server no longer has the history a token points into. */\nfunction historyLost(error: unknown): boolean {\n\tconst code = (error as { serverCode?: number } | undefined)?.serverCode;\n\treturn code === 286 || code === 280;\n}\n\n/**\n * Follows the collection from its recorded point — after a reindex when\n * nothing is recorded, or when the point is older than the server's history\n * and `onHistoryLost` allows it.\n */\nexport async function start(ctx: SyncContext): Promise<RunningSearchSync> {\n\tcheckIdle(ctx, 'start it twice');\n\t// Before anything else, the first reindex included: two processes\n\t// starting at once would otherwise both reindex, and both follow.\n\tconst lease = await acquire(ctx, 'start it');\n\t// Renewed while it reindexes, which can outlast `leaseMs`; the follower\n\t// renews it on its own once it is open.\n\tconst stop = keepLease(ctx, lease, () => undefined);\n\ttry {\n\t\tconst running = await startHeld(ctx, lease);\n\t\tstop();\n\t\treturn running;\n\t} catch (error) {\n\t\tstop();\n\t\tawait release(ctx, lease);\n\t\tthrow error;\n\t}\n}\n\n/** Opens the follower, once the server confirms the lease is still held. */\nasync function openHeld(\n\tctx: SyncContext,\n\ttoken: ResumeToken,\n\tlease: HeldLease,\n): Promise<RunningSearchSync> {\n\tawait confirmLease(ctx, lease);\n\treturn open(ctx, token, lease);\n}\n\nasync function startHeld(\n\tctx: SyncContext,\n\tlease: HeldLease,\n): Promise<RunningSearchSync> {\n\tlet state = await readState(ctx);\n\tif (!state) {\n\t\tawait reindexHeld(ctx, lease);\n\t\tstate = await readState(ctx);\n\t}\n\ttry {\n\t\treturn await openHeld(\n\t\t\tctx,\n\t\t\t(state as { resumeToken: ResumeToken }).resumeToken,\n\t\t\tlease,\n\t\t);\n\t} catch (error) {\n\t\tif (!historyLost(error)) throw failed(ctx.name, 'starting', error);\n\t\tif (ctx.onHistoryLost === 'fail') {\n\t\t\tthrow new SearchSyncError(\n\t\t\t\t`Search sync \"${ctx.name}\" was last at a point the server's change ` +\n\t\t\t\t\t'history no longer reaches. Reindex it, or start it with ' +\n\t\t\t\t\t\"onHistoryLost: 'reindex'.\",\n\t\t\t\t{ code: 'HISTORY_LOST', sync: ctx.name, cause: error },\n\t\t\t);\n\t\t}\n\t\tawait reindexHeld(ctx, lease);\n\t\tconst fresh = (await readState(ctx)) as { resumeToken: ResumeToken };\n\t\ttry {\n\t\t\treturn await openHeld(ctx, fresh.resumeToken, lease);\n\t\t} catch (again) {\n\t\t\tthrow failed(ctx.name, 'starting', again);\n\t\t}\n\t}\n}\n",
|
|
15
|
-
"import type { AnyIndexDefinition } from '@nxgt/meilisearch';\nimport type { AnyCollectionDefinition } from '@nxgt/mongo';\nimport { reindex } from '../run/reindex';\nimport { createContext } from './context';\nimport { start } from './start';\nimport { readState } from './state';\nimport type { SearchSync, SearchSyncOptions } from './types';\n\n/**\n * Keeps an index in step with a collection.\n *\n * ```ts\n * const usersSearch = createSearchSync({\n * \tcollection: getCollection(db, users),\n * \tindex: bindIndex(meili, userIndex),\n * \ttransform: (user) => (user.active ? { id: user.id, name: user.name } : null),\n * });\n * const running = await usersSearch.start(); // reindexes the first time\n * // …\n * await running.close();\n * ```\n *\n * Nothing is sent before `reindex` or `start`.\n */\nexport function createSearchSync<\n\tC extends AnyCollectionDefinition,\n\tI extends AnyIndexDefinition,\n>(options: SearchSyncOptions<C, I>): SearchSync {\n\t// The one place the caller's types are let go: a method taking `IdOf<C>`\n\t// is not one taking any id, so the widening cannot be implicit. Below\n\t// here, documents are records and ids are values.\n\tconst ctx = createContext(\n\t\toptions as unknown as SearchSyncOptions<\n\t\t\tAnyCollectionDefinition,\n\t\t\tAnyIndexDefinition\n\t\t>,\n\t);\n\treturn {\n\t\tname: ctx.name,\n\t\treindex: () => reindex(ctx),\n\t\tstart: () => start(ctx),\n\t\tstate: () => readState(ctx),\n\t};\n}\n"
|
|
15
|
+
"import type { AnyIndexDefinition } from '@nxgt/meilisearch';\nimport type { AnyCollectionDefinition } from '@nxgt/mongo';\nimport { reindex } from '../run/reindex';\nimport { createContext } from './context';\nimport { start } from './start';\nimport { readState } from './state';\nimport type { SearchSync, SearchSyncOptions } from './types';\n\n/**\n * Keeps an index in step with a collection.\n *\n * ```ts\n * const usersSearch = createSearchSync({\n * \tcollection: getCollection(db, users),\n * \tindex: bindIndex(meili, userIndex),\n * \ttransform: (user) => (user.active ? { id: user.id, name: user.name } : null),\n * });\n * const running = await usersSearch.start(); // reindexes the first time\n * // …\n * await running.close();\n * ```\n *\n * Nothing is sent before `reindex` or `start`.\n */\nexport function createSearchSync<\n\tC extends AnyCollectionDefinition,\n\tI extends AnyIndexDefinition,\n>(options: SearchSyncOptions<C, I>): SearchSync {\n\t// The one place the caller's types are let go: a method taking `IdOf<C>`\n\t// is not one taking any id, so the widening cannot be implicit. Below\n\t// here, documents are records and ids are values.\n\tconst ctx = createContext(\n\t\toptions as unknown as SearchSyncOptions<\n\t\t\tAnyCollectionDefinition,\n\t\t\tAnyIndexDefinition\n\t\t>,\n\t);\n\treturn {\n\t\tname: ctx.name,\n\t\treindex: () => reindex(ctx),\n\t\tstart: () => start(ctx),\n\t\tstate: () => readState(ctx),\n\t};\n}\n",
|
|
16
|
+
"import type { SyncReport, TypedIndex } from '@nxgt/meilisearch';\nimport type {\n\tAnyCollectionDefinition,\n\tMongo,\n\tTypedCollection,\n} from '@nxgt/mongo';\nimport { createSearchSync } from '../sync/create-search-sync';\nimport type {\n\tReindexReport,\n\tRunningSearchSync,\n\tSearchSync,\n\tSearchSyncState,\n} from '../sync/types';\nimport type {\n\tByKey,\n\tIndexMap,\n\tRunningSearchSyncs,\n\tSearchSyncs,\n\tSearchSyncsConfig,\n} from './types';\n\n/** The Mongo's sole scope, or a refusal naming what to do instead. */\nfunction soleScope(mongo: Mongo<unknown>): Record<string, unknown> {\n\tconst names = Object.keys(mongo.databases);\n\tif (names.length !== 1) {\n\t\tthrow new TypeError(\n\t\t\t'createSearchSyncs: this Mongo holds ' +\n\t\t\t\t`${names.length} databases (${names.join(', ')}), and ` +\n\t\t\t\t'createSearchSyncs follows the collections of one. Build one ' +\n\t\t\t\t'`createSearchSyncs` per database, from a Mongo that wires that ' +\n\t\t\t\t'database alone',\n\t\t);\n\t}\n\treturn mongo.db as unknown as Record<string, unknown>;\n}\n\n/** The collection a key names, refused by name when the Mongo wires none. */\nfunction collectionAt(\n\tscope: Record<string, unknown>,\n\tkey: string,\n): TypedCollection<AnyCollectionDefinition> {\n\tconst collection = scope[key];\n\t// A `Db` answers to its own members, so a key that is one would give\n\t// something that is not a collection rather than `undefined`. A GridFS\n\t// bucket the Mongo wires has a `definition` too, so it is the definition's\n\t// shape that decides: a collection's has a schema, a bucket's has none.\n\tconst definition =\n\t\ttypeof collection === 'object' && collection !== null\n\t\t\t? (collection as { definition?: unknown }).definition\n\t\t\t: undefined;\n\tif (\n\t\ttypeof definition !== 'object' ||\n\t\tdefinition === null ||\n\t\t!('schema' in definition)\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`createSearchSyncs: this Mongo wires no collection called \"${key}\"`,\n\t\t);\n\t}\n\treturn collection as TypedCollection<AnyCollectionDefinition>;\n}\n\n/**\n * The search syncs: one `createSearchSync` per entry, over the collections\n * the Mongo already holds.\n *\n * It is an object of its own rather than something added to the Mongo: the\n * Mongo stays as `openMongo` returned it, and each of the two is closed by\n * whoever opened it. The search syncs close only what they started — the\n * collections, the client and the database are the Mongo's.\n */\nexport function createSearchSyncs<C, const I extends IndexMap<I>>(\n\tmongo: Mongo<C>,\n\tconfig: SearchSyncsConfig<C, I>,\n): SearchSyncs<I> {\n\tconst scope = soleScope(mongo as Mongo<unknown>);\n\tconst keys = Object.keys(config) as (keyof I & string)[];\n\n\tconst syncs = {} as Record<keyof I & string, SearchSync>;\n\tconst indexes = {} as Record<keyof I & string, TypedIndex<never>>;\n\tfor (const key of keys) {\n\t\tconst entry = config[key] as unknown as Record<string, unknown>;\n\t\tindexes[key] = entry['index'] as TypedIndex<never>;\n\t\tsyncs[key] = createSearchSync({\n\t\t\t...entry,\n\t\t\tcollection: collectionAt(scope, key),\n\t\t} as Parameters<typeof createSearchSync>[0]);\n\t}\n\n\treturn {\n\t\tsyncs: syncs as ByKey<I, SearchSync>,\n\n\t\tasync state() {\n\t\t\tconst state = {} as Record<keyof I & string, SearchSyncState | undefined>;\n\t\t\tfor (const key of keys) state[key] = await syncs[key].state();\n\t\t\treturn state as ByKey<I, SearchSyncState | undefined>;\n\t\t},\n\n\t\tasync syncIndexes(options) {\n\t\t\tconst reports = {} as Record<keyof I & string, SyncReport>;\n\t\t\tfor (const key of keys) reports[key] = await indexes[key].sync(options);\n\t\t\treturn reports as ByKey<I, SyncReport>;\n\t\t},\n\n\t\tasync reindexAll() {\n\t\t\tconst reports = {} as Record<keyof I & string, ReindexReport>;\n\t\t\tfor (const key of keys) reports[key] = await syncs[key].reindex();\n\t\t\treturn reports as ByKey<I, ReindexReport>;\n\t\t},\n\n\t\tasync start() {\n\t\t\tconst running = {} as Record<keyof I & string, RunningSearchSync>;\n\t\t\tconst started: RunningSearchSync[] = [];\n\t\t\tfor (const key of keys) {\n\t\t\t\tlet one: RunningSearchSync;\n\t\t\t\ttry {\n\t\t\t\t\tone = await syncs[key].start();\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Nothing half-started: a caller that catches this owns no sync.\n\t\t\t\t\tawait Promise.allSettled(started.map((it) => it.close()));\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\t// Taken the moment the sync exists, not once the loop is done: a\n\t\t\t\t// later `start` reindexes when its key has nothing recorded, which\n\t\t\t\t// is minutes on a real collection, and this sync is already\n\t\t\t\t// following changes throughout. A `closed` that rejects with\n\t\t\t\t// nobody listening ends the process.\n\t\t\t\tone.closed.catch(() => undefined);\n\t\t\t\trunning[key] = one;\n\t\t\t\tstarted.push(one);\n\t\t\t}\n\t\t\treturn runningSyncs(running as ByKey<I, RunningSearchSync>, started);\n\t\t},\n\t};\n}\n\n/** The started syncs: what `start` hands over. */\nfunction runningSyncs<S>(\n\trunning: ByKey<S, RunningSearchSync>,\n\tstarted: RunningSearchSync[],\n): RunningSearchSyncs<S> {\n\tlet closing: Promise<void> | undefined;\n\n\t// `closed` resolves on a clean stop and rejects on a failure. Only the\n\t// rejections are interesting here, so a resolution is turned into a\n\t// promise that never settles — `failed` is what a caller awaits.\n\t//\n\t// The sync whose rejection wins the race is kept, because that is the one\n\t// `failed` reports: `close` stays quiet about that one alone, and still\n\t// throws a *second* sync's failure, which `failed` can no longer carry.\n\tlet reported: RunningSearchSync | undefined;\n\tconst failed = Promise.race(\n\t\tstarted.map((one) =>\n\t\t\tone.closed.then(\n\t\t\t\t() => new Promise<never>(() => {}),\n\t\t\t\t(reason: unknown) => {\n\t\t\t\t\treported ??= one;\n\t\t\t\t\tthrow reason;\n\t\t\t\t},\n\t\t\t),\n\t\t),\n\t);\n\t// And `failed` itself is taken, so that a caller who never looks at it\n\t// does not end the process either.\n\tfailed.catch(() => undefined);\n\n\tconst close = () => {\n\t\tclosing ??= (async () => {\n\t\t\tlet first: unknown;\n\t\t\tlet caught = false;\n\t\t\tfor (const one of started) {\n\t\t\t\ttry {\n\t\t\t\t\tawait one.close();\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// The sync `failed` reported rejects `close` with what it\n\t\t\t\t\t// stopped on. That is `failed`'s to report, not this one's — a\n\t\t\t\t\t// caller should not have to wrap `close` to hear it twice. Any\n\t\t\t\t\t// other failure, and anything that goes wrong *while* closing,\n\t\t\t\t\t// is thrown: the first of them.\n\t\t\t\t\tif (one === reported || caught) continue;\n\t\t\t\t\tfirst = error;\n\t\t\t\t\tcaught = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (caught) throw first;\n\t\t})();\n\t\treturn closing;\n\t};\n\n\treturn {\n\t\trunning,\n\t\tfailed,\n\t\tasync flush() {\n\t\t\tfor (const one of started) await one.flush();\n\t\t},\n\t\tclose,\n\t\t[Symbol.asyncDispose]: close,\n\t};\n}\n"
|
|
16
17
|
],
|
|
17
|
-
"mappings": "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",
|
|
18
|
-
"debugId": "
|
|
18
|
+
"mappings": "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",
|
|
19
|
+
"debugId": "C960A5123B6682B664756E2164756E21",
|
|
19
20
|
"names": []
|
|
20
21
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Mongo } from '@nxgt/mongo';
|
|
2
|
+
import type { IndexMap, SearchSyncs, SearchSyncsConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* The search syncs: one `createSearchSync` per entry, over the collections
|
|
5
|
+
* the Mongo already holds.
|
|
6
|
+
*
|
|
7
|
+
* It is an object of its own rather than something added to the Mongo: the
|
|
8
|
+
* Mongo stays as `openMongo` returned it, and each of the two is closed by
|
|
9
|
+
* whoever opened it. The search syncs close only what they started — the
|
|
10
|
+
* collections, the client and the database are the Mongo's.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createSearchSyncs<C, const I extends IndexMap<I>>(mongo: Mongo<C>, config: SearchSyncsConfig<C, I>): SearchSyncs<I>;
|
|
13
|
+
//# sourceMappingURL=create-search-syncs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-search-syncs.d.ts","sourceRoot":"","sources":["../../src/syncs/create-search-syncs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEX,KAAK,EAEL,MAAM,aAAa,CAAC;AAQrB,OAAO,KAAK,EAEX,QAAQ,EAER,WAAW,EACX,iBAAiB,EACjB,MAAM,SAAS,CAAC;AA2CjB;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,EAC/D,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,MAAM,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,WAAW,CAAC,CAAC,CAAC,CA4DhB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { AnyIndexDefinition, SyncOptions, SyncReport } from '@nxgt/meilisearch';
|
|
2
|
+
import type { AnyCollectionDefinition, CollectionsIn, CollectionsOf, DbName } from '@nxgt/mongo';
|
|
3
|
+
import type { ReindexReport, RunningSearchSync, SearchSync, SearchSyncOptions, SearchSyncState } from '../sync/types';
|
|
4
|
+
/**
|
|
5
|
+
* What a Mongo's sole database holds, by the name each definition is exported
|
|
6
|
+
* under — the same keys `mongo.db` answers to.
|
|
7
|
+
*
|
|
8
|
+
* A Mongo with several databases gives `never`, as `mongo.db` itself does:
|
|
9
|
+
* this version follows the collections of one. See the README.
|
|
10
|
+
*/
|
|
11
|
+
export type SoleCollections<C> = DbName<C> extends infer N extends DbName<C> ? [Exclude<DbName<C>, N>] extends [never] ? CollectionsOf<CollectionsIn<C, N>> : never : never;
|
|
12
|
+
/**
|
|
13
|
+
* One collection's entry: everything `createSearchSync` takes except the
|
|
14
|
+
* collection itself, which the Mongo already holds.
|
|
15
|
+
*/
|
|
16
|
+
export type SearchSyncEntry<Col extends AnyCollectionDefinition, I extends AnyIndexDefinition> = Omit<SearchSyncOptions<Col, I>, 'collection'>;
|
|
17
|
+
/** The index definitions a config names, one per key. */
|
|
18
|
+
export type IndexMap<I> = {
|
|
19
|
+
[K in keyof I]: AnyIndexDefinition;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The config `createSearchSyncs` takes: an entry per collection, under the key
|
|
23
|
+
* the Mongo wires that collection under.
|
|
24
|
+
*
|
|
25
|
+
* `I` is inferred from each entry's `index` alone, which is what lets a
|
|
26
|
+
* `transform` be written inline — its document is typed by the collection the
|
|
27
|
+
* key names, and its result by that index. A key the Mongo wires no collection
|
|
28
|
+
* for is refused by name.
|
|
29
|
+
*/
|
|
30
|
+
export type SearchSyncsConfig<C, I extends IndexMap<I>> = {
|
|
31
|
+
[K in keyof I]: K extends keyof SoleCollections<C> ? SoleCollections<C>[K] extends infer Col extends AnyCollectionDefinition ? SearchSyncEntry<Col, I[K]> : never : {
|
|
32
|
+
index: `createSearchSyncs: this Mongo wires no collection called "${K & string}"`;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** A report per key of the config, under the same names. */
|
|
36
|
+
export type ByKey<S, T> = {
|
|
37
|
+
readonly [K in keyof S]: T;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Every collection's sync, wired to the Mongo's collections — not started.
|
|
41
|
+
*
|
|
42
|
+
* `syncs` is each one as `@nxgt/mongo-meilisearch` builds it, so anything
|
|
43
|
+
* createSearchSyncs does not wrap is still reachable under its key.
|
|
44
|
+
*/
|
|
45
|
+
export interface SearchSyncs<S> {
|
|
46
|
+
/** The syncs, under the keys the config used. */
|
|
47
|
+
readonly syncs: ByKey<S, SearchSync>;
|
|
48
|
+
/** Where each sync stands; `undefined` for one that never reindexed. */
|
|
49
|
+
state(): Promise<ByKey<S, SearchSyncState | undefined>>;
|
|
50
|
+
/**
|
|
51
|
+
* Brings every index the Mongo wires in line with its definition — created
|
|
52
|
+
* with its primary key, its settings updated where they differ — one
|
|
53
|
+
* after another, and reports each under its key. `@nxgt/meilisearch`'s
|
|
54
|
+
* `syncIndex`, per entry; the first that throws stops the rest. `dryRun`
|
|
55
|
+
* shows every settings difference, but a primary-key mismatch throws even
|
|
56
|
+
* then. A deployment step, run before `reindexAll` or `start`.
|
|
57
|
+
*/
|
|
58
|
+
syncIndexes(options?: SyncOptions): Promise<ByKey<S, SyncReport>>;
|
|
59
|
+
/**
|
|
60
|
+
* Reindexes every collection, one after another, and reports each under
|
|
61
|
+
* its key. The first that throws stops the rest — a reindex removes what
|
|
62
|
+
* a collection no longer gives, so a half-finished run is not something
|
|
63
|
+
* to keep going from.
|
|
64
|
+
*/
|
|
65
|
+
reindexAll(): Promise<ByKey<S, ReindexReport>>;
|
|
66
|
+
/**
|
|
67
|
+
* Starts every sync, and resolves once they are all hearing changes. One
|
|
68
|
+
* that fails closes the ones already started, so a failed `start` leaves
|
|
69
|
+
* nothing running.
|
|
70
|
+
*/
|
|
71
|
+
start(): Promise<RunningSearchSyncs<S>>;
|
|
72
|
+
}
|
|
73
|
+
/** Every sync of a started `createSearchSyncs`. */
|
|
74
|
+
export interface RunningSearchSyncs<S> extends AsyncDisposable {
|
|
75
|
+
/** Each running sync, under the keys the config used. */
|
|
76
|
+
readonly running: ByKey<S, RunningSearchSync>;
|
|
77
|
+
/**
|
|
78
|
+
* Rejects with the first sync that stops on an error, and never resolves
|
|
79
|
+
* on its own — a sync that ends because `close` was called is not an
|
|
80
|
+
* event to wait for. **Await it or catch it**: an unhandled rejection
|
|
81
|
+
* ends the process.
|
|
82
|
+
*/
|
|
83
|
+
readonly failed: Promise<never>;
|
|
84
|
+
/** Sends what every sync is holding, and records where each one is. */
|
|
85
|
+
flush(): Promise<void>;
|
|
86
|
+
/** Flushes, then stops every sync. Idempotent. */
|
|
87
|
+
close(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/syncs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACX,uBAAuB,EACvB,aAAa,EACb,aAAa,EACb,MAAM,EACN,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACX,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,MAAM,eAAe,CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAC5B,MAAM,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,GACxC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACtC,aAAa,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAClC,KAAK,GACN,KAAK,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,eAAe,CAC1B,GAAG,SAAS,uBAAuB,EACnC,CAAC,SAAS,kBAAkB,IACzB,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAElD,yDAAyD;AACzD,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,kBAAkB;CAAE,CAAC;AAEjE;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,IAAI;KACxD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,eAAe,CAAC,CAAC,CAAC,GAC/C,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,uBAAuB,GACtE,eAAe,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAC1B,KAAK,GACN;QACA,KAAK,EAAE,6DAA6D,CAAC,GAAG,MAAM,GAAG,CAAC;KAClF;CACH,CAAC;AAEF,4DAA4D;AAC5D,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC;CAAE,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IACrC,wEAAwE;IACxE,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC;IACxD;;;;;;;OAOG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;IAClE;;;;;OAKG;IACH,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/C;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;CACxC;AAED,mDAAmD;AACnD,MAAM,WAAW,kBAAkB,CAAC,CAAC,CAAE,SAAQ,eAAe;IAC7D,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC9C;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,uEAAuE;IACvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,kDAAkD;IAClD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
|
package/docs/README.md
CHANGED
|
@@ -5,7 +5,9 @@ example per area. These pages are the long one.
|
|
|
5
5
|
|
|
6
6
|
| Page | Read it when |
|
|
7
7
|
| --- | --- |
|
|
8
|
-
| [The sync's lifecycle](guide/sync-lifecycle.md) | you are wiring
|
|
8
|
+
| [The sync's lifecycle](guide/sync-lifecycle.md) | you are wiring one collection to an index for the first time, or looking for an option and its default |
|
|
9
|
+
| [Wiring it over a Mongo](guide/search-syncs/wiring.md) | one config has to follow several collections: an index and a transform each, under the keys `openMongo` wires, with `createSearchSyncs` |
|
|
10
|
+
| [The search syncs' lifecycle](guide/search-syncs/lifecycle.md) | you are reindexing, starting the syncs of several collections at once, watching for a failure, or shutting the process down |
|
|
9
11
|
| [Reindexing](guide/reindex.md) | the index has to be filled, or refilled, from the collection |
|
|
10
12
|
| [Following changes](guide/following-changes.md) | a process has to keep the index in step, and stop cleanly; several processes run the same sync and one must follow; or it stopped and you need to know why |
|
|
11
13
|
| [What it leaves out](guide/boundaries.md) | you want to know what the lease on a sync name does not give, are about to join another collection in, or wonder who applies the index settings |
|