joist-orm 2.3.0-next.41 → 2.3.0-next.43

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.
Files changed (95) hide show
  1. package/build/_virtual/_rolldown/runtime.cjs +23 -0
  2. package/build/_virtual/_rolldown/runtime.js +5 -0
  3. package/build/codegen.cjs +19 -0
  4. package/build/codegen.cjs.map +1 -0
  5. package/build/codegen.d.cts +1 -0
  6. package/build/codegen.d.mts +1 -0
  7. package/build/codegen.js +11 -28
  8. package/build/codegen.js.map +1 -1
  9. package/build/drivers/PostgresDriver.cjs +290 -0
  10. package/build/drivers/PostgresDriver.cjs.map +1 -0
  11. package/build/drivers/PostgresDriver.d.cts +77 -0
  12. package/build/drivers/PostgresDriver.d.cts.map +1 -0
  13. package/build/drivers/PostgresDriver.d.mts +77 -0
  14. package/build/drivers/PostgresDriver.d.mts.map +1 -0
  15. package/build/drivers/PostgresDriver.js +249 -325
  16. package/build/drivers/PostgresDriver.js.map +1 -1
  17. package/build/drivers/WireRowData.cjs +374 -0
  18. package/build/drivers/WireRowData.cjs.map +1 -0
  19. package/build/drivers/WireRowData.d.cts +111 -0
  20. package/build/drivers/WireRowData.d.cts.map +1 -0
  21. package/build/drivers/WireRowData.d.mts +111 -0
  22. package/build/drivers/WireRowData.d.mts.map +1 -0
  23. package/build/drivers/WireRowData.js +352 -412
  24. package/build/drivers/WireRowData.js.map +1 -1
  25. package/build/drivers/binaryParsers.cjs +422 -0
  26. package/build/drivers/binaryParsers.cjs.map +1 -0
  27. package/build/drivers/{binaryParsers.d.ts → binaryParsers.d.cts} +18 -14
  28. package/build/drivers/binaryParsers.d.cts.map +1 -0
  29. package/build/drivers/binaryParsers.d.mts +80 -0
  30. package/build/drivers/binaryParsers.d.mts.map +1 -0
  31. package/build/drivers/binaryParsers.js +315 -385
  32. package/build/drivers/binaryParsers.js.map +1 -1
  33. package/build/drivers/patchPgProtocol.cjs +255 -0
  34. package/build/drivers/patchPgProtocol.cjs.map +1 -0
  35. package/build/drivers/{patchPgProtocol.d.ts → patchPgProtocol.d.cts} +18 -14
  36. package/build/drivers/patchPgProtocol.d.cts.map +1 -0
  37. package/build/drivers/patchPgProtocol.d.mts +47 -0
  38. package/build/drivers/patchPgProtocol.d.mts.map +1 -0
  39. package/build/drivers/patchPgProtocol.js +211 -232
  40. package/build/drivers/patchPgProtocol.js.map +1 -1
  41. package/build/graphql-codegen-export.cjs +10 -0
  42. package/build/graphql-codegen-export.d.cts +1 -0
  43. package/build/graphql-codegen-export.d.mts +1 -0
  44. package/build/graphql-codegen-export.js +2 -19
  45. package/build/graphql-export.cjs +10 -0
  46. package/build/graphql-export.d.cts +1 -0
  47. package/build/graphql-export.d.mts +1 -0
  48. package/build/graphql-export.js +2 -19
  49. package/build/index.cjs +41 -0
  50. package/build/index.d.cts +3 -0
  51. package/build/index.d.mts +3 -0
  52. package/build/index.js +3 -27
  53. package/build/knex-export.cjs +10 -0
  54. package/build/knex-export.d.cts +1 -0
  55. package/build/knex-export.d.mts +1 -0
  56. package/build/knex-export.js +2 -19
  57. package/build/pg-export.cjs +13 -0
  58. package/build/pg-export.d.cts +4 -0
  59. package/build/pg-export.d.mts +4 -0
  60. package/build/pg-export.js +4 -20
  61. package/build/pg-migrate.cjs +22 -0
  62. package/build/pg-migrate.cjs.map +1 -0
  63. package/build/pg-migrate.d.cts +1 -0
  64. package/build/pg-migrate.d.mts +1 -0
  65. package/build/pg-migrate.js +13 -28
  66. package/build/pg-migrate.js.map +1 -1
  67. package/build/seed.cjs +49 -0
  68. package/build/seed.cjs.map +1 -0
  69. package/build/{seed.d.ts → seed.d.cts} +5 -1
  70. package/build/seed.d.cts.map +1 -0
  71. package/build/seed.d.mts +24 -0
  72. package/build/seed.d.mts.map +1 -0
  73. package/build/seed.js +39 -45
  74. package/build/seed.js.map +1 -1
  75. package/build/tests-export.cjs +10 -0
  76. package/build/tests-export.d.cts +1 -0
  77. package/build/tests-export.d.mts +1 -0
  78. package/build/tests-export.js +2 -19
  79. package/package.json +150 -28
  80. package/build/codegen.d.ts +0 -2
  81. package/build/drivers/PostgresDriver.d.ts +0 -73
  82. package/build/drivers/WireRowData.d.ts +0 -107
  83. package/build/graphql-codegen-export.d.ts +0 -1
  84. package/build/graphql-codegen-export.js.map +0 -1
  85. package/build/graphql-export.d.ts +0 -1
  86. package/build/graphql-export.js.map +0 -1
  87. package/build/index.d.ts +0 -3
  88. package/build/index.js.map +0 -1
  89. package/build/knex-export.d.ts +0 -1
  90. package/build/knex-export.js.map +0 -1
  91. package/build/pg-export.d.ts +0 -3
  92. package/build/pg-export.js.map +0 -1
  93. package/build/pg-migrate.d.ts +0 -2
  94. package/build/tests-export.d.ts +0 -1
  95. package/build/tests-export.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresDriver.js","sourceRoot":"","sources":["../../src/drivers/PostgresDriver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostgresDriver.js","names":["#idAssigner","#preloadPlugin","#onQuery","#executeFindRowData","#databaseBinaryParsers"],"sources":["../../src/drivers/PostgresDriver.ts"],"sourcesContent":["import {\n type DeleteOp,\n type Driver,\n type EntityManager,\n type IdAssigner,\n type InsertOp,\n JoinRowOperation,\n type JoinRowTodo,\n type OpColumn,\n type ParsedFindQuery,\n PojoRowData,\n type PreloadPlugin,\n type RowData,\n type RuntimeConfig,\n SequenceIdAssigner,\n type Todo,\n type UpdateOp,\n buildRawQuery,\n cleanSql,\n driverAfterBegin,\n driverAfterCommit,\n driverBeforeBegin,\n driverBeforeCommit,\n ensureRectangularArraySizes,\n fail,\n generateOps,\n getRuntimeConfig,\n kq,\n kqDot,\n partition,\n} from \"joist-core\";\nimport pg from \"pg\";\nimport { builtins, getTypeParser } from \"pg-types\";\nimport array from \"postgres-array\";\n\nimport { registerDatabaseBinaryParsers, registerTemporalBinaryParsers } from \"./binaryParsers.ts\";\nimport { ensureLazyDataRows } from \"./patchPgProtocol.ts\";\nimport { executeRowDataQuery, isRowDataCapableClient } from \"./WireRowData.ts\";\n\nexport interface PostgresDriverOpts {\n idAssigner?: IdAssigner;\n /** Sets a default `PreloadPlugin` for any `EntityManager` that uses this driver. */\n preloadPlugin?: PreloadPlugin;\n /** Called after each query is executed, useful for testing/debugging. */\n onQuery?: (sql: string) => void;\n /**\n * Experimental: keeps entity find results as raw wire bytes and decodes each row/column cell\n * lazily on field access, instead of eagerly materializing POJO rows.\n *\n * Applies to unpaginated `em.find`, `em.load`, and o2m/o2o/recursive relation loads against\n * the pure-JS pg client. Other loaders deliberately stay classic: paginated finds (small\n * pages, measured neutral), m2m join-table rows (narrow + fully read, where materialized rows\n * measured faster, and `JoinRows` owns/mutates them), lazy columns, and id/count loaders.\n *\n * Lazy queries also request *binary* result format (prototype), decoding int/bool/float/text\n * cells — and, via the fast paths `setupLatestPgTypes` registers, date/timestamptz cells —\n * wire-bytes -> value with no intermediate strings; numeric/exotic cells render to pg's\n * canonical text and reuse the active text parsers for parity. `JOIST_LAZY_BINARY=0`\n * reverts lazy queries to text-format results. It\n * uses classic rows when the choice is knowable up-front (patching pg-protocol failed, or the\n * client is unsupported, i.e. pg-native — both warn once). If a connection turns out\n * mid-query to use an unpatched pg-protocol copy (a duplicate `pg` install), the query fails\n * with a descriptive error — a misconfiguration CI builds/smoketests will catch immediately.\n * Note deferred decoding also defers custom-parser errors from `await em.find` to first field\n * access. See JS-ROW-STORE-DESIGN.md.\n */\n lazyRows?: boolean;\n}\n\n/**\n * Provides a callback for tests/debugging.\n *\n * We used to get this for-free from knex, but node-pg does not have a `query` event.\n */\ntype OnQuery = ((sql: string) => void) | undefined;\n\n/**\n * Implements the `Driver` interface for Postgres.\n *\n * This is the canonical driver implementation and leverages several aspects of\n * Postgres for the best performance, i.e.:\n *\n * - Deferred foreign key constraints are used to allow bulk inserting/updating\n * all entities without any topographic sorting/ordering issues.\n *\n * - Sequences are used to bulk-assign + then bulk-insert all entities, to again\n * avoid issues with ordering issues (cannot bulk insert A w/o knowing the id of B).\n *\n * - We use a pg-specific bulk update syntax.\n */\nexport class PostgresDriver implements Driver<pg.PoolClient> {\n readonly #idAssigner: IdAssigner;\n readonly #preloadPlugin: PreloadPlugin | undefined;\n readonly #onQuery: OnQuery;\n readonly lazyRows: boolean;\n /** Defined only when `lazyRows` is enabled; its presence is the capability signal the EM checks. */\n readonly executeFindRowData: Driver[\"executeFindRowData\"];\n #databaseBinaryParsers: Promise<void> | undefined = undefined;\n\n constructor(\n readonly pool: pg.Pool,\n opts?: PostgresDriverOpts,\n ) {\n this.#idAssigner =\n opts?.idAssigner ??\n new SequenceIdAssigner(async (sql: string) => {\n this.#onQuery?.(sql);\n return (await pool.query(sql)).rows;\n });\n this.#preloadPlugin = opts?.preloadPlugin;\n this.#onQuery = opts?.onQuery;\n // Lazy rows require pg-protocol to emit lazy DataRows, which we patch in at runtime; if the\n // patch cannot be applied/verified (i.e. future pg-protocol internals changed), stay classic\n this.lazyRows = (opts?.lazyRows ?? false) && ensureLazyDataRows();\n if (opts?.lazyRows && !this.lazyRows) {\n console.warn(\"joist-orm: lazyRows was requested, but patching pg-protocol failed; using classic rows.\");\n }\n this.executeFindRowData = this.lazyRows\n ? (em, parsed, settings) => this.#executeFindRowData(em, parsed, settings)\n : undefined;\n setupLatestPgTypes(getRuntimeConfig().temporal);\n }\n\n async executeFind(\n em: EntityManager,\n parsed: ParsedFindQuery,\n settings: { limit?: number; offset?: number },\n ): Promise<any[]> {\n const { sql, bindings } = buildRawQuery(parsed, { limit: em.entityLimit, ...settings });\n return this.executeQuery(em, sql, bindings);\n }\n\n async #executeFindRowData(\n em: EntityManager,\n parsed: ParsedFindQuery,\n settings: { limit?: number; offset?: number },\n ): Promise<RowData> {\n // Auto-register binary parsers for the db's dynamic-oid text-likes (native enums, citext)\n // once, before our first lazy query; on failure, reset so the next query retries\n await (this.#databaseBinaryParsers ??= registerDatabaseBinaryParsers(this.pool).catch((err) => {\n this.#databaseBinaryParsers = undefined;\n throw err;\n }));\n const { sql, bindings } = buildRawQuery(parsed, { limit: em.entityLimit, ...settings });\n const pgSql = toPgParams(sql);\n this.#onQuery?.(pgSql);\n // Centralize client checkout here (pg-pool rejects Submittables in pool.query), and decide\n // classic-vs-lazy *before* submitting anything, i.e. unsupported clients like pg-native fall\n // back to classic rows rather than failing mid-query\n const txnClient = em.txn as pg.PoolClient | undefined;\n const client = txnClient ?? (await this.pool.connect());\n try {\n if (!isRowDataCapableClient(client)) {\n warnUnsupportedClientOnce();\n return new PojoRowData((await (client as pg.PoolClient).query(pgSql, bindings as any[])).rows);\n }\n return await executeRowDataQuery(client, pgSql, bindings);\n } finally {\n if (!txnClient) client.release();\n }\n }\n\n async executeQuery(em: EntityManager, sql: string, bindings: readonly any[]): Promise<any[]> {\n const pgSql = toPgParams(sql);\n this.#onQuery?.(pgSql);\n const client = this.getMaybeInTxnClient(em);\n return client.query(pgSql, bindings as any[]).then((result) => result.rows);\n }\n\n async transaction<T>(em: EntityManager, fn: (txn: pg.PoolClient) => Promise<T>): Promise<T> {\n if (em.txn) {\n return fn(em.txn as pg.PoolClient);\n }\n const client = await this.pool.connect();\n let result: T;\n try {\n await driverBeforeBegin(em, client);\n this.#onQuery?.(\"BEGIN;\");\n await client.query(\"BEGIN\");\n em.txn = client;\n try {\n await driverAfterBegin(em, client);\n result = await fn(client);\n await driverBeforeCommit(em, client);\n this.#onQuery?.(\"COMMIT;\");\n await client.query(\"COMMIT\");\n } catch (e) {\n await client.query(\"ROLLBACK\");\n throw e;\n } finally {\n em.txn = undefined;\n }\n await driverAfterCommit(em, client);\n } finally {\n client.release();\n }\n return result;\n }\n\n async assignNewIds(_: EntityManager, todos: Record<string, Todo>): Promise<void> {\n return this.#idAssigner.assignNewIds(todos);\n }\n\n async flush(\n em: EntityManager,\n entityTodos: Record<string, Todo>,\n joinRows: Record<string, JoinRowTodo>,\n ): Promise<void> {\n const client = (em.txn ?? fail(\"Expected EntityManager.txn to be set\")) as pg.PoolClient;\n await this.#idAssigner.assignNewIds(entityTodos);\n const ops = generateOps(entityTodos);\n const onQuery = this.#onQuery;\n // Do INSERTs+UPDATEs first so that we avoid DELETE cascades invalidating oplocks\n // See https://github.com/joist-orm/joist-orm/issues/591\n await Promise.all([\n ...ops.inserts.map((op) => batchInsert(client, op, onQuery)),\n ...ops.updates.map((op) => batchUpdate(client, op, onQuery)),\n ...ops.deletes.map((op) => batchDelete(client, op, onQuery)),\n ...Object.entries(joinRows).flatMap(([joinTableName, todo]) => {\n return [\n m2mBatchInsert(client, joinTableName, todo, onQuery),\n m2mBatchDelete(client, joinTableName, todo, onQuery),\n ];\n }),\n ]);\n }\n\n get defaultPlugins() {\n return { preloadPlugin: this.#preloadPlugin };\n }\n\n private getMaybeInTxnClient(em: EntityManager): pg.PoolClient | pg.Pool {\n return (em.txn as pg.PoolClient) || this.pool;\n }\n}\n\nasync function batchInsert(client: pg.PoolClient, op: InsertOp, onQuery: OnQuery): Promise<unknown> {\n const { tableName, columns, columnValues } = op;\n const [cte, bindings] = buildUnnestCte(\"data\", columns, columnValues);\n const sql = cleanSql(`\n ${cte}\n INSERT INTO ${kq(tableName)} (${columns.map((c) => kq(c.columnName)).join(\", \")})\n SELECT * FROM data\n `);\n const pgSql = toPgParams(sql);\n onQuery?.(pgSql);\n return client.query(pgSql, bindings);\n}\n\nasync function batchUpdate(client: pg.PoolClient, op: UpdateOp, onQuery: OnQuery): Promise<void> {\n const { tableName, columns, columnValues, updatedAt } = op;\n\n const [cte, bindings] = buildUnnestCte(\"data\", columns, columnValues);\n\n // JS Dates only have millisecond-level precision, so we may have dropped/lost accuracy when\n // reading Postgres's microsecond-level `timestamptz` values; using `date_trunc` \"downgrades\"\n // the pg data to match what we have in the JS Date.\n //\n // ...but Temporal's types don't have this flaw.\n const truncateToMills = !getRuntimeConfig().temporal;\n const maybeUpdatedAt =\n updatedAt && truncateToMills\n ? ` AND date_trunc('milliseconds', ${kqDot(tableName, updatedAt)}) = data.__original_updated_at`\n : updatedAt\n ? ` AND ${kqDot(tableName, updatedAt)} = data.__original_updated_at`\n : \"\";\n\n const sql = `\n ${cte}\n UPDATE ${kq(tableName)}\n SET ${columns\n .filter((c) => c.columnName !== \"id\" && c.columnName !== \"__original_updated_at\")\n .map((c) => `${kq(c.columnName)} = data.${kq(c.columnName)}`)\n .join(\", \")}\n FROM data\n WHERE ${kq(tableName)}.id = data.id ${maybeUpdatedAt}\n RETURNING ${kq(tableName)}.id\n `;\n\n const pgSql = toPgParams(cleanSql(sql));\n onQuery?.(pgSql);\n const result = await client.query(pgSql, bindings);\n const results = result.rows;\n\n const ids = columnValues[0]; // assume id is the 1st column\n if (results.length !== ids.length) {\n const updated = new Set(results.map((r: any) => r.id));\n const missing = ids.filter((id) => !updated.has(id));\n throw new Error(`Oplock failure for ${tableName} rows ${missing.join(\", \")}`);\n }\n}\n\nasync function batchDelete(client: pg.PoolClient, op: DeleteOp, onQuery: OnQuery): Promise<void> {\n const { tableName, ids } = op;\n const pgSql = toPgParams(`DELETE FROM ${kq(tableName)} WHERE id = ANY(?)`);\n onQuery?.(pgSql);\n await client.query(pgSql, [ids]);\n}\n\n/** Creates a CTE named `tableName` that bulk-injects the `columnValues` into a SQL query. */\nfunction buildUnnestCte(tableName: string, columns: OpColumn[], columnValues: any[][]): [string, any[][]] {\n ensureRectangularArraySizes(columns, columnValues);\n const selects = columns.map((c) => {\n if (c.dbType.endsWith(\"[]\")) {\n if (c.isNullableArray) {\n return `unnest_arrays(?::${c.dbType}[], true) as ${kq(c.columnName)}`;\n } else {\n return `unnest_arrays(?::${c.dbType}[]) as ${kq(c.columnName)}`;\n }\n } else {\n return `unnest(?::${c.dbType}[]) as ${kq(c.columnName)}`;\n }\n });\n const sql = `WITH ${tableName} AS (SELECT ${selects.join(\", \")})`;\n return [sql, columnValues];\n}\n\nasync function m2mBatchInsert(client: pg.PoolClient, joinTableName: string, todo: JoinRowTodo, onQuery: OnQuery) {\n const { m2m, newRows } = todo;\n if (newRows.length === 0) return;\n const col1Values = newRows.map((row) => todo.dbValue(row, m2m.columnName));\n const col2Values = newRows.map((row) => todo.dbValue(row, m2m.otherColumnName));\n if (m2m.hasJoinTableId) {\n const sql = cleanSql(`\n WITH data AS (SELECT unnest(?::int[]) as ${kq(m2m.columnName)}, unnest(?::int[]) as ${kq(m2m.otherColumnName)})\n INSERT INTO ${kq(joinTableName)} (${kq(m2m.columnName)}, ${kq(m2m.otherColumnName)})\n SELECT * FROM data\n ON CONFLICT (${kq(m2m.columnName)}, ${kq(m2m.otherColumnName)}) DO UPDATE SET id = ${kq(joinTableName)}.id\n RETURNING id;\n `);\n const pgSql = toPgParams(sql);\n onQuery?.(pgSql);\n const { rows } = await client.query(pgSql, [col1Values, col2Values]);\n for (let i = 0; i < rows.length; i++) {\n newRows[i].id = rows[i].id;\n newRows[i].op = JoinRowOperation.Flushed;\n newRows[i].persisted = true;\n }\n } else {\n // Id-less join tables have no surrogate id to return; the FK pair is the PK, so just\n // insert and let any duplicate be a no-op.\n const sql = cleanSql(`\n WITH data AS (SELECT unnest(?::int[]) as ${kq(m2m.columnName)}, unnest(?::int[]) as ${kq(m2m.otherColumnName)})\n INSERT INTO ${kq(joinTableName)} (${kq(m2m.columnName)}, ${kq(m2m.otherColumnName)})\n SELECT * FROM data\n ON CONFLICT (${kq(m2m.columnName)}, ${kq(m2m.otherColumnName)}) DO NOTHING;\n `);\n const pgSql = toPgParams(sql);\n onQuery?.(pgSql);\n await client.query(pgSql, [col1Values, col2Values]);\n for (const row of newRows) {\n row.op = JoinRowOperation.Flushed;\n row.persisted = true;\n }\n }\n}\n\nasync function m2mBatchDelete(client: pg.PoolClient, joinTableName: string, todo: JoinRowTodo, onQuery: OnQuery) {\n const { m2m, deletedRows } = todo;\n if (deletedRows.length === 0) return;\n // Rows with a surrogate id are deleted by id; rows without one — id-less tables, or `remove`s\n // done against an unloaded ManyToManyCollection — are deleted by their (col1, col2) composite.\n const [haveIds, noIds] = partition(deletedRows, (r) => {\n // We used to use `id !== -1` as a marker for \"row is/is-not persisted in the db\" -- but when adding support\n // for id-column-less m2m tables, we couldn't use `id === -1` as this marker anymore, so now rely on a dedicated\n // `persisted` key instead.\n //\n // So, ideally, this `id !== -1` could go away _except_ that our internal verisoning plugin leverages this \"m2m rows\n // with an id=-1 delete by their FK values\" to handle our versioned m2m tables. And for now it's easier to\n // keep/restore this `id !== -1` than refactor that.\n return r.id !== undefined && r.id !== -1;\n });\n if (haveIds.length > 0) {\n const pgSql = toPgParams(`DELETE FROM ${kq(joinTableName)} WHERE id = ANY(?)`);\n onQuery?.(pgSql);\n await client.query(pgSql, [haveIds.map((r) => r.id!)]);\n }\n if (noIds.length > 0) {\n const data = noIds\n // Watch for m2m rows that got added-then-removed to entities that were themselves added-then-removed,\n // as the deTagId will be undefined for those, as we're skipping adding them to the database.\n .filter((row) => !todo.isNew(row, m2m.columnName) && !todo.isNew(row, m2m.otherColumnName))\n .map((row) => [todo.dbValue(row, m2m.columnName), todo.dbValue(row, m2m.otherColumnName)] as any);\n if (data.length > 0) {\n const pgSql = toPgParams(`\n DELETE FROM ${kq(joinTableName)}\n WHERE (${kq(m2m.columnName)}, ${kq(m2m.otherColumnName)}) IN (\n SELECT (data->>0)::int, (data->>1)::int FROM jsonb_array_elements(?) data\n )`);\n onQuery?.(pgSql);\n await client.query(pgSql, [JSON.stringify(data)]);\n }\n }\n deletedRows.forEach((row) => {\n row.id = undefined;\n row.persisted = false;\n row.op = JoinRowOperation.Flushed;\n });\n}\n\n/**\n * Configures the `pg` driver with the best type parsers.\n *\n * In particular, pg's default `TIMESTAMPTZ` parser is very inefficient, and even just\n * pulling in the latest `pg-types` and installing the fixed parser makes a noticable\n * difference.\n */\nexport function setupLatestPgTypes(temporal: RuntimeConfig[\"temporal\"]): void {\n if (temporal) {\n // Don't eagerly parse the strings, instead defer to the serde logic. This only governs\n // classic *text* results (knex, pool.query, non-lazy drivers); binary lazy cells construct\n // Temporal values directly, with no strings involved (see registerTemporalBinaryParsers).\n const noop = (s: string) => s;\n const noopArray = (s: string) => array.parse(s, noop);\n\n const { TIMESTAMP, TIMESTAMPTZ, DATE } = pg.types.builtins;\n pg.types.setTypeParser(DATE, noop);\n pg.types.setTypeParser(TIMESTAMP, noop);\n pg.types.setTypeParser(TIMESTAMPTZ, noop);\n\n // Use `as number` b/c the typings of shadowed pg-types from `pg` and `pg-types` top-level don't line up\n pg.types.setTypeParser(1182 as number, noopArray); // date[]\n pg.types.setTypeParser(1115 as number, noopArray); // timestamp[]\n pg.types.setTypeParser(1185 as number, noopArray); // timestamptz[]\n\n registerTemporalBinaryParsers();\n } else {\n pg.types.setTypeParser(pg.types.builtins.TIMESTAMPTZ, getTypeParser(builtins.TIMESTAMPTZ));\n // The binary registry's date/timestamp/timestamptz builtins already decode to Dates\n }\n}\n\nconst questionMarks = /(?<!@)\\?/g;\n\n/**\n * Converts our knex-style `?` placeholders to pg-native `$1, $2, ...` numbered parameters.\n *\n * We skipping postgres operators like `@?`. */\nfunction toPgParams(sql: string): string {\n let i = 0;\n return sql.replace(questionMarks, () => `$${++i}`);\n}\n\nlet warnedUnsupportedClient = false;\n\n/** Warns once when lazyRows degrades to classic rows for an unsupported client, i.e. pg-native. */\nfunction warnUnsupportedClientOnce(): void {\n if (warnedUnsupportedClient) return;\n warnedUnsupportedClient = true;\n console.warn(\"joist-orm: lazyRows is enabled, but this client does not support it; using classic rows.\");\n}\n"],"mappings":"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"}
