@nxgt/mongo-kit 0.1.3 → 0.1.5

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.
@@ -0,0 +1,83 @@
1
+ # `discoverCollections`
2
+
3
+ Reads the collection definitions a glob matches, for a **script** that has no
4
+ kit to work from — a sync, a migration, a one-off run from the repository.
5
+
6
+ ```ts
7
+ import { connectMongo, syncCollections } from '@nxgt/mongo';
8
+ import { discoverCollections } from '@nxgt/mongo-kit';
9
+
10
+ const mongo = await connectMongo(process.env.MONGO_URI!);
11
+ const definitions = await discoverCollections({ glob: 'src/**/*.model.ts' });
12
+ await syncCollections(mongo.db, definitions);
13
+ await mongo.close();
14
+ ```
15
+
16
+ It gives `@nxgt/mongo`'s `AnyCollectionDefinition[]`, sorted by path and with
17
+ each definition appearing once.
18
+
19
+ ## It is for scripts, and for nothing else
20
+
21
+ - **It produces no types.** A glob is read at run time, so the compiler sees
22
+ nothing: everything it returns is an `AnyCollectionDefinition`.
23
+ - **It does not survive bundling.** A bundler cannot follow a glob, so the
24
+ matched files are not in the bundle and nothing is found.
25
+ - **It needs the Bun runtime**: the glob is `Bun.Glob`. A Node script gets
26
+ `ReferenceError: Bun is not defined`.
27
+ - **It imports every file it matches**, so their top level runs — and a model
28
+ file's top level registers its definition.
29
+
30
+ An application wires its collections with
31
+ `import * as collections from './models'`, which a bundler follows and the
32
+ compiler sees. See [Configuration](configuration.md).
33
+
34
+ ## Options
35
+
36
+ | Option | Type | Default | Effect |
37
+ | --- | --- | --- | --- |
38
+ | `glob` | `string` | — | Relative to `cwd`: `'src/models/*.model.ts'`. Required |
39
+ | `cwd` | `string` | `process.cwd()` | Where the glob starts |
40
+ | `export` | `string` | — | Read one export by name in each file. Without it, every export that is a definition is taken |
41
+
42
+ ```ts
43
+ // every definition each file exports
44
+ await discoverCollections({ glob: 'test/models/*.model.ts', cwd });
45
+
46
+ // only the export called `definition`, in each matched file
47
+ await discoverCollections({
48
+ glob: 'test/models/*.model.ts',
49
+ cwd,
50
+ export: 'definition',
51
+ });
52
+ ```
53
+
54
+ A glob that matches nothing gives `[]`.
55
+
56
+ ## What it throws
57
+
58
+ All three are a `TypeError`:
59
+
60
+ - `discoverCollections: a glob is required` — `glob` missing or empty.
61
+ - `discoverCollections: <path> exports no definition named "<name>"` — with
62
+ `export`, a matched file that has no definition under that name. Without
63
+ `export`, such a file simply contributes nothing.
64
+ - `discoverCollections: <a> and <b> both define the collection "<name>"` —
65
+ two files describing one server collection.
66
+
67
+ ## Signatures
68
+
69
+ ```ts
70
+ interface DiscoverOptions {
71
+ glob: string;
72
+ cwd?: string;
73
+ export?: string;
74
+ }
75
+
76
+ function discoverCollections(
77
+ options: DiscoverOptions,
78
+ ): Promise<AnyCollectionDefinition[]>;
79
+ ```
80
+
81
+ ## Next
82
+
83
+ - [Syncing](sync.md) — the same step for an application that has a kit.
@@ -0,0 +1,108 @@
1
+ # Syncing
2
+
3
+ `kit.sync()` brings the server in line with the definitions the kit wires:
4
+ the collections, their `$jsonSchema` validators, their collection options and
5
+ their indexes, database by database.
6
+
7
+ ```ts
8
+ import { createKit, defineConfig } from '@nxgt/mongo-kit';
9
+ import * as collections from './models'; // every `defineCollection` of the app
10
+
11
+ await using kit = await createKit(
12
+ defineConfig({ uri: process.env.MONGO_URI!, collections }),
13
+ );
14
+
15
+ const reports = await kit.sync();
16
+ // { default: [ { name: 'posts', created: true, … }, { name: 'users', … } ] }
17
+ ```
18
+
19
+ It reports one `SyncReport[]` per database, under the name the config gave it
20
+ — `default` when it named none. Run it twice and the second run sends
21
+ nothing.
22
+
23
+ ## Options
24
+
25
+ They are `@nxgt/mongo`'s `SyncOptions`, passed through as they are.
26
+
27
+ | Option | Type | Default | Effect |
28
+ | --- | --- | --- | --- |
29
+ | `dryRun` | `boolean` | `false` | Compare and report, send nothing. An option MongoDB cannot change is reported instead of thrown, so one run lists everything that is wrong |
30
+ | `dropUnknownIndexes` | `boolean` | `false` | Drop the indexes the server has and no definition names. `_id_` is never dropped |
31
+ | `session` | `ClientSession` | — | A session for the reads. Never one in a transaction: MongoDB allows neither `collMod` nor an index build inside one |
32
+
33
+ ```ts
34
+ const reports = await kit.sync({ dryRun: true });
35
+ reports.default[0]?.created; // what it would create
36
+ reports.default[0]?.indexes.created; // the indexes it would build
37
+ ```
38
+
39
+ The first database that throws stops the rest, which is what `dryRun` is
40
+ for: it reports everything at once.
41
+
42
+ ## It is a deployment step
43
+
44
+ `collMod` needs the `dbAdmin` role, and an index build runs outside any
45
+ transaction — neither belongs in a request. A script of its own, run before
46
+ the new version serves traffic:
47
+
48
+ ```ts
49
+ // src/sync.ts — `bun run src/sync.ts [--dry-run]`
50
+ import { createKit } from '@nxgt/mongo-kit';
51
+ import { config } from './db';
52
+
53
+ await using kit = await createKit(config);
54
+
55
+ const reports = await kit.sync({ dryRun: process.argv.includes('--dry-run') });
56
+ for (const [database, collections] of Object.entries(reports)) {
57
+ for (const report of collections) {
58
+ console.log(
59
+ `${database}.${report.name}: ${report.created ? 'created' : 'in place'}, ` +
60
+ `${report.indexes.created.length} index(es) created`,
61
+ );
62
+ }
63
+ }
64
+ ```
65
+
66
+ For tests and local development, `autoSync: true` in the
67
+ [configuration](configuration.md) syncs each collection before its first
68
+ operation instead, and no script is needed.
69
+
70
+ ## Why not `syncAll`
71
+
72
+ `@nxgt/mongo`'s `syncAll` works from a global registry, which knows no
73
+ database: it cannot tell the collections of one from those of another.
74
+ `kit.sync()` syncs exactly what the kit wires, on the database each one is
75
+ wired to. For a repository that has no kit — a migration script, a one-off —
76
+ [`discoverCollections`](discover-collections.md) with `syncCollections` is
77
+ the other way round.
78
+
79
+ ## Signatures
80
+
81
+ ```ts
82
+ interface MongoKit<C> {
83
+ sync(options?: SyncOptions): Promise<Record<DbName<C>, SyncReport[]>>;
84
+ }
85
+
86
+ // both from @nxgt/mongo
87
+ interface SyncOptions {
88
+ dryRun?: boolean;
89
+ dropUnknownIndexes?: boolean;
90
+ session?: ClientSession;
91
+ }
92
+
93
+ interface SyncReport {
94
+ name: string;
95
+ created: boolean;
96
+ validator: 'unchanged' | 'created' | 'updated' | 'removed';
97
+ options: { changed: string[]; immutable: OptionMismatch[] };
98
+ indexes: { created: string[]; recreated: string[]; dropped: string[]; unchanged: string[] };
99
+ dryRun: boolean;
100
+ }
101
+ ```
102
+
103
+ ## Next
104
+
105
+ - [`discoverCollections`](discover-collections.md) — syncing from a glob,
106
+ without a kit.
107
+ - [Configuration](configuration.md) — `autoSync`, and the options a
108
+ collection is built with.
@@ -0,0 +1,62 @@
1
+ # Roadmap
2
+
3
+ Where `@nxgt/mongo-kit` is going. A direction, not a commitment: the version
4
+ an item shipped in is the only number on this page.
5
+
6
+ ## Now
7
+
8
+ - **`ping()`** — one call that says whether the databases the kit wires
9
+ answer, and how long they took, for a health endpoint that does not reach
10
+ for the driver itself.
11
+
12
+ ## Next
13
+
14
+ - **Files beside the collections** — a bucket declared in the configuration
15
+ and reached off the kit the way a collection is today, in the kit's session
16
+ and under its actor, so a file write joins a transaction with the documents
17
+ around it.
18
+
19
+ ## Later
20
+
21
+ _Nothing queued._
22
+
23
+ ## Not planned
24
+
25
+ - **A typed `discoverCollections`** — it reads the file system under Bun, has
26
+ no types and does not survive bundling. It is for scripts; an application
27
+ wires its collections in the configuration, as `import * as collections`,
28
+ where they stay typed.
29
+ - **Closing a client the configuration handed over** — the kit gives back only
30
+ the clients it opened, `await using` included. A client you opened is closed
31
+ where it was opened.
32
+ - **A transaction across two clients** — MongoDB refuses a session a client
33
+ does not own, so a transaction reaches one client's databases and `{ on }`
34
+ names which. Two databases on one URI share a client and need no `{ on }`.
35
+ - **`autoSync` as a production setting** — it is for tests and development.
36
+ In production `sync()` is a deployment step: it needs `dbAdmin`, and an
37
+ index build does not run in a transaction.
38
+ - **Wiring a collection under a name the driver's `Db` already answers to** —
39
+ refused by the types where the configuration is written, and again by
40
+ `createKit` against the object itself, so `kit.db.command(…)` is always the
41
+ driver's.
42
+
43
+ ## Shipped
44
+
45
+ - **Documentation that travels with the package** — a guide page for the
46
+ configuration, the `db` scope, actor and transactions, and `sync()`, a
47
+ troubleshooting page whose headings are the exact error text, and this
48
+ roadmap, installed in `docs/` rather than left on GitHub — 0.1.5.
49
+ - **`@nxgt/mongo` 0.15.0** — a deduplicated file write two callers cannot
50
+ both win — 0.1.4.
51
+ - **`@nxgt/mongo` 0.14.0** — files under its `./gridfs` subpath — 0.1.3.
52
+ - **`@nxgt/mongo` 0.13.0** — `upsert` in one round trip — 0.1.2.
53
+ - **`@nxgt/mongo` 0.12.0** — strings from outside read from the schema —
54
+ 0.1.1.
55
+ - **First release** — `defineConfig` checking a configuration of one or
56
+ several databases and freezing it, and `createKit` giving a `db` that is the
57
+ driver's own with every collection typed on it, plus `as(actor)`,
58
+ `withSession`, `transaction`, `sync()` and `close()`; `discoverCollections`
59
+ for scripts — 0.1.0.
60
+
61
+ Everything released is in [`CHANGELOG.md`](https://github.com/softistx/nxgt-data/blob/develop/packages/mongo-kit/CHANGELOG.md) — it is not in
62
+ the published package, only in the repository.