@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.
- package/README.md +15 -0
- package/docs/README.md +14 -0
- package/docs/guide/actor-and-transactions.md +196 -0
- package/docs/guide/configuration.md +229 -0
- package/docs/guide/db-scope.md +173 -0
- package/docs/guide/discover-collections.md +83 -0
- package/docs/guide/sync.md +108 -0
- package/docs/roadmap.md +62 -0
- package/docs/troubleshooting.md +565 -0
- package/package.json +4 -3
|
@@ -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.
|
package/docs/roadmap.md
ADDED
|
@@ -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.
|