turbine-orm 0.24.0 → 0.25.0

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.
@@ -89,12 +89,29 @@ const client_js_1 = require("./client.js");
89
89
  * manage its own `pg.Pool`. The caller retains ownership of the pool's
90
90
  * lifecycle — `db.disconnect()` is a no-op.
91
91
  *
92
+ * ## Typed table accessors
93
+ *
94
+ * By default `turbineHttp` returns the base {@link TurbineClient}, so you
95
+ * reach tables through `db.table('users')`. To get the *generated*, fully
96
+ * typed accessors (`db.users.findMany()`) — identical to what the TCP-path
97
+ * `turbine()` factory gives you — pass your generated client type as the
98
+ * `TClient` type argument. The runtime object is the same; the generated
99
+ * subclass only adds `declare readonly` accessor typings, and the base
100
+ * constructor already creates those accessors at runtime for every table in
101
+ * the schema, so the assertion is sound (not a lie about the shape).
102
+ *
103
+ * This closes the "identical typed code across transports" gap: the edge
104
+ * client is now as typed as the direct one, with no `as` casts at the call
105
+ * site.
106
+ *
107
+ * @typeParam TClient - The generated `TurbineClient` subclass (from
108
+ * `./generated/turbine`). Defaults to the base client for back-compat.
92
109
  * @param pool - Any pg-compatible pool (Neon, Vercel Postgres, etc.)
93
110
  * @param schema - Introspected or hand-written schema metadata
94
111
  * @param options - Optional logging / defaultLimit / warnOnUnlimited
95
- * @returns A TurbineClient instance
112
+ * @returns A TurbineClient instance (typed as `TClient`)
96
113
  *
97
- * @example
114
+ * @example Untyped (back-compat) — reach tables via `db.table(...)`
98
115
  * ```ts
99
116
  * import { Pool } from '@neondatabase/serverless';
100
117
  * import { turbineHttp } from 'turbine-orm/serverless';
@@ -102,10 +119,25 @@ const client_js_1 = require("./client.js");
102
119
  *
103
120
  * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
104
121
  * const db = turbineHttp(pool, SCHEMA);
105
- *
106
122
  * const users = await db.table('users').findMany({ limit: 10 });
107
123
  * ```
124
+ *
125
+ * @example Typed — generated accessors, identical to the TCP client
126
+ * ```ts
127
+ * import { Pool } from '@neondatabase/serverless';
128
+ * import { turbineHttp } from 'turbine-orm/serverless';
129
+ * import type { TurbineClient } from './generated/turbine';
130
+ * import { SCHEMA } from './generated/turbine/metadata.js';
131
+ *
132
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
133
+ * const db = turbineHttp<TurbineClient>(pool, SCHEMA);
134
+ * const users = await db.users.findMany({ limit: 10 }); // fully typed, no cast
135
+ * ```
108
136
  */
109
137
  function turbineHttp(pool, schema, options = {}) {
138
+ // The generated subclass only layers `declare readonly` accessor typings
139
+ // over the base client; the base constructor materializes those same
140
+ // accessors at runtime (Object.defineProperty per schema table). So the
141
+ // returned instance genuinely has TClient's shape — the assertion is safe.
110
142
  return new client_js_1.TurbineClient({ pool, ...options }, schema);
111
143
  }
@@ -94,12 +94,29 @@ export interface TurbineHttpOptions extends Pick<TurbineConfig, 'logging' | 'def
94
94
  * manage its own `pg.Pool`. The caller retains ownership of the pool's
95
95
  * lifecycle — `db.disconnect()` is a no-op.
96
96
  *
97
+ * ## Typed table accessors
98
+ *
99
+ * By default `turbineHttp` returns the base {@link TurbineClient}, so you
100
+ * reach tables through `db.table('users')`. To get the *generated*, fully
101
+ * typed accessors (`db.users.findMany()`) — identical to what the TCP-path
102
+ * `turbine()` factory gives you — pass your generated client type as the
103
+ * `TClient` type argument. The runtime object is the same; the generated
104
+ * subclass only adds `declare readonly` accessor typings, and the base
105
+ * constructor already creates those accessors at runtime for every table in
106
+ * the schema, so the assertion is sound (not a lie about the shape).
107
+ *
108
+ * This closes the "identical typed code across transports" gap: the edge
109
+ * client is now as typed as the direct one, with no `as` casts at the call
110
+ * site.
111
+ *
112
+ * @typeParam TClient - The generated `TurbineClient` subclass (from
113
+ * `./generated/turbine`). Defaults to the base client for back-compat.
97
114
  * @param pool - Any pg-compatible pool (Neon, Vercel Postgres, etc.)
98
115
  * @param schema - Introspected or hand-written schema metadata
99
116
  * @param options - Optional logging / defaultLimit / warnOnUnlimited
100
- * @returns A TurbineClient instance
117
+ * @returns A TurbineClient instance (typed as `TClient`)
101
118
  *
