@kequtech/tenon-orm 0.4.3 → 0.4.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/docs/reference.md CHANGED
@@ -10,12 +10,19 @@ Requires Node.js 24+, PostgreSQL 16+, and ESM. TypeScript consumers need TypeScr
10
10
  development typings. Install `@kequtech/tenon-orm`; pgclear is included as a runtime dependency.
11
11
 
12
12
  ```text
13
- createTenon({ connection, onQuery? }): Database
13
+ createTenon(config: TenonConfig): Database
14
14
  ```
15
15
 
16
- `connection` is required: a PostgreSQL URI string, pgclear `PoolOptions`, or an existing pgclear
17
- `Pool`. `Connection` names this union; `ConnectionOptions` aliases `PoolOptions`. A supplied pool
18
- retains application ownership. Unknown Tenon or driver configuration options reject.
16
+ Pass one database config directly. Its `connection` holds a PostgreSQL URI, pgclear pool-option
17
+ values, or an application-owned pool. Its optional `onQuery` callback observes runtime queries.
18
+ `ConnectionOptions` aliases pgclear `PoolOptions`; a supplied pool retains application ownership.
19
+ Unknown config keys reject. Connection validation and pool creation wait until the first query,
20
+ transaction, or native-pool access. Closing an unused instance needs no credentials.
21
+
22
+ `tenon init` generates a named `main` config with plain environment reads and no eager credential
23
+ check. Import it and call `createTenon(main)`. Runtime does not discover files. For multiple databases,
24
+ export one config per database and select the matching export in the CLI with `--database`.
25
+ See [shared configuration](configuration.md) for the complete setup.
19
26
 
20
27
  The returned `Database` provides:
21
28
 
@@ -37,7 +44,7 @@ handling, timeout bounds, and lifecycle examples. Runtime `search_path` is indep
37
44
 
38
45
  ### Driver updates
39
46
 
