@kequtech/tenon-orm 0.2.0 → 0.2.2
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/CHANGELOG.md +23 -0
- package/README.md +27 -66
- package/dist/connection.d.ts +8 -2
- package/dist/connection.js +13 -0
- package/dist/database.js +35 -8
- package/dist/driver/listener.d.ts +3 -0
- package/dist/driver/listener.js +63 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +15 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/inspection/cli.js +3 -3
- package/dist/inspection/options.d.ts +3 -3
- package/dist/inspection/options.js +9 -1
- package/dist/inspection/types.d.ts +8 -8
- package/dist/query-options.js +2 -2
- package/dist/types.d.ts +8 -1
- package/docs/adoption-guide.md +105 -117
- package/docs/agent-guide.md +114 -217
- package/docs/human-guide.md +35 -47
- package/docs/mutations.md +57 -78
- package/docs/query-inspection.md +99 -89
- package/docs/reference.md +272 -294
- package/package.json +2 -3
package/docs/adoption-guide.md
CHANGED
|
@@ -1,147 +1,135 @@
|
|
|
1
|
-
# Adopting Tenon
|
|
1
|
+
# Adopting Tenon
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[
|
|
6
|
-
application behavior while replacing the old ORM. Tenon does not need to own migrations to execute
|
|
7
|
-
queries or generate types; keep the existing migration runner if that is the intended scope.
|
|
3
|
+
Replace application queries independently of migration ownership. Tenon can query an existing
|
|
4
|
+
schema and generate types while the current migration runner stays in place. For a Tenon version
|
|
5
|
+
upgrade, read the [Changelog](../CHANGELOG.md).
|
|
8
6
|
|
|
9
|
-
##
|
|
7
|
+
## Preserve connections and behavior
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
serialization, and transaction boundaries.
|
|
14
|
-
2. If row and mutation input types will help your application, generate them from the existing database:
|
|
9
|
+
Keep the existing database URI, credentials, TLS requirements, schema, and data. Tenon can add
|
|
10
|
+
driver settings without parsing the URI:
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```
|
|
12
|
+
```ts
|
|
13
|
+
import { createTenon } from '@kequtech/tenon-orm';
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
const db = createTenon({
|
|
16
|
+
connection: { url: existingUri, options: { connect_timeout: 5, idle_timeout: 10 } },
|
|
17
|
+
});
|
|
18
|
+
```
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
and run tests against a dedicated test database. Verify
|
|
30
|
-
writes and rollback, relationships, validation, and any hooks you moved into application code or
|
|
31
|
-
SQL. A schema-preserving first release makes application rollback easier.
|
|
32
|
-
5. Remove the old runtime dependency and unused generated code after its callers are gone. Keep the
|
|
33
|
-
migration tooling until the migration transition below is complete, if that transition is part of
|
|
34
|
-
the work.
|
|
20
|
+
Translate old driver configuration into Postgres.js options rather than passing it through.
|
|
21
|
+
For example, pg's `connectionTimeoutMillis: 5000` becomes `connect_timeout: 5`, and
|
|
22
|
+
`idleTimeoutMillis: 10000` becomes `idle_timeout: 10`; both native options use seconds. Preserve
|
|
23
|
+
runtime `search_path` through URI startup parameters or `options.connection.search_path`.
|
|
24
|
+
URI startup parameters take precedence when both are supplied. CLI `--namespace` does not change
|
|
25
|
+
runtime queries. See [connection options](reference.md#installation-and-connection).
|
|
35
26
|
|
|
36
|
-
|
|
27
|
+
Before conversion, identify behavior supplied by the old ORM: IDs/defaults, timestamps,
|
|
28
|
+
validation, hooks, serialization, relationships, and transaction boundaries. Preserve it explicitly
|
|
29
|
+
in application code or SQL where required.
|
|
37
30
|
|
|
38
|
-
|
|
31
|
+
## Replace queries
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
import { sql } from '@kequtech/tenon-orm';
|
|
33
|
+
1. Optionally generate persistence types from the existing schema:
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```
|
|
35
|
+
```sh
|
|
36
|
+
npx tenon generate --namespace public --out src/generated-schema.d.ts
|
|
37
|
+
```
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
in SQL and remove the local utilities after their callers move. Generated `Rows.Insert` and
|
|
49
|
-
`Rows.Update` types can replace handwritten table inputs; retain application-specific refinements
|
|
50
|
-
and validation. Run the existing write and rollback workflows. See the [mutation cookbook](mutations.md).
|
|
39
|
+
This needs no Tenon migration history. Use the application's namespace and commit exact output.
|
|
51
40
|
|
|
52
|
-
|
|
41
|
+
2. Replace queries with parameterized SQL in ordinary functions accepting `QueryClient` where
|
|
42
|
+
callers may supply `db` or `tx`. Retain projections, ordering, null handling, and authorization.
|
|
43
|
+
3. Review value conversions against [Tenon's mappings](reference.md#generated-types-and-checking):
|
|
44
|
+
bigint/numeric strings, dates, arrays, and native JSON may differ from the previous driver.
|
|
45
|
+
Generated declarations do not replace domain validation.
|
|
46
|
+
4. Inspect meaningful completed query variants and run database assertions for actual rows,
|
|
47
|
+
permissions, write effects, and rollback. See [query inspection](query-inspection.md).
|
|
48
|
+
5. Remove unused runtime dependencies and generated code after their callers are gone. Dependencies
|
|
49
|
+
retained by other application code or installed transitively may still be needed.
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
fragments because it receives the final SQL. See [query inspection](query-inspection.md).
|
|
51
|
+
Check cardinality when replacing a first-row accessor. `oneOrNone` rejects multiple rows and `one`
|
|
52
|
+
also rejects zero rows. Use deterministic `ORDER BY` plus `LIMIT 1` when choosing one of several
|
|
53
|
+
matches is intended; modes do not add a limit.
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
Use `sql.insertValues` and `sql.assignments` to replace object-to-SQL utilities, checking omission,
|
|
56
|
+
default, null, and empty-input semantics. Generated `Rows.Insert`/`Rows.Update` types can replace
|
|
57
|
+
handwritten persistence inputs. See the [mutation cookbook](mutations.md).
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
does not verify a TypeScript annotation or prove that execution is permitted or succeeds. Preserve
|
|
67
|
-
existing authorization policy and transaction boundaries while making queries available to tests.
|
|
59
|
+
Use `tx.query` for work that must commit together. Native pool calls do not join Tenon transactions.
|
|
60
|
+
For driver features, preserve resource ownership and recovery policy under the
|
|
61
|
+
[native access contract](reference.md#native-driver-access).
|
|
68
62
|
|
|
69
|
-
|
|
70
|
-
queries or detect stale annotations elsewhere.
|
|
63
|
+
## Transfer migration ownership
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
Choose one final checkpoint for the old runner. Bring existing databases to it and disable that
|
|
66
|
+
runner before handover; the runners do not share locks. Capture from a trusted reference database,
|
|
67
|
+
preferably a disposable replay of the legacy migrations.
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
Disable its migration/schema synchronization before handing ownership to Tenon. The tools do not
|
|
76
|
-
share locks.
|
|
69
|
+
### Capture a baseline
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
For an application owning `app` in a shared database:
|
|
79
72
|
|
|
80
73
|
```sh
|
|
81
|
-
npx tenon baseline capture --directory migrations --namespace
|
|
74
|
+
npx tenon baseline capture --directory migrations --namespace app --schema app
|
|
82
75
|
```
|
|
83
76
|
|
|
84
|
-
|
|
85
|
-
`0001_baseline.up.sql`
|
|
86
|
-
|
|
87
|
-
explicitly, accounting for dependencies, extensions, and required roles. Tenon's selected history
|
|
88
|
-
table is excluded; old ORM metadata is preserved for deliberate cleanup later.
|
|
89
|
-
|
|
90
|
-
The baseline recreates application schema, not a complete deployment environment. It omits
|
|
91
|
-
ownership, grants/revokes, and default privileges. PostgreSQL creates replayed objects under the
|
|
92
|
-
migration role. Role definitions and memberships also remain outside the dump. Functions,
|
|
93
|
-
policies, or other object definitions can still refer to roles; provision any referenced roles
|
|
94
|
-
before replay. See the [PostgreSQL pg_dump reference](https://www.postgresql.org/docs/16/app-pgdump.html).
|
|
95
|
-
|
|
96
|
-
For `SECURITY DEFINER` functions, the owner determines execution authority, and newly created
|
|
97
|
-
functions ordinarily permit `PUBLIC` execution. A captured function body alone does not preserve
|
|
98
|
-
its original security boundary. Keep fixed application policy, such as revoking `PUBLIC` execution,
|
|
99
|
-
in reviewed SQL in the baseline before its first adoption or in a subsequent application migration.
|
|
100
|
-
Deployment provisioning assigns the intended owners, schema access, and grants to runtime roles.
|
|
101
|
-
Keeping all security setup in provisioning is also supported, provided it runs before application access.
|
|
102
|
-
|
|
103
|
-
On fresh environments, provision required roles, apply migrations, then apply the deployment's
|
|
104
|
-
ownership/grant policy before starting the application. Verify both allowed and denied operations,
|
|
105
|
-
including execution of sensitive functions and access to their underlying tables. For a shared
|
|
106
|
-
database, apply only the selected application's policy. On existing environments, confirm the same
|
|
107
|
-
provisioning procedure is repeatable. After adoption, use subsequent migrations rather than editing
|
|
108
|
-
checksummed history.
|
|
109
|
-
|
|
110
|
-
Capture changes no source data, migration history, or sequence positions. Review and commit the SQL.
|
|
111
|
-
Keep the capture header: it identifies native dump SQL that bypasses the authored-migration scanner.
|
|
112
|
-
It is a convention, not proof of provenance; do not use it on handwritten migrations. Normal
|
|
113
|
-
transactional execution and checksums still apply.
|
|
114
|
-
|
|
115
|
-
On each existing database already at that checkpoint:
|
|
77
|
+
The directory must contain no SQL files. Capture uses native `pg_dump --schema-only --no-owner
|
|
78
|
+
--no-privileges` and writes `0001_baseline.up.sql` with no down file. Install compatible PostgreSQL
|
|
79
|
+
client tools on PATH; prefer the server's major version.
|
|
116
80
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
81
|
+
| Option | Scope |
|
|
82
|
+
| --------------------- | ------------------------------------------------------------------------------------ |
|
|
83
|
+
| `--namespace app` | Tenon history table to exclude from capture; history/runner scope for later commands |
|
|
84
|
+
| `--schema app` | Objects selected by native `pg_dump`; repeat to select additional schemas |
|
|
85
|
+
| Runtime `search_path` | Configured independently on the application connection |
|
|
120
86
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
87
|
+
Omitting `--schema` captures the whole database schema, even with a custom namespace. Capture does
|
|
88
|
+
not modify source data/history or preserve sequence positions. It excludes Tenon's selected history
|
|
89
|
+
table but can retain the old runner's metadata tables. Review and commit the SQL. Preserve the
|
|
90
|
+
capture header, which opts this reviewed dump into native baseline parsing; do not add it to
|
|
91
|
+
handwritten migrations.
|
|
124
92
|
|
|
125
|
-
|
|
93
|
+
A scoped dump can refer to objects it does not include. Provision external schemas, functions,
|
|
94
|
+
extensions, and referenced roles before they are needed. A fresh replay must execute representative
|
|
95
|
+
operations, not just reproduce generated relation types. Tenon requires no particular extension.
|
|
126
96
|
|
|
127
|
-
|
|
128
|
-
npx tenon migrate
|
|
129
|
-
```
|
|
97
|
+
### Check and adopt an existing database
|
|
130
98
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
99
|
+
Verify the final legacy checkpoint before adoption. If using schema comparisons, freeze separate
|
|
100
|
+
reference definitions rather than comparing against types regenerated after later migrations.
|
|
101
|
+
`generateDefinitions` covers relation metadata, not functions or privileges; include reviewed
|
|
102
|
+
catalog checks for other objects the application needs. Tenon does not perform these comparisons.
|
|
134
103
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
the baseline. Keep the application's backup and recovery procedure.
|
|
140
|
-
|
|
141
|
-
Programmatic equivalents:
|
|
104
|
+
```sh
|
|
105
|
+
npx tenon baseline adopt --directory migrations --namespace app
|
|
106
|
+
npx tenon migrate --directory migrations --namespace app
|
|
107
|
+
```
|
|
142
108
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
109
|
+
Adoption records the baseline checksum without executing its SQL. The namespace must already
|
|
110
|
+
exist. Repeating matching adoption is harmless, including after later migrations; history conflicts
|
|
111
|
+
fail. Once Tenon owns history, add forward migrations rather than editing the baseline.
|
|
112
|
+
|
|
113
|
+
### Replay a fresh database
|
|
114
|
+
|
|
115
|
+
Run `tenon migrate --directory migrations --namespace app`, without adoption. It executes the same
|
|
116
|
+
committed baseline and subsequent migrations. Apply the deployment's required roles, ownership,
|
|
117
|
+
and grants before application access.
|
|
118
|
+
|
|
119
|
+
The portable baseline omits ownership, grants/revokes, and default privileges. Objects are recreated
|
|
120
|
+
under the migration role. For `SECURITY DEFINER` functions, that owner controls execution authority,
|
|
121
|
+
and new functions ordinarily permit `PUBLIC` execution. Keep fixed policy such as revoking public
|
|
122
|
+
execution in reviewed baseline SQL before first adoption or in a forward migration. Deployment
|
|
123
|
+
provisioning supplies named roles, owners, and grants. Verify permitted and denied operations on
|
|
124
|
+
both adopted and fresh environments. See the
|
|
125
|
+
[pg_dump contract](https://www.postgresql.org/docs/16/app-pgdump.html).
|
|
126
|
+
|
|
127
|
+
For development, generate types after migrating; production runs migrations and consumes committed
|
|
128
|
+
types. Test existing-row preservation, repeatable adoption, subsequent migrations, and fresh replay.
|
|
129
|
+
A schema-only baseline and down migration are not backups. The missing down file prevents rollback
|
|
130
|
+
across the baseline; use the application's backup/recovery procedure for that boundary.
|
|
131
|
+
|
|
132
|
+
Programmatic capture is `captureBaseline({ connection, directory?, namespace?, schemas?, onWarning? })`
|
|
133
|
+
and returns `{ id, upPath }`. It requires a native libpq connection string; an explicitly empty
|
|
134
|
+
`schemas` list fails. `adoptBaseline({ connection, directory?, namespace? })` accepts Tenon's runtime
|
|
135
|
+
connection forms and returns newly recorded IDs.
|