@kequtech/tenon-orm 0.4.4 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.5
4
+
5
+ - Preserve generated enum and enum-domain label unions when unrelated codecs change, including
6
+ Date and bigint decoding. Custom enum decoders retain their declared output types; unidentified
7
+ decoders still warn and generate `unknown`. Enum write inputs retain catalog choices.
8
+ - Require pgclear `^0.3.3` for per-type default-decoder metadata and dynamic notification
9
+ subscriptions. Native listeners can add and remove channels on one dedicated connection; see
10
+ [notifications](docs/connections.md#listen-for-notifications) for ownership and recovery.
11
+
3
12
  ## 0.4.4
4
13
 
5
14
  - Pass the shared `TenonConfig` directly to `createTenon`, including its connection, codecs, and
@@ -6,12 +6,13 @@ function columnTypes(column, codecs, path, warn) {
6
6
  warn(`Column ${path} uses a custom decoder without a known TypeScript representation; generated as unknown.`);
7
7
  read = 'unknown';
8
8
  }
9
- const choices = column.choices?.map((choice) => JSON.stringify(choice)).join(' | ') || 'never';
10
- if (column.typeKind === 'e' && codecs === defaultCodecs && read === 'string')
11
- read = choices;
12
9
  let write = defaultCodecs.typescript(oid);
13
- if (column.typeKind === 'e')
10
+ if (column.typeKind === 'e') {
11
+ const choices = column.choices?.map((choice) => JSON.stringify(choice)).join(' | ') || 'never';
12
+ if (read === 'string' && codecs.isDefaultDecoder(oid))
13
+ read = choices;
14
14
  write = choices;
15
+ }
15
16
  if (write === 'unknown' || write.startsWith('PgArray<'))
16
17
  write = 'string';
17
18
  if ([20, 1700].includes(oid))
@@ -181,20 +181,29 @@ During application startup, pass a validated PostgreSQL URI (`connection` below)
181
181
  import { listen } from '@kequtech/pgclear';
182
182
 
183
183
  const listener = await listen(connection, {
184
- channels: ['users_changed'],
184
+ channels: [],
185
185
  onNotification: ({ payload }) => console.log(payload),
186
186
  reconnect: true,
187
187
  });
188
+ // Membership can change on this same connection. Await server registration:
189
+ await listener.subscribe('users_changed');
190
+ // When the channel is no longer needed:
191
+ await listener.unsubscribe('users_changed');
188
192
  // At shutdown:
189
193
  await listener.close();
190
194
  ```
191
195
 
192
- A listener has a separate lifetime and is not closed by `db.close()`. Notifications are not replayed
193
- after a disconnection; the application owns its recovery policy.
196
+ A listener has a separate lifetime and is not closed by `db.close()`. Subscription changes share its
197
+ dedicated connection; reconnect restores the last acknowledged channel set. Subscriptions are set
198
+ operations: repeated subscribes do not add reference counts. Applications own subscriber counts,
199
+ authorization, and routing. Notifications are not replayed after a disconnection; use the listener's
200
+ status/generation changes to detect a possible gap and reconcile persistent state. See
201
+ [pgclear's notification guide](https://github.com/kequtech/pgclear/blob/main/docs/notifications.md)
202
+ for deadlines, cancellation, and changes queued during reconnect.
194
203
 
195
204
  ## Update the driver
196
205
 
197
- Tenon depends on `@kequtech/pgclear: ^0.3.0`, which permits compatible 0.3.x patch updates. With npm:
206
+ Tenon depends on `@kequtech/pgclear: ^0.3.3`, which permits compatible 0.3.x patch updates. With npm:
198
207
 
199
208
  ```sh
200
209
  npm update @kequtech/pgclear
package/docs/reference.md CHANGED
@@ -44,7 +44,7 @@ handling, timeout bounds, and lifecycle examples. Runtime `search_path` is indep
44
44
 
45
45
  ### Driver updates
46
46
 
47
- 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;
48
48
  see [driver updates](connections.md#update-the-driver). Tenon re-exports `builtin`, `json`, `param`,
49
49
  `defaultCodecs`, and `createTemporalCodecs`, with the driver's `Codec`, `CodecRegistry`, `Parameter`,
50
50
  `PgArray`, `TemporalConstructors`, and `TemporalInput` types.
@@ -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,
@@ -200,8 +200,11 @@ configuration needs the corresponding Temporal library declarations.
200
200
 
201
201
  A custom text codec can declare `text.typescript` to describe its non-NULL output. Generation and
202
202
  checking consume the registry's metadata. An unidentified decoder warns and becomes `unknown`;
203
- a declared representation is trusted, not runtime validation. Under a custom registry, enum output
204
- 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.
205
208
 
206
209
  Place the registry in shared `connection.codecs` so runtime, CLI generation, inspection, and source
207
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.4",
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
  }