@@ -0,0 +1,374 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
+ const require_drivers_binaryParsers = require("./binaryParsers.cjs");
4
+ require("joist-core");
5
+ let pg = require("pg");
6
+ pg = require_runtime.__toESM(pg, 1);
7
+ //#region src/drivers/WireRowData.ts
8
+ const PgQuery = (0, require("node:module").createRequire)(require("url").pathToFileURL(__filename).href)("pg/lib/query");
9
+ const ROW_STRIDE = 3;
10
+ /** The row-length sentinel for rows dropped by `finalize` compaction. */
11
+ const DROPPED = 4294967295;
12
+ /** Only compact when dropped rows hold more than this fraction of the payload bytes. */
13
+ const COMPACT_THRESHOLD = .2;
14
+ /**
15
+ * Only allocate the adaptive scan cursor once a fault targets at least this ordinal: shallower
16
+ * scans cost less than the cursor's bookkeeping, i.e. hydrate-only results (id is ordinal ~0)
17
+ * and narrow reads never pay the 6 bytes/row.
18
+ */
19
+ const SCAN_CURSOR_MIN_ORDINAL = 8;
20
+ /**
21
+ * A lazy wire-row {@link RowData} over raw Postgres `DataRow` payload bytes.
22
+ *
23
+ * Each query produces its own `WireRowData` — one query, one result; results are never combined
24
+ * or appended across queries, and the payload is read-only after the query completes (entity
25
+ * mutations go into `InstanceData.data`, never back into the row bytes).
26
+ *
27
+ * Rows are kept in their row-major wire format (`int16 fieldCount` + length-prefixed cells) as
28
+ * zero-copy views over the parser's own immutable buffers: `addRow` records each DataRow's
29
+ * `(bytes, offset, length)` by reference, deduping the socket chunk that consecutive rows
30
+ * share. (Our pg-protocol patch guarantees message bytes are never rewritten — chunks parse in
31
+ * place and straddling messages get a buffer of their own; see `patchPgProtocol.ts`.) A
32
+ * `row × column` cell is decoded on first field access by scanning the row's length-prefixed
33
+ * cells to the column's ordinal ("row-lazy" decode, see JS-ROW-STORE-DESIGN.md §3/C2). This is
34
+ * deferred decoding of row-major data, not a columnar layout.
35
+ *
36
+ * Because chunks are whole socket reads, retaining any row pins its ~64KiB chunk (plus whatever
37
+ * protocol frames share it); `finalize`'s compaction copies retained rows out into an
38
+ * exact-size owned buffer when enough of the payload was dropped.
39
+ *
40
+ * Text-format cells go through the same active text parsers node-postgres would resolve for
41
+ * the query (i.e. honoring pool/client `TypeOverrides`), so they parse identically to classic
42
+ * rows. Binary-format cells decode via `wireBinaryParser`: wire bytes -> value directly for
43
+ * default-parsed scalar types (no intermediate string), else rendered to pg's canonical text
44
+ * and fed through the active text parser for parity. (Classic node-postgres cannot do binary
45
+ * at all — it round-trips cells through a UTF-8 string, corrupting bytes >= 0x80.)
46
+ *
47
+ * Because decoding is deferred, a custom parser that throws will do so on first field access
48
+ * (or `toRow`/`toRows`), not while awaiting the query; `id` and inheritance-discriminator cells
49
+ * still decode during hydration.
50
+ *
51
+ * After hydration, `finalize` trims unused capacity and, when some rows were not retained (i.e.
52
+ * their entities were already in the identity map), compacts the payload down to only the
53
+ * retained rows, so retained memory tracks live entities rather than query history.
54
+ *
55
+ * Small results deliberately stay lazy — there is NO row-count threshold below which we
56
+ * materialize to a `PojoRowData` instead. Measured (benchmark-rowdata-small.ts, 40-col rows):
57
+ * for the typical sparse access pattern (~6 of 40 columns read), keeping the lazy result wins at
58
+ * every size including a single row (n=1: 4.3µs vs 7.6µs; n=1000: 0.76ms vs 3.0ms), because
59
+ * materialization eagerly decodes every column while lazy faults only what is read. Even full
60
+ * column coverage no longer flips the winner: with binary decode and `#readCell`'s adaptive
61
+ * scan cursor, reading all ~36 columns of every row measures ~parity with classic end-to-end
62
+ * (benchmark-lazy-parsing.ts), and small finds (n <= 10) are statistically identical.
63
+ */
64
+ var WireRowData = class {
65
+ #chunks = [];
66
+ /** Where each row's bytes live: `(chunk index, start, length)` slices, `ROW_STRIDE` entries per row. */
67
+ #rowSlices = /* @__PURE__ */ new Uint32Array(48);
68
+ #rowCount = 0;
69
+ #payloadBytes = 0;
70
+ #retained = void 0;
71
+ #columns = /* @__PURE__ */ new Map();
72
+ #fields = [];
73
+ /** The adaptive scan cursor: per row, the furthest scanned ordinal + its offset (see #readCell). */
74
+ #scanOrdinal = void 0;
75
+ #scanOffset = void 0;
76
+ get rowCount() {
77
+ return this.#rowCount;
78
+ }
79
+ /** The DataRow payload bytes currently indexed; drops when compaction discards rows. */
80
+ get payloadBytes() {
81
+ return this.#payloadBytes;
82
+ }
83
+ /** The bytes currently held by payload chunks + the row-slice table, i.e. for benchmarks. */
84
+ get memoryBytes() {
85
+ let bytes = this.#rowSlices.byteLength;
86
+ for (const chunk of this.#chunks) bytes += chunk.length;
87
+ return bytes;
88
+ }
89
+ get(rowIndex, columnName) {
90
+ const column = this.#columns.get(columnName);
91
+ if (column === void 0) return void 0;
92
+ const base = this.#rowBase(rowIndex);
93
+ const slices = this.#rowSlices;
94
+ const start = slices[base + 1];
95
+ return this.#readCell(this.#chunks[slices[base]], start, start + slices[base + 2], column, rowIndex);
96
+ }
97
+ /** Materializes one row as a POJO, i.e. for debugging and differential tests; values are not cached. */
98
+ toRow(rowIndex) {
99
+ const base = this.#rowBase(rowIndex);
100
+ const slices = this.#rowSlices;
101
+ const chunk = this.#chunks[slices[base]];
102
+ const start = slices[base + 1];
103
+ const end = start + slices[base + 2];
104
+ const row = {};
105
+ let pos = start + 2;
106
+ for (const field of this.#fields) {
107
+ const len = this.#cellLength(chunk, pos, end, rowIndex);
108
+ pos += 4;
109
+ if (len === -1) row[field.name] = null;
110
+ else {
111
+ row[field.name] = field.decode(chunk, pos, len);
112
+ pos += len;
113
+ }
114
+ }
115
+ return row;
116
+ }
117
+ /** Materializes classic POJO rows, i.e. for `afterFind` observation or debugging; not cached. */
118
+ toRows() {
119
+ const rows = new Array(this.#rowCount);
120
+ for (let i = 0; i < this.#rowCount; i++) rows[i] = this.toRow(i);
121
+ return rows;
122
+ }
123
+ /**
124
+ * Resolves each column's decoder from the query's RowDescription.
125
+ *
126
+ * Binary-format fields decode through Joist's own binary registry only (see
127
+ * `setBinaryTypeParser`) — `pg.types`/`TypeOverrides` are never consulted, and a column whose
128
+ * oid has no registered binary parser fails the query here, before any rows arrive, rather
129
+ * than guessing at a lossy decoding. Text-format fields (the `binary: false` escape hatch)
130
+ * decode by utf8-slicing the cell into the active text parser, resolved via `getTypeParser`
131
+ * (i.e. the pool/client `TypeOverrides` chain) or the global registry.
132
+ */
133
+ setRowDescription(fields, getTypeParser) {
134
+ for (let i = 0; i < fields.length; i++) {
135
+ const { name, dataTypeID, format } = fields[i];
136
+ let decode;
137
+ if (format === "binary") {
138
+ decode = require_drivers_binaryParsers.getBinaryTypeParser(dataTypeID);
139
+ if (decode === void 0) throw new Error(`joist-orm: no binary type parser registered for oid ${dataTypeID} (column "${name}"); register one with setBinaryTypeParser (i.e. binaryTextParser for text-like types)`);
140
+ } else decode = textCellDecoder(getTypeParser?.(dataTypeID) ?? pg.default.types.getTypeParser(dataTypeID, "text"));
141
+ const column = {
142
+ name,
143
+ ordinal: i,
144
+ decode
145
+ };
146
+ this.#columns.set(name, column);
147
+ this.#fields.push(column);
148
+ }
149
+ }
150
+ /**
151
+ * Records one DataRow payload *by reference* (zero-copy); called synchronously from the wire
152
+ * parser, whose patched buffer management guarantees the bytes are never rewritten.
153
+ *
154
+ * Consecutive rows usually share one socket chunk, so `bytes` is deduped against the last
155
+ * chunk ref; retaining any row of a chunk pins the whole chunk, which `finalize`'s compaction
156
+ * resolves by copying retained rows out when enough of the payload was dropped.
157
+ */
158
+ addRow(bytes, offset, payloadLength) {
159
+ if (payloadLength < 2 || offset + payloadLength > bytes.length) throw new Error(`Malformed DataRow payload (length ${payloadLength})`);
160
+ let chunkIndex = this.#chunks.length - 1;
161
+ if (chunkIndex === -1 || this.#chunks[chunkIndex] !== bytes) {
162
+ this.#chunks.push(bytes);
163
+ chunkIndex++;
164
+ }
165
+ let slices = this.#rowSlices;
166
+ const base = this.#rowCount * ROW_STRIDE;
167
+ if (base === slices.length) {
168
+ const grown = new Uint32Array(slices.length * 2);
169
+ grown.set(slices);
170
+ slices = this.#rowSlices = grown;
171
+ }
172
+ slices[base] = chunkIndex;
173
+ slices[base + 1] = offset;
174
+ slices[base + 2] = payloadLength;
175
+ this.#rowCount++;
176
+ this.#payloadBytes += payloadLength;
177
+ }
178
+ /** Marks `rowIndex` as retained by a hydrated entity; unmarked rows can be compacted away. */
179
+ retain(rowIndex) {
180
+ (this.#retained ??= []).push(rowIndex);
181
+ }
182
+ /**
183
+ * Trims unused capacity, and compacts down to only `retain`-ed rows when enough rows were not
184
+ * retained to be worth the copy.
185
+ *
186
+ * Compaction exists to release pinned socket buffers to the GC: rows are zero-copy views into
187
+ * whole ~64KiB chunks, so keeping any row alive pins its entire chunk — and unretained rows
188
+ * are typically duplicates whose entities were *already in memory* (identity-map hits that
189
+ * keep their original `rowData`), making the newly-arrived bytes dead weight. Copying the
190
+ * retained rows into one exact-size owned buffer lets every chunk reference drop.
191
+ *
192
+ * The copy re-copies every retained byte, so it only pays off when it buys back a meaningful
193
+ * fraction of the payload: we compact when the dropped rows hold more than 20% of the payload
194
+ * bytes, and otherwise just trim, accepting the (bounded) leftover bytes. Called once after
195
+ * hydration + sidecar reads (`_tags`, preload aggregates) are complete; retained entities keep
196
+ * their original `rowIndex`, and un-compacted unretained rows simply remain readable-but-unused.
197
+ */
198
+ finalize() {
199
+ const retained = this.#retained ?? [];
200
+ this.#retained = void 0;
201
+ if (retained.length < this.#rowCount) {
202
+ let retainedBytes = 0;
203
+ for (const i of retained) retainedBytes += this.#rowSlices[i * ROW_STRIDE + 2];
204
+ if (this.#payloadBytes - retainedBytes > this.#payloadBytes * COMPACT_THRESHOLD) {
205
+ this.#compact(retained, retainedBytes);
206
+ return;
207
+ }
208
+ }
209
+ if (this.#rowCount * ROW_STRIDE < this.#rowSlices.length) this.#rowSlices = this.#rowSlices.slice(0, this.#rowCount * ROW_STRIDE);
210
+ }
211
+ /** Copies retained rows into one owned buffer, releasing the pinned socket chunks to the GC. */
212
+ #compact(retained, bytes) {
213
+ const chunks = bytes > 0 ? [Buffer.allocUnsafe(bytes)] : [];
214
+ const slices = new Uint32Array(this.#rowCount * ROW_STRIDE);
215
+ for (let i = 0; i < this.#rowCount; i++) slices[i * ROW_STRIDE + 2] = DROPPED;
216
+ let used = 0;
217
+ for (const i of retained) {
218
+ const base = i * ROW_STRIDE;
219
+ const source = this.#chunks[this.#rowSlices[base]];
220
+ const start = this.#rowSlices[base + 1];
221
+ const len = this.#rowSlices[base + 2];
222
+ source.copy(chunks[0], used, start, start + len);
223
+ slices[base] = 0;
224
+ slices[base + 1] = used;
225
+ slices[base + 2] = len;
226
+ used += len;
227
+ }
228
+ this.#chunks = chunks;
229
+ this.#rowSlices = slices;
230
+ this.#payloadBytes = used;
231
+ }
232
+ /** Validates `rowIndex` and returns its base index into the `#rowSlices` table. */
233
+ #rowBase(rowIndex) {
234
+ if (!(rowIndex >= 0 && rowIndex < this.#rowCount)) throw new Error(`Invalid rowIndex ${rowIndex} (rowCount ${this.#rowCount})`);
235
+ const base = rowIndex * ROW_STRIDE;
236
+ if (this.#rowSlices[base + 2] === DROPPED) throw new Error(`Row ${rowIndex} was compacted away (its entity was already loaded)`);
237
+ return base;
238
+ }
239
+ /**
240
+ * Scans a row's cells to `column`'s ordinal and decodes it.
241
+ *
242
+ * An adaptive per-row scan cursor caches the furthest cell boundary already scanned — the
243
+ * ordinal whose row-relative offset is known (`#scanOrdinal`/`#scanOffset`) — so ascending
244
+ * reads resume instead of re-scanning from the row start: a dense in-order read of all C
245
+ * columns costs one linear pass rather than O(C^2) length-prefix skips. Out-of-order
246
+ * (descending) faults simply scan from the start, i.e. never worse than without the cursor.
247
+ * The arrays are a fixed 6 bytes/row, allocated lazily on the first fault deep enough for
248
+ * resuming to matter, and — being row-relative — stay valid across compaction.
249
+ */
250
+ #readCell(chunk, start, end, column, rowIndex) {
251
+ const fieldCount = chunk.readInt16BE(start);
252
+ const { ordinal } = column;
253
+ if (ordinal >= fieldCount) throw new Error(`Row ${rowIndex} has ${fieldCount} cells but column ${column.name} is #${column.ordinal}`);
254
+ let pos = start + 2;
255
+ let c = 0;
256
+ let scanOrdinal = this.#scanOrdinal;
257
+ if (scanOrdinal === void 0 && ordinal >= SCAN_CURSOR_MIN_ORDINAL) {
258
+ scanOrdinal = this.#scanOrdinal = new Uint16Array(this.#rowCount);
259
+ this.#scanOffset = new Uint32Array(this.#rowCount);
260
+ }
261
+ if (scanOrdinal !== void 0 && rowIndex < scanOrdinal.length) {
262
+ const known = scanOrdinal[rowIndex];
263
+ if (known !== 0 && known <= ordinal) {
264
+ c = known;
265
+ pos = start + this.#scanOffset[rowIndex];
266
+ }
267
+ }
268
+ for (; c < ordinal; c++) {
269
+ const len = this.#cellLength(chunk, pos, end, rowIndex);
270
+ pos += len > 0 ? len + 4 : 4;
271
+ }
272
+ const len = this.#cellLength(chunk, pos, end, rowIndex);
273
+ if (scanOrdinal !== void 0 && rowIndex < scanOrdinal.length && ordinal + 1 > scanOrdinal[rowIndex]) {
274
+ scanOrdinal[rowIndex] = ordinal + 1;
275
+ this.#scanOffset[rowIndex] = pos + 4 + (len > 0 ? len : 0) - start;
276
+ }
277
+ if (len === -1) return null;
278
+ return column.decode(chunk, pos + 4, len);
279
+ }
280
+ /** Reads + validates one cell's length prefix. */
281
+ #cellLength(chunk, pos, end, rowIndex) {
282
+ if (pos + 4 > end) throw new Error(`Truncated DataRow payload in row ${rowIndex}`);
283
+ const len = chunk.readInt32BE(pos);
284
+ if (len < -1 || len > 0 && pos + 4 + len > end) throw new Error(`Malformed cell length ${len} in row ${rowIndex}`);
285
+ return len;
286
+ }
287
+ };
288
+ /**
289
+ * Executes `sql` on an already-checked-out client, returning a {@link RowData} instead of
290
+ * materialized POJO rows.
291
+ *
292
+ * Uses a `pg` Query subclass that records each DataRow's raw payload bytes into the result
293
+ * (via the lazy DataRow message from `patchPgProtocol`) and never materializes per-cell
294
+ * strings or per-row objects. If the client's connection turns out to use an unpatched
295
+ * pg-protocol copy (i.e. the app's pool was built from a different `pg` install than the one
296
+ * joist-orm patched), the query fails with a descriptive error — a misconfiguration any CI
297
+ * build/smoketest will surface immediately, so we fail loudly rather than silently degrade.
298
+ * The rows already streamed are discarded; the connection itself stays usable.
299
+ *
300
+ * By default the query requests *binary* result format (via the extended protocol), so scalar
301
+ * cells decode wire-bytes -> value with no intermediate strings; see `wireBinaryParser` for the
302
+ * parity strategy. Pass `binary: false` for classic text-format results, or set
303
+ * `JOIST_LAZY_BINARY=0` to flip the default while the binary path is a prototype (i.e. for
304
+ * A/B benchmarking or as an escape hatch).
305
+ */
306
+ const BINARY_BY_DEFAULT = process.env.JOIST_LAZY_BINARY !== "0";
307
+ function executeRowDataQuery(client, sql, bindings, opts) {
308
+ const binary = opts?.binary ?? BINARY_BY_DEFAULT;
309
+ return new Promise((resolve, reject) => {
310
+ const query = new RowDataQuery(binary ? {
311
+ text: sql,
312
+ values: bindings,
313
+ binary: true,
314
+ queryMode: "extended"
315
+ } : {
316
+ text: sql,
317
+ values: bindings
318
+ }, (err) => {
319
+ if (err) reject(err);
320
+ else resolve(query.rowData);
321
+ });
322
+ client.query(query);
323
+ });
324
+ }
325
+ /** Returns whether `client` supports the lazy row-data query path, before submitting anything. */
326
+ function isRowDataCapableClient(client) {
327
+ return typeof client === "object" && client !== null && typeof client.query === "function" && client.connection !== void 0 && client.native === void 0;
328
+ }
329
+ /** A pg Query that diverts DataRows into a {@link WireRowData} instead of a `Result`. */
330
+ var RowDataQuery = class extends PgQuery {
331
+ #wire = new WireRowData();
332
+ constructor(config, callback) {
333
+ super(config, void 0, callback);
334
+ }
335
+ /**
336
+ * The query's result rows, i.e. once our callback has fired.
337
+ *
338
+ * If a small-result materialization threshold ever seems attractive, this is where it would
339
+ * go — but see the "Small results deliberately stay lazy" note on {@link WireRowData}: lazy
340
+ * won the measured comparison at every row count for sparse access, so no threshold exists.
341
+ */
342
+ get rowData() {
343
+ return this.#wire;
344
+ }
345
+ handleRowDescription(msg) {
346
+ if (this._canceledDueToError) return;
347
+ try {
348
+ super.handleRowDescription(msg);
349
+ const types = this._result?._types;
350
+ this.#wire.setRowDescription(msg.fields, types && ((oid) => types.getTypeParser(oid, "text")));
351
+ } catch (err) {
352
+ this._canceledDueToError = err;
353
+ }
354
+ }
355
+ handleDataRow(msg) {
356
+ if (this._canceledDueToError) return;
357
+ try {
358
+ if (msg.bytes === void 0) throw new Error("joist-orm: lazyRows is enabled, but this connection's pg-protocol emits classic DataRows (likely a duplicate pg install); fix the install or disable lazyRows.");
359
+ this.#wire.addRow(msg.bytes, msg.offset, msg.length - 4);
360
+ } catch (err) {
361
+ this._canceledDueToError = err;
362
+ }
363
+ }
364
+ };
365
+ /** Builds a text-format cell decoder: utf8-slice the cell bytes into the active text parser. */
366
+ function textCellDecoder(parse) {
367
+ return (chunk, start, length) => parse(chunk.toString("utf8", start, start + length));
368
+ }
369
+ //#endregion
370
+ exports.WireRowData = WireRowData;
371
+ exports.executeRowDataQuery = executeRowDataQuery;
372
+ exports.isRowDataCapableClient = isRowDataCapableClient;
373
+
374
+ //# sourceMappingURL=WireRowData.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WireRowData.cjs","names":["createRequire","#rowCount","#payloadBytes","#rowSlices","#chunks","#columns","#rowBase","#readCell","#fields","#cellLength","getBinaryTypeParser","#retained","#compact","#scanOrdinal","#scanOffset","#wire"],"sources":["../../src/drivers/WireRowData.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { type RowData } from \"joist-core\";\nimport pg from \"pg\";\n\nimport { getBinaryTypeParser } from \"./binaryParsers.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\n// pg's internal-but-exported Query class; subclassing it reuses its extended-protocol\n// submit/bind logic while letting us intercept row handling (the same seam pg-cursor uses).\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst PgQuery: any = runtimeRequire(\"pg/lib/query\");\n\n/** One column's RowDescription-derived metadata, resolved once per query. */\ntype WireColumn = {\n name: string;\n ordinal: number;\n /** Decodes this column's cell bytes to its value; see `setRowDescription`. */\n decode: (chunk: Buffer, start: number, length: number) => any;\n};\n\n// Each row is three consecutive entries in the `#rowSlices` table: chunk index, start, length\nconst ROW_STRIDE = 3;\n\n/** The row-length sentinel for rows dropped by `finalize` compaction. */\nconst DROPPED = 0xffffffff;\n\n/** Only compact when dropped rows hold more than this fraction of the payload bytes. */\nconst COMPACT_THRESHOLD = 0.2;\n\n/**\n * Only allocate the adaptive scan cursor once a fault targets at least this ordinal: shallower\n * scans cost less than the cursor's bookkeeping, i.e. hydrate-only results (id is ordinal ~0)\n * and narrow reads never pay the 6 bytes/row.\n */\nconst SCAN_CURSOR_MIN_ORDINAL = 8;\n\n/**\n * A lazy wire-row {@link RowData} over raw Postgres `DataRow` payload bytes.\n *\n * Each query produces its own `WireRowData` — one query, one result; results are never combined\n * or appended across queries, and the payload is read-only after the query completes (entity\n * mutations go into `InstanceData.data`, never back into the row bytes).\n *\n * Rows are kept in their row-major wire format (`int16 fieldCount` + length-prefixed cells) as\n * zero-copy views over the parser's own immutable buffers: `addRow` records each DataRow's\n * `(bytes, offset, length)` by reference, deduping the socket chunk that consecutive rows\n * share. (Our pg-protocol patch guarantees message bytes are never rewritten — chunks parse in\n * place and straddling messages get a buffer of their own; see `patchPgProtocol.ts`.) A\n * `row × column` cell is decoded on first field access by scanning the row's length-prefixed\n * cells to the column's ordinal (\"row-lazy\" decode, see JS-ROW-STORE-DESIGN.md §3/C2). This is\n * deferred decoding of row-major data, not a columnar layout.\n *\n * Because chunks are whole socket reads, retaining any row pins its ~64KiB chunk (plus whatever\n * protocol frames share it); `finalize`'s compaction copies retained rows out into an\n * exact-size owned buffer when enough of the payload was dropped.\n *\n * Text-format cells go through the same active text parsers node-postgres would resolve for\n * the query (i.e. honoring pool/client `TypeOverrides`), so they parse identically to classic\n * rows. Binary-format cells decode via `wireBinaryParser`: wire bytes -> value directly for\n * default-parsed scalar types (no intermediate string), else rendered to pg's canonical text\n * and fed through the active text parser for parity. (Classic node-postgres cannot do binary\n * at all — it round-trips cells through a UTF-8 string, corrupting bytes >= 0x80.)\n *\n * Because decoding is deferred, a custom parser that throws will do so on first field access\n * (or `toRow`/`toRows`), not while awaiting the query; `id` and inheritance-discriminator cells\n * still decode during hydration.\n *\n * After hydration, `finalize` trims unused capacity and, when some rows were not retained (i.e.\n * their entities were already in the identity map), compacts the payload down to only the\n * retained rows, so retained memory tracks live entities rather than query history.\n *\n * Small results deliberately stay lazy — there is NO row-count threshold below which we\n * materialize to a `PojoRowData` instead. Measured (benchmark-rowdata-small.ts, 40-col rows):\n * for the typical sparse access pattern (~6 of 40 columns read), keeping the lazy result wins at\n * every size including a single row (n=1: 4.3µs vs 7.6µs; n=1000: 0.76ms vs 3.0ms), because\n * materialization eagerly decodes every column while lazy faults only what is read. Even full\n * column coverage no longer flips the winner: with binary decode and `#readCell`'s adaptive\n * scan cursor, reading all ~36 columns of every row measures ~parity with classic end-to-end\n * (benchmark-lazy-parsing.ts), and small finds (n <= 10) are statistically identical.\n */\nexport class WireRowData implements RowData {\n #chunks: Buffer[] = [];\n /** Where each row's bytes live: `(chunk index, start, length)` slices, `ROW_STRIDE` entries per row. */\n #rowSlices: Uint32Array<ArrayBufferLike> = new Uint32Array(16 * ROW_STRIDE);\n #rowCount = 0;\n #payloadBytes = 0;\n #retained: number[] | undefined = undefined;\n #columns: Map<string, WireColumn> = new Map();\n #fields: WireColumn[] = [];\n /** The adaptive scan cursor: per row, the furthest scanned ordinal + its offset (see #readCell). */\n #scanOrdinal: Uint16Array | undefined = undefined;\n #scanOffset: Uint32Array | undefined = undefined;\n\n get rowCount(): number {\n return this.#rowCount;\n }\n\n /** The DataRow payload bytes currently indexed; drops when compaction discards rows. */\n get payloadBytes(): number {\n return this.#payloadBytes;\n }\n\n /** The bytes currently held by payload chunks + the row-slice table, i.e. for benchmarks. */\n get memoryBytes(): number {\n let bytes = this.#rowSlices.byteLength;\n for (const chunk of this.#chunks) bytes += chunk.length;\n return bytes;\n }\n\n get(rowIndex: number, columnName: string): any {\n const column = this.#columns.get(columnName);\n // Tolerate probes for columns the query didn't select, i.e. `__class` on non-CTI queries\n if (column === undefined) return undefined;\n const base = this.#rowBase(rowIndex);\n const slices = this.#rowSlices;\n const start = slices[base + 1];\n return this.#readCell(this.#chunks[slices[base]], start, start + slices[base + 2], column, rowIndex);\n }\n\n /** Materializes one row as a POJO, i.e. for debugging and differential tests; values are not cached. */\n toRow(rowIndex: number): any {\n const base = this.#rowBase(rowIndex);\n const slices = this.#rowSlices;\n const chunk = this.#chunks[slices[base]];\n const start = slices[base + 1];\n const end = start + slices[base + 2];\n const row: Record<string, any> = {};\n let pos = start + 2;\n for (const field of this.#fields) {\n const len = this.#cellLength(chunk, pos, end, rowIndex);\n pos += 4;\n if (len === -1) {\n row[field.name] = null;\n } else {\n row[field.name] = field.decode(chunk, pos, len);\n pos += len;\n }\n }\n return row;\n }\n\n /** Materializes classic POJO rows, i.e. for `afterFind` observation or debugging; not cached. */\n toRows(): any[] {\n const rows = new Array(this.#rowCount);\n for (let i = 0; i < this.#rowCount; i++) rows[i] = this.toRow(i);\n return rows;\n }\n\n /**\n * Resolves each column's decoder from the query's RowDescription.\n *\n * Binary-format fields decode through Joist's own binary registry only (see\n * `setBinaryTypeParser`) — `pg.types`/`TypeOverrides` are never consulted, and a column whose\n * oid has no registered binary parser fails the query here, before any rows arrive, rather\n * than guessing at a lossy decoding. Text-format fields (the `binary: false` escape hatch)\n * decode by utf8-slicing the cell into the active text parser, resolved via `getTypeParser`\n * (i.e. the pool/client `TypeOverrides` chain) or the global registry.\n */\n setRowDescription(\n fields: Array<{ name: string; dataTypeID: number; format?: string }>,\n getTypeParser?: (dataTypeID: number) => (value: any) => any,\n ): void {\n for (let i = 0; i < fields.length; i++) {\n const { name, dataTypeID, format } = fields[i];\n let decode;\n if (format === \"binary\") {\n decode = getBinaryTypeParser(dataTypeID);\n if (decode === undefined) {\n throw new Error(\n `joist-orm: no binary type parser registered for oid ${dataTypeID} (column \"${name}\");` +\n ` register one with setBinaryTypeParser (i.e. binaryTextParser for text-like types)`,\n );\n }\n } else {\n const parse = getTypeParser?.(dataTypeID) ?? pg.types.getTypeParser(dataTypeID, \"text\");\n decode = textCellDecoder(parse);\n }\n const column = { name, ordinal: i, decode };\n this.#columns.set(name, column);\n this.#fields.push(column);\n }\n }\n\n /**\n * Records one DataRow payload *by reference* (zero-copy); called synchronously from the wire\n * parser, whose patched buffer management guarantees the bytes are never rewritten.\n *\n * Consecutive rows usually share one socket chunk, so `bytes` is deduped against the last\n * chunk ref; retaining any row of a chunk pins the whole chunk, which `finalize`'s compaction\n * resolves by copying retained rows out when enough of the payload was dropped.\n */\n addRow(bytes: Buffer, offset: number, payloadLength: number): void {\n if (payloadLength < 2 || offset + payloadLength > bytes.length) {\n throw new Error(`Malformed DataRow payload (length ${payloadLength})`);\n }\n let chunkIndex = this.#chunks.length - 1;\n if (chunkIndex === -1 || this.#chunks[chunkIndex] !== bytes) {\n this.#chunks.push(bytes);\n chunkIndex++;\n }\n let slices = this.#rowSlices;\n const base = this.#rowCount * ROW_STRIDE;\n if (base === slices.length) {\n const grown = new Uint32Array(slices.length * 2);\n grown.set(slices);\n slices = this.#rowSlices = grown;\n }\n slices[base] = chunkIndex;\n slices[base + 1] = offset;\n slices[base + 2] = payloadLength;\n this.#rowCount++;\n this.#payloadBytes += payloadLength;\n }\n\n /** Marks `rowIndex` as retained by a hydrated entity; unmarked rows can be compacted away. */\n retain(rowIndex: number): void {\n (this.#retained ??= []).push(rowIndex);\n }\n\n /**\n * Trims unused capacity, and compacts down to only `retain`-ed rows when enough rows were not\n * retained to be worth the copy.\n *\n * Compaction exists to release pinned socket buffers to the GC: rows are zero-copy views into\n * whole ~64KiB chunks, so keeping any row alive pins its entire chunk — and unretained rows\n * are typically duplicates whose entities were *already in memory* (identity-map hits that\n * keep their original `rowData`), making the newly-arrived bytes dead weight. Copying the\n * retained rows into one exact-size owned buffer lets every chunk reference drop.\n *\n * The copy re-copies every retained byte, so it only pays off when it buys back a meaningful\n * fraction of the payload: we compact when the dropped rows hold more than 20% of the payload\n * bytes, and otherwise just trim, accepting the (bounded) leftover bytes. Called once after\n * hydration + sidecar reads (`_tags`, preload aggregates) are complete; retained entities keep\n * their original `rowIndex`, and un-compacted unretained rows simply remain readable-but-unused.\n */\n finalize(): void {\n const retained = this.#retained ?? [];\n this.#retained = undefined;\n if (retained.length < this.#rowCount) {\n let retainedBytes = 0;\n for (const i of retained) retainedBytes += this.#rowSlices[i * ROW_STRIDE + 2];\n const droppedBytes = this.#payloadBytes - retainedBytes;\n if (droppedBytes > this.#payloadBytes * COMPACT_THRESHOLD) {\n this.#compact(retained, retainedBytes);\n return;\n }\n }\n // Just shrink the row-slice table to its used size\n if (this.#rowCount * ROW_STRIDE < this.#rowSlices.length) {\n this.#rowSlices = this.#rowSlices.slice(0, this.#rowCount * ROW_STRIDE);\n }\n }\n\n /** Copies retained rows into one owned buffer, releasing the pinned socket chunks to the GC. */\n #compact(retained: readonly number[], bytes: number): void {\n const chunks: Buffer[] = bytes > 0 ? [Buffer.allocUnsafe(bytes)] : [];\n const slices = new Uint32Array(this.#rowCount * ROW_STRIDE);\n for (let i = 0; i < this.#rowCount; i++) slices[i * ROW_STRIDE + 2] = DROPPED;\n let used = 0;\n for (const i of retained) {\n const base = i * ROW_STRIDE;\n const source = this.#chunks[this.#rowSlices[base]];\n const start = this.#rowSlices[base + 1];\n const len = this.#rowSlices[base + 2];\n source.copy(chunks[0], used, start, start + len);\n slices[base] = 0;\n slices[base + 1] = used;\n slices[base + 2] = len;\n used += len;\n }\n this.#chunks = chunks;\n this.#rowSlices = slices;\n this.#payloadBytes = used;\n // The scan cursor survives: its cached offsets are relative to each row's (copied) payload\n }\n\n /** Validates `rowIndex` and returns its base index into the `#rowSlices` table. */\n #rowBase(rowIndex: number): number {\n if (!(rowIndex >= 0 && rowIndex < this.#rowCount)) {\n throw new Error(`Invalid rowIndex ${rowIndex} (rowCount ${this.#rowCount})`);\n }\n const base = rowIndex * ROW_STRIDE;\n if (this.#rowSlices[base + 2] === DROPPED) {\n throw new Error(`Row ${rowIndex} was compacted away (its entity was already loaded)`);\n }\n return base;\n }\n\n /**\n * Scans a row's cells to `column`'s ordinal and decodes it.\n *\n * An adaptive per-row scan cursor caches the furthest cell boundary already scanned — the\n * ordinal whose row-relative offset is known (`#scanOrdinal`/`#scanOffset`) — so ascending\n * reads resume instead of re-scanning from the row start: a dense in-order read of all C\n * columns costs one linear pass rather than O(C^2) length-prefix skips. Out-of-order\n * (descending) faults simply scan from the start, i.e. never worse than without the cursor.\n * The arrays are a fixed 6 bytes/row, allocated lazily on the first fault deep enough for\n * resuming to matter, and — being row-relative — stay valid across compaction.\n */\n #readCell(chunk: Buffer, start: number, end: number, column: WireColumn, rowIndex: number): any {\n const fieldCount = chunk.readInt16BE(start);\n const { ordinal } = column;\n if (ordinal >= fieldCount) {\n throw new Error(`Row ${rowIndex} has ${fieldCount} cells but column ${column.name} is #${column.ordinal}`);\n }\n let pos = start + 2;\n let c = 0;\n let scanOrdinal = this.#scanOrdinal;\n if (scanOrdinal === undefined && ordinal >= SCAN_CURSOR_MIN_ORDINAL) {\n scanOrdinal = this.#scanOrdinal = new Uint16Array(this.#rowCount);\n this.#scanOffset = new Uint32Array(this.#rowCount);\n }\n if (scanOrdinal !== undefined && rowIndex < scanOrdinal.length) {\n // 0 = unset: caching cell #0 would be pointless (it is always at offset 2), so any real\n // entry is the ordinal, >= 1, whose row-relative offset is in #scanOffset\n const known = scanOrdinal[rowIndex];\n if (known !== 0 && known <= ordinal) {\n c = known;\n pos = start + this.#scanOffset![rowIndex];\n }\n }\n for (; c < ordinal; c++) {\n const len = this.#cellLength(chunk, pos, end, rowIndex);\n pos += len > 0 ? len + 4 : 4;\n }\n const len = this.#cellLength(chunk, pos, end, rowIndex);\n if (scanOrdinal !== undefined && rowIndex < scanOrdinal.length && ordinal + 1 > scanOrdinal[rowIndex]) {\n // advance-only: after reading cell #ordinal we know where cell #ordinal+1 starts\n scanOrdinal[rowIndex] = ordinal + 1;\n this.#scanOffset![rowIndex] = pos + 4 + (len > 0 ? len : 0) - start;\n }\n if (len === -1) return null;\n return column.decode(chunk, pos + 4, len);\n }\n\n /** Reads + validates one cell's length prefix. */\n #cellLength(chunk: Buffer, pos: number, end: number, rowIndex: number): number {\n if (pos + 4 > end) throw new Error(`Truncated DataRow payload in row ${rowIndex}`);\n const len = chunk.readInt32BE(pos);\n if (len < -1 || (len > 0 && pos + 4 + len > end)) {\n throw new Error(`Malformed cell length ${len} in row ${rowIndex}`);\n }\n return len;\n }\n}\n\n/**\n * Executes `sql` on an already-checked-out client, returning a {@link RowData} instead of\n * materialized POJO rows.\n *\n * Uses a `pg` Query subclass that records each DataRow's raw payload bytes into the result\n * (via the lazy DataRow message from `patchPgProtocol`) and never materializes per-cell\n * strings or per-row objects. If the client's connection turns out to use an unpatched\n * pg-protocol copy (i.e. the app's pool was built from a different `pg` install than the one\n * joist-orm patched), the query fails with a descriptive error — a misconfiguration any CI\n * build/smoketest will surface immediately, so we fail loudly rather than silently degrade.\n * The rows already streamed are discarded; the connection itself stays usable.\n *\n * By default the query requests *binary* result format (via the extended protocol), so scalar\n * cells decode wire-bytes -> value with no intermediate strings; see `wireBinaryParser` for the\n * parity strategy. Pass `binary: false` for classic text-format results, or set\n * `JOIST_LAZY_BINARY=0` to flip the default while the binary path is a prototype (i.e. for\n * A/B benchmarking or as an escape hatch).\n */\n// The prototype escape hatch for binary results, i.e. for A/B benchmarking; read once at load\nconst BINARY_BY_DEFAULT = process.env.JOIST_LAZY_BINARY !== \"0\";\n\nexport function executeRowDataQuery(\n client: pg.PoolClient,\n sql: string,\n bindings: readonly any[],\n opts?: { binary?: boolean },\n): Promise<RowData> {\n const binary = opts?.binary ?? BINARY_BY_DEFAULT;\n return new Promise((resolve, reject) => {\n const query = new RowDataQuery(\n // Binary results require the extended protocol; `queryMode` forces it for bindings-less queries\n binary\n ? { text: sql, values: bindings as any[], binary: true, queryMode: \"extended\" }\n : { text: sql, values: bindings as any[] },\n (err: unknown) => {\n if (err) reject(err);\n else resolve(query.rowData);\n },\n );\n client.query(query as any);\n });\n}\n\n/** Returns whether `client` supports the lazy row-data query path, before submitting anything. */\nexport function isRowDataCapableClient(client: unknown): client is pg.PoolClient {\n // Require the pure-JS pg client (pg-native has no `connection` and different query internals)\n return (\n typeof client === \"object\" &&\n client !== null &&\n typeof (client as any).query === \"function\" &&\n (client as any).connection !== undefined &&\n (client as any).native === undefined\n );\n}\n\n/** A pg Query that diverts DataRows into a {@link WireRowData} instead of a `Result`. */\nclass RowDataQuery extends PgQuery {\n #wire = new WireRowData();\n\n constructor(\n config: { text: string; values: any[]; binary?: boolean; queryMode?: string },\n callback: (err: unknown) => void,\n ) {\n super(config, undefined, callback);\n }\n\n /**\n * The query's result rows, i.e. once our callback has fired.\n *\n * If a small-result materialization threshold ever seems attractive, this is where it would\n * go — but see the \"Small results deliberately stay lazy\" note on {@link WireRowData}: lazy\n * won the measured comparison at every row count for sparse access, so no threshold exists.\n */\n get rowData(): RowData {\n return this.#wire;\n }\n\n handleRowDescription(msg: any): void {\n if (this._canceledDueToError) return;\n try {\n super.handleRowDescription(msg);\n // Resolve active *text* parsers through the client's TypeOverrides chain (client.js\n // injects `_types` at submit time); we can't reuse `Result._parsers` because in binary\n // mode those resolve to pg's (broken) binary registry, while our binary decode path is\n // built on text-parser parity — see `wireBinaryParser`\n const types = this._result?._types;\n this.#wire.setRowDescription(msg.fields, types && ((oid: number) => types.getTypeParser(oid, \"text\")));\n } catch (err) {\n // Mirror pg's Query error containment: record + reject at ReadyForQuery, keeping the\n // connection's protocol state intact\n this._canceledDueToError = err;\n }\n }\n\n handleDataRow(msg: any): void {\n if (this._canceledDueToError) return;\n try {\n if (msg.bytes === undefined) {\n // This connection's pg-protocol copy is unpatched (i.e. the pool came from a different\n // `pg` install than the one joist-orm patched), so lazyRows cannot work — fail loudly\n // rather than silently degrade; any CI build/smoketest will surface this immediately\n throw new Error(\n \"joist-orm: lazyRows is enabled, but this connection's pg-protocol emits classic\" +\n \" DataRows (likely a duplicate pg install); fix the install or disable lazyRows.\",\n );\n }\n // `msg.length` includes the int32 length field itself, so the payload is `length - 4`;\n // our patched message carries the real length from `handlePacket`'s argument\n this.#wire.addRow(msg.bytes, msg.offset, msg.length - 4);\n } catch (err) {\n this._canceledDueToError = err;\n }\n }\n}\n\n/** Builds a text-format cell decoder: utf8-slice the cell bytes into the active text parser. */\nfunction textCellDecoder(parse: (value: any) => any): (chunk: Buffer, start: number, length: number) => any {\n return (chunk, start, length) => parse(chunk.toString(\"utf8\", start, start + length));\n}\n"],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ import { RowData } from "joist-core";
2
+ import pg from "pg";
3
+ //#region src/drivers/WireRowData.d.ts
4
+ /**
5
+ * A lazy wire-row {@link RowData} over raw Postgres `DataRow` payload bytes.
6
+ *
7
+ * Each query produces its own `WireRowData` — one query, one result; results are never combined
8
+ * or appended across queries, and the payload is read-only after the query completes (entity
9
+ * mutations go into `InstanceData.data`, never back into the row bytes).
10
+ *
11
+ * Rows are kept in their row-major wire format (`int16 fieldCount` + length-prefixed cells) as
12
+ * zero-copy views over the parser's own immutable buffers: `addRow` records each DataRow's
13
+ * `(bytes, offset, length)` by reference, deduping the socket chunk that consecutive rows
14
+ * share. (Our pg-protocol patch guarantees message bytes are never rewritten — chunks parse in
15
+ * place and straddling messages get a buffer of their own; see `patchPgProtocol.ts`.) A
16
+ * `row × column` cell is decoded on first field access by scanning the row's length-prefixed
17
+ * cells to the column's ordinal ("row-lazy" decode, see JS-ROW-STORE-DESIGN.md §3/C2). This is
18
+ * deferred decoding of row-major data, not a columnar layout.
19
+ *
20
+ * Because chunks are whole socket reads, retaining any row pins its ~64KiB chunk (plus whatever
21
+ * protocol frames share it); `finalize`'s compaction copies retained rows out into an
22
+ * exact-size owned buffer when enough of the payload was dropped.
23
+ *
24
+ * Text-format cells go through the same active text parsers node-postgres would resolve for
25
+ * the query (i.e. honoring pool/client `TypeOverrides`), so they parse identically to classic
26
+ * rows. Binary-format cells decode via `wireBinaryParser`: wire bytes -> value directly for
27
+ * default-parsed scalar types (no intermediate string), else rendered to pg's canonical text
28
+ * and fed through the active text parser for parity. (Classic node-postgres cannot do binary
29
+ * at all — it round-trips cells through a UTF-8 string, corrupting bytes >= 0x80.)
30
+ *
31
+ * Because decoding is deferred, a custom parser that throws will do so on first field access
32
+ * (or `toRow`/`toRows`), not while awaiting the query; `id` and inheritance-discriminator cells
33
+ * still decode during hydration.
34
+ *
35
+ * After hydration, `finalize` trims unused capacity and, when some rows were not retained (i.e.
36
+ * their entities were already in the identity map), compacts the payload down to only the
37
+ * retained rows, so retained memory tracks live entities rather than query history.
38
+ *
39
+ * Small results deliberately stay lazy — there is NO row-count threshold below which we
40
+ * materialize to a `PojoRowData` instead. Measured (benchmark-rowdata-small.ts, 40-col rows):
41
+ * for the typical sparse access pattern (~6 of 40 columns read), keeping the lazy result wins at
42
+ * every size including a single row (n=1: 4.3µs vs 7.6µs; n=1000: 0.76ms vs 3.0ms), because
43
+ * materialization eagerly decodes every column while lazy faults only what is read. Even full
44
+ * column coverage no longer flips the winner: with binary decode and `#readCell`'s adaptive
45
+ * scan cursor, reading all ~36 columns of every row measures ~parity with classic end-to-end
46
+ * (benchmark-lazy-parsing.ts), and small finds (n <= 10) are statistically identical.
47
+ */
48
+ declare class WireRowData implements RowData {
49
+ #private;
50
+ get rowCount(): number;
51
+ /** The DataRow payload bytes currently indexed; drops when compaction discards rows. */
52
+ get payloadBytes(): number;
53
+ /** The bytes currently held by payload chunks + the row-slice table, i.e. for benchmarks. */
54
+ get memoryBytes(): number;
55
+ get(rowIndex: number, columnName: string): any;
56
+ /** Materializes one row as a POJO, i.e. for debugging and differential tests; values are not cached. */
57
+ toRow(rowIndex: number): any;
58
+ /** Materializes classic POJO rows, i.e. for `afterFind` observation or debugging; not cached. */
59
+ toRows(): any[];
60
+ /**
61
+ * Resolves each column's decoder from the query's RowDescription.
62
+ *
63
+ * Binary-format fields decode through Joist's own binary registry only (see
64
+ * `setBinaryTypeParser`) — `pg.types`/`TypeOverrides` are never consulted, and a column whose
65
+ * oid has no registered binary parser fails the query here, before any rows arrive, rather
66
+ * than guessing at a lossy decoding. Text-format fields (the `binary: false` escape hatch)
67
+ * decode by utf8-slicing the cell into the active text parser, resolved via `getTypeParser`
68
+ * (i.e. the pool/client `TypeOverrides` chain) or the global registry.
69
+ */
70
+ setRowDescription(fields: Array<{
71
+ name: string;
72
+ dataTypeID: number;
73
+ format?: string;
74
+ }>, getTypeParser?: (dataTypeID: number) => (value: any) => any): void;
75
+ /**
76
+ * Records one DataRow payload *by reference* (zero-copy); called synchronously from the wire
77
+ * parser, whose patched buffer management guarantees the bytes are never rewritten.
78
+ *
79
+ * Consecutive rows usually share one socket chunk, so `bytes` is deduped against the last
80
+ * chunk ref; retaining any row of a chunk pins the whole chunk, which `finalize`'s compaction
81
+ * resolves by copying retained rows out when enough of the payload was dropped.
82
+ */
83
+ addRow(bytes: Buffer, offset: number, payloadLength: number): void;
84
+ /** Marks `rowIndex` as retained by a hydrated entity; unmarked rows can be compacted away. */
85
+ retain(rowIndex: number): void;
86
+ /**
87
+ * Trims unused capacity, and compacts down to only `retain`-ed rows when enough rows were not
88
+ * retained to be worth the copy.
89
+ *
90
+ * Compaction exists to release pinned socket buffers to the GC: rows are zero-copy views into
91
+ * whole ~64KiB chunks, so keeping any row alive pins its entire chunk — and unretained rows
92
+ * are typically duplicates whose entities were *already in memory* (identity-map hits that
93
+ * keep their original `rowData`), making the newly-arrived bytes dead weight. Copying the
94
+ * retained rows into one exact-size owned buffer lets every chunk reference drop.
95
+ *
96
+ * The copy re-copies every retained byte, so it only pays off when it buys back a meaningful
97
+ * fraction of the payload: we compact when the dropped rows hold more than 20% of the payload
98
+ * bytes, and otherwise just trim, accepting the (bounded) leftover bytes. Called once after
99
+ * hydration + sidecar reads (`_tags`, preload aggregates) are complete; retained entities keep
100
+ * their original `rowIndex`, and un-compacted unretained rows simply remain readable-but-unused.
101
+ */
102
+ finalize(): void;
103
+ }
104
+ declare function executeRowDataQuery(client: pg.PoolClient, sql: string, bindings: readonly any[], opts?: {
105
+ binary?: boolean;
106
+ }): Promise<RowData>;
107
+ /** Returns whether `client` supports the lazy row-data query path, before submitting anything. */
108
+ declare function isRowDataCapableClient(client: unknown): client is pg.PoolClient;
109
+ //#endregion
110
+ export { WireRowData, executeRowDataQuery, isRowDataCapableClient };
111
+ //# sourceMappingURL=WireRowData.d.cts.map