102
- * @example
119
+ * @example Untyped (back-compat) — reach tables via `db.table(...)`
103
120
  * ```ts
104
121
  * import { Pool } from '@neondatabase/serverless';
105
122
  * import { turbineHttp } from 'turbine-orm/serverless';
@@ -107,8 +124,19 @@ export interface TurbineHttpOptions extends Pick<TurbineConfig, 'logging' | 'def
107
124
  *
108
125
  * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
109
126
  * const db = turbineHttp(pool, SCHEMA);
110
- *
111
127
  * const users = await db.table('users').findMany({ limit: 10 });
112
128
  * ```
129
+ *
130
+ * @example Typed — generated accessors, identical to the TCP client
131
+ * ```ts
132
+ * import { Pool } from '@neondatabase/serverless';
133
+ * import { turbineHttp } from 'turbine-orm/serverless';
134
+ * import type { TurbineClient } from './generated/turbine';
135
+ * import { SCHEMA } from './generated/turbine/metadata.js';
136
+ *
137
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
138
+ * const db = turbineHttp<TurbineClient>(pool, SCHEMA);
139
+ * const users = await db.users.findMany({ limit: 10 }); // fully typed, no cast
140
+ * ```
113
141
  */
114
- export declare function turbineHttp(pool: PgCompatPool, schema: SchemaMetadata, options?: TurbineHttpOptions): TurbineClient;
142
+ export declare function turbineHttp<TClient extends TurbineClient = TurbineClient>(pool: PgCompatPool, schema: SchemaMetadata, options?: TurbineHttpOptions): TClient;
@@ -86,12 +86,29 @@ import { TurbineClient } from './client.js';
86
86
  * manage its own `pg.Pool`. The caller retains ownership of the pool's
87
87
  * lifecycle — `db.disconnect()` is a no-op.
88
88
  *
89
+ * ## Typed table accessors
90
+ *
91
+ * By default `turbineHttp` returns the base {@link TurbineClient}, so you
92
+ * reach tables through `db.table('users')`. To get the *generated*, fully
93
+ * typed accessors (`db.users.findMany()`) — identical to what the TCP-path
94
+ * `turbine()` factory gives you — pass your generated client type as the
95
+ * `TClient` type argument. The runtime object is the same; the generated
96
+ * subclass only adds `declare readonly` accessor typings, and the base
97
+ * constructor already creates those accessors at runtime for every table in
98
+ * the schema, so the assertion is sound (not a lie about the shape).
99
+ *
100
+ * This closes the "identical typed code across transports" gap: the edge
101
+ * client is now as typed as the direct one, with no `as` casts at the call
102
+ * site.
103
+ *
104
+ * @typeParam TClient - The generated `TurbineClient` subclass (from
105
+ * `./generated/turbine`). Defaults to the base client for back-compat.
89
106
  * @param pool - Any pg-compatible pool (Neon, Vercel Postgres, etc.)
90
107
  * @param schema - Introspected or hand-written schema metadata
91
108
  * @param options - Optional logging / defaultLimit / warnOnUnlimited
92
- * @returns A TurbineClient instance
109
+ * @returns A TurbineClient instance (typed as `TClient`)
93
110
  *
94
- * @example
111
+ * @example Untyped (back-compat) — reach tables via `db.table(...)`
95
112
  * ```ts
96
113
  * import { Pool } from '@neondatabase/serverless';
97
114
  * import { turbineHttp } from 'turbine-orm/serverless';
@@ -99,10 +116,25 @@ import { TurbineClient } from './client.js';
99
116
  *
100
117
  * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
101
118
  * const db = turbineHttp(pool, SCHEMA);
102
- *
103
119
  * const users = await db.table('users').findMany({ limit: 10 });
104
120
  * ```
121
+ *
122
+ * @example Typed — generated accessors, identical to the TCP client
123
+ * ```ts
124
+ * import { Pool } from '@neondatabase/serverless';
125
+ * import { turbineHttp } from 'turbine-orm/serverless';
126
+ * import type { TurbineClient } from './generated/turbine';
127
+ * import { SCHEMA } from './generated/turbine/metadata.js';
128
+ *
129
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
130
+ * const db = turbineHttp<TurbineClient>(pool, SCHEMA);
131
+ * const users = await db.users.findMany({ limit: 10 }); // fully typed, no cast
132
+ * ```
105
133
  */
106
134
  export function turbineHttp(pool, schema, options = {}) {
135
+ // The generated subclass only layers `declare readonly` accessor typings
136
+ // over the base client; the base constructor materializes those same
137
+ // accessors at runtime (Object.defineProperty per schema table). So the
138
+ // returned instance genuinely has TClient's shape — the assertion is safe.
107
139
  return new TurbineClient({ pool, ...options }, schema);
108
140
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbine-orm",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "Postgres-native TypeScript ORM — runs on Neon, Vercel Postgres, Cloudflare, Supabase. Streaming cursors, typed errors, single-query nested relations. One dependency, no WASM engine",
5
5
  "type": "module",
6
6
  "exports": {