40
- The dependency range is `@kequtech/pgclear: ^0.3.0`. Compatible patches may be updated independently;
47
+ The dependency range is `@kequtech/pgclear: ^0.3.3`. Compatible patches may be updated independently;
41
48
  see [driver updates](connections.md#update-the-driver). Tenon re-exports `builtin`, `json`, `param`,
42
49
  `defaultCodecs`, and `createTemporalCodecs`, with the driver's `Codec`, `CodecRegistry`, `Parameter`,
43
50
  `PgArray`, `TemporalConstructors`, and `TemporalInput` types.
@@ -280,21 +287,23 @@ prepared statements, and dedicated notification listeners.
280
287
 
281
288
  ## Troubleshooting
282
289
 
283
- | Symptom | Response |
284
- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
285
- | Missing shared configuration | Run `tenon init` or select an existing config with `--config`. Generation, checking, and inspection require it. |
286
- | `DATABASE_URL is required` | Supply the variable for migration commands without config, or from your shared config module. No `.env` files are loaded automatically. |
287
- | `PGCLEAR_ENCODE` | Check inputs: objects/arrays need `json`/`param`; direct undefined, unsafe integers, nonfinite numbers, and invalid Dates reject. JSON still rejects bigint. |
288
- | `CardinalityError` | Check the expected row count and predicate. To choose one of several rows, author deterministic `ORDER BY ... LIMIT 1`. |
289
- | `TENON_AFFECTED_ROWS_MISMATCH` | The guarded operation rolled back. Inspect `actual` and the predicate; retain the intended bound. |
290
- | `TENON_AFFECTED_ROWS_UNSUPPORTED` | The final command lacks a supported write count. Use guards on INSERT/UPDATE/DELETE/MERGE; result modes check returned rows. |
291
- | Empty assignments | All selected fields were missing/undefined. Skip the update or branch to an expression-only statement. |
292
- | Duplicate result columns | Alias columns uniquely, especially in joins. The driver rejects duplicate object keys. |
293
- | SQLSTATE `42P18` / `42P08` during inspection | Add the intended parameter cast or Describe OID hints. Inspection binds no values. |
294
- | Checker reports `unchecked` | Follow the diagnostic. Runtime fragments and optional patches can execute correctly yet remain unsupported by source recovery. |
295
- | Missing/stale generated output | Check schema, namespace, registry, driver version, and path. Regenerate, review, and commit intended output. |
296
- | Migration history conflict | Restore original applied files. Add new changes in a forward migration. Checksums include down SQL too. |
297
- | Tooling lock wait | Check concurrent migration/DDL work, use direct or session pooling, and configure server timeouts. |
290
+ | Symptom | Response |
291
+ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
292
+ | Missing shared configuration | Run `tenon init` or select an existing config with `--config`. Generation, checking, and inspection require it. |
293
+ | Multiple databases or unknown database export | Select a named config with `--database name`. Use `--config path` when it belongs to another file. |
294
+ | Missing or empty config connection | Set the environment variable read by that database's config before using it. Imports alone need no credentials. |
295
+ | `DATABASE_URL is required` | Supply the variable for migration commands without config. Tenon does not load `.env` files. |
296
+ | `PGCLEAR_ENCODE` | Check inputs: objects/arrays need `json`/`param`; direct undefined, unsafe integers, nonfinite numbers, and invalid Dates reject. JSON still rejects bigint. |
297
+ | `CardinalityError` | Check the expected row count and predicate. To choose one of several rows, author deterministic `ORDER BY ... LIMIT 1`. |
298
+ | `TENON_AFFECTED_ROWS_MISMATCH` | The guarded operation rolled back. Inspect `actual` and the predicate; retain the intended bound. |
299
+ | `TENON_AFFECTED_ROWS_UNSUPPORTED` | The final command lacks a supported write count. Use guards on INSERT/UPDATE/DELETE/MERGE; result modes check returned rows. |
300
+ | Empty assignments | All selected fields were missing/undefined. Skip the update or branch to an expression-only statement. |
301
+ | Duplicate result columns | Alias columns uniquely, especially in joins. The driver rejects duplicate object keys. |
302
+ | SQLSTATE `42P18` / `42P08` during inspection | Add the intended parameter cast or Describe OID hints. Inspection binds no values. |
303
+ | Checker reports `unchecked` | Follow the diagnostic. Runtime fragments and optional patches can execute correctly yet remain unsupported by source recovery. |
304
+ | Missing/stale generated output | Check schema, namespace, registry, driver version, and path. Regenerate, review, and commit intended output. |
305
+ | Migration history conflict | Restore original applied files. Add new changes in a forward migration. Checksums include down SQL too. |
306
+ | Tooling lock wait | Check concurrent migration/DDL work, use direct or session pooling, and configure server timeouts. |
298
307
 
299
308
  After a guarded query rejects, savepoint cleanup has finished. An unguarded server error normally
300
309
  aborts a transaction. A timeout or lost connection does not itself establish whether a commit
@@ -302,12 +311,14 @@ happened; review the transaction contract before adding retries.
302
311
 
303
312
  ## Command reference
304
313
 
305
- All commands accept `--config path`. `generate`, `check`, and `describe` require
314
+ All commands accept `--config path`. Commands using a database config also accept `--database name`
315
+ to select its export. A file with one config is selected automatically; multiple configs require an
316
+ explicit selection. `generate`, `check`, and `describe` require
306
317
  [shared configuration](configuration.md) and use its connection/codecs. Migration and baseline
307
318
  commands use config when present and fall back to `DATABASE_URL` only when no config is found.
308
319
  `init` creates config without importing application code; `new` uses the configured migration
309
- directory without opening a database; `--help` loads no config.
310
- Config modules may read environment variables, but Tenon loads no `.env` files automatically.
320
+ directory without opening a database; `--help` loads no config. Config modules may read environment variables, but Tenon loads no `.env`
321
+ files automatically.
311
322
  Configured paths resolve from the config file; CLI path flags resolve from the working directory.
312
323
  Unsupported command flags reject.
313
324
 
@@ -131,22 +131,22 @@ well typed; PostgreSQL still enforces constraints.
131
131
  These are the default driver representations. SQL NULL is `null`; nullable generated columns add
132
132
  null to their type. Input encoding and output decoding are separate choices.
133
133
 
134
- | PostgreSQL value | Default read | Plain write input |
135
- | ----------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------- |
136
- | smallint, integer, serial, oid | `number` | `number` |
137
- | bigint, bigserial, `count(*)` | Exact `string` | Exact string or bigint |
138
- | numeric/decimal | `string` | String or bigint |
139
- | real, double precision | `number` | Finite number |
140
- | boolean | `boolean` | Boolean |
141
- | text, UUID, other textual types | `string` | String |
142
- | enum | Catalog label union in default-registry generated rows | Label union |
143
- | date, timestamp, timestamptz | `string` | String, Date, or supported Temporal value |
144
- | time, interval | `string` | String or supported Temporal value |
145
- | timetz | `string` | String |
146
- | json/jsonb | `unknown` | Encoded JSON string; use `json(value)` for a parameter |
147
- | bytea | `Uint8Array` | Uint8Array |
148
- | Supported built-in arrays | Recursive readonly `PgArray<T>` | Encoded PostgreSQL array text; use `param` for an array value |
149
- | Unrecognized types and dynamic enum/domain/extension arrays | Wire-text `string` | Encoded string or explicit parameter |
134
+ | PostgreSQL value | Default read | Plain write input |
135
+ | ----------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------- |
136
+ | smallint, integer, serial, oid | `number` | `number` |
137
+ | bigint, bigserial, `count(*)` | Exact `string` | Exact string or bigint |
138
+ | numeric/decimal | `string` | String or bigint |
139
+ | real, double precision | `number` | Finite number |
140
+ | boolean | `boolean` | Boolean |
141
+ | text, UUID, other textual types | `string` | String |
142
+ | enum | Catalog label union when its decoder remains default | Label union |
143
+ | date, timestamp, timestamptz | `string` | String, Date, or supported Temporal value |
144
+ | time, interval | `string` | String or supported Temporal value |
145
+ | timetz | `string` | String |
146
+ | json/jsonb | `unknown` | Encoded JSON string; use `json(value)` for a parameter |
147
+ | bytea | `Uint8Array` | Uint8Array |
148
+ | Supported built-in arrays | Recursive readonly `PgArray<T>` | Encoded PostgreSQL array text; use `param` for an array value |
149
+ | Unrecognized types and dynamic enum/domain/extension arrays | Wire-text `string` | Encoded string or explicit parameter |
150
150
 
151
151
  Generated inputs conservatively describe column-compatible representations; an explicit `Parameter`
152
152
  is accepted for every writable column. PostgreSQL checks ranges and text formats. Plain undefined,
@@ -163,17 +163,22 @@ both become null. For raw JSON text or Date/bigint outputs, configure codecs.
163
163
 
164
164
  ## Custom codecs
165
165
 
166
- Configure the registry on the application's connection. For example:
166
+ Configure the registry in `tenon.config.ts` so runtime queries and generated declarations use the
167
+ same representations:
167
168
 
168
169
  ```ts
169
- import { builtin, createTenon, defaultCodecs } from '@kequtech/tenon-orm';
170
+ import { builtin, defaultCodecs, type TenonConfig } from '@kequtech/tenon-orm';
170
171
 
171
172
  const codecs = defaultCodecs.with(builtin.int8BigInt).with(builtin.timestamptzDate);
172
- const db = createTenon({ connection: { connectionString: connection, codecs } });
173
+ export const main = {
174
+ connection: { connectionString: process.env.DATABASE_URL, codecs },
175
+ generate: { out: 'src/generated-schema.d.ts' },
176
+ } satisfies TenonConfig;
173
177
  ```
174
178
 
175
- Int8 now reads as bigint, and timestamptz reads as a millisecond-precision Date. Regenerate using this
176
- instance. Scalar overrides affect derived built-in arrays; explicit array overrides win. Date and
179
+ Int8 now reads as bigint, and timestamptz reads as a millisecond-precision Date. Run `tenon generate`
180
+ with this config to update declarations. Scalar overrides affect derived built-in arrays; explicit
181
+ array overrides win. Date and
177
182
  Temporal output codecs reject infinity and values outside their supported ranges.
178
183
 
179
184
  For Temporal, import `createTemporalCodecs` from Tenon and supply a native or compatible polyfill
@@ -195,8 +200,11 @@ configuration needs the corresponding Temporal library declarations.
195
200
 
196
201
  A custom text codec can declare `text.typescript` to describe its non-NULL output. Generation and
197
202
  checking consume the registry's metadata. An unidentified decoder warns and becomes `unknown`;
198
- a declared representation is trusted, not runtime validation. Under a custom registry, enum output
199
- may remain string because a decoder can transform labels; enum write inputs retain catalog choices.
203
+ a declared representation is trusted, not runtime validation. Generated enum rows retain catalog label
204
+ unions when that enum's decoder remains default, including when unrelated Date, bigint, or other
205
+ codecs change. A custom enum decoder uses its own declared output type, or `unknown` with a warning
206
+ when unidentified; declaring `string` does not establish that it preserves catalog labels. Enum write
207
+ inputs retain catalog choices regardless of the output decoder.
200
208
 
201
209
  Place the registry in shared `connection.codecs` so runtime, CLI generation, inspection, and source
202
210
  checking use it consistently. Programmatic inspection/checking inherit `connection.codecs` too. Relative type-import
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kequtech/tenon-orm",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "A PostgreSQL ORM designed for coding agents, with explicit SQL, typed queries, and migrations",
@@ -71,7 +71,7 @@
71
71
  "printWidth": 100
72
72
  },
73
73
  "dependencies": {
74
- "@kequtech/pgclear": "^0.3.0",
74
+ "@kequtech/pgclear": "^0.3.3",
75
75
  "typescript": "~6.0.2"
76
76
  }
77
77
  }