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.
- package/build/_virtual/_rolldown/runtime.cjs +23 -0
- package/build/_virtual/_rolldown/runtime.js +5 -0
- package/build/codegen.cjs +19 -0
- package/build/codegen.cjs.map +1 -0
- package/build/codegen.d.cts +1 -0
- package/build/codegen.d.mts +1 -0
- package/build/codegen.js +11 -28
- package/build/codegen.js.map +1 -1
- package/build/drivers/PostgresDriver.cjs +290 -0
- package/build/drivers/PostgresDriver.cjs.map +1 -0
- package/build/drivers/PostgresDriver.d.cts +77 -0
- package/build/drivers/PostgresDriver.d.cts.map +1 -0
- package/build/drivers/PostgresDriver.d.mts +77 -0
- package/build/drivers/PostgresDriver.d.mts.map +1 -0
- package/build/drivers/PostgresDriver.js +249 -325
- package/build/drivers/PostgresDriver.js.map +1 -1
- package/build/drivers/WireRowData.cjs +374 -0
- package/build/drivers/WireRowData.cjs.map +1 -0
- package/build/drivers/WireRowData.d.cts +111 -0
- package/build/drivers/WireRowData.d.cts.map +1 -0
- package/build/drivers/WireRowData.d.mts +111 -0
- package/build/drivers/WireRowData.d.mts.map +1 -0
- package/build/drivers/WireRowData.js +352 -412
- package/build/drivers/WireRowData.js.map +1 -1
- package/build/drivers/binaryParsers.cjs +422 -0
- package/build/drivers/binaryParsers.cjs.map +1 -0
- package/build/drivers/{binaryParsers.d.ts → binaryParsers.d.cts} +18 -14
- package/build/drivers/binaryParsers.d.cts.map +1 -0
- package/build/drivers/binaryParsers.d.mts +80 -0
- package/build/drivers/binaryParsers.d.mts.map +1 -0
- package/build/drivers/binaryParsers.js +315 -385
- package/build/drivers/binaryParsers.js.map +1 -1
- package/build/drivers/patchPgProtocol.cjs +255 -0
- package/build/drivers/patchPgProtocol.cjs.map +1 -0
- package/build/drivers/{patchPgProtocol.d.ts → patchPgProtocol.d.cts} +18 -14
- package/build/drivers/patchPgProtocol.d.cts.map +1 -0
- package/build/drivers/patchPgProtocol.d.mts +47 -0
- package/build/drivers/patchPgProtocol.d.mts.map +1 -0
- package/build/drivers/patchPgProtocol.js +211 -232
- package/build/drivers/patchPgProtocol.js.map +1 -1
- package/build/graphql-codegen-export.cjs +10 -0
- package/build/graphql-codegen-export.d.cts +1 -0
- package/build/graphql-codegen-export.d.mts +1 -0
- package/build/graphql-codegen-export.js +2 -19
- package/build/graphql-export.cjs +10 -0
- package/build/graphql-export.d.cts +1 -0
- package/build/graphql-export.d.mts +1 -0
- package/build/graphql-export.js +2 -19
- package/build/index.cjs +41 -0
- package/build/index.d.cts +3 -0
- package/build/index.d.mts +3 -0
- package/build/index.js +3 -27
- package/build/knex-export.cjs +10 -0
- package/build/knex-export.d.cts +1 -0
- package/build/knex-export.d.mts +1 -0
- package/build/knex-export.js +2 -19
- package/build/pg-export.cjs +13 -0
- package/build/pg-export.d.cts +4 -0
- package/build/pg-export.d.mts +4 -0
- package/build/pg-export.js +4 -20
- package/build/pg-migrate.cjs +22 -0
- package/build/pg-migrate.cjs.map +1 -0
- package/build/pg-migrate.d.cts +1 -0
- package/build/pg-migrate.d.mts +1 -0
- package/build/pg-migrate.js +13 -28
- package/build/pg-migrate.js.map +1 -1
- package/build/seed.cjs +49 -0
- package/build/seed.cjs.map +1 -0
- package/build/{seed.d.ts → seed.d.cts} +5 -1
- package/build/seed.d.cts.map +1 -0
- package/build/seed.d.mts +24 -0
- package/build/seed.d.mts.map +1 -0
- package/build/seed.js +39 -45
- package/build/seed.js.map +1 -1
- package/build/tests-export.cjs +10 -0
- package/build/tests-export.d.cts +1 -0
- package/build/tests-export.d.mts +1 -0
- package/build/tests-export.js +2 -19
- package/package.json +150 -28
- package/build/codegen.d.ts +0 -2
- package/build/drivers/PostgresDriver.d.ts +0 -73
- package/build/drivers/WireRowData.d.ts +0 -107
- package/build/graphql-codegen-export.d.ts +0 -1
- package/build/graphql-codegen-export.js.map +0 -1
- package/build/graphql-export.d.ts +0 -1
- package/build/graphql-export.js.map +0 -1
- package/build/index.d.ts +0 -3
- package/build/index.js.map +0 -1
- package/build/knex-export.d.ts +0 -1
- package/build/knex-export.js.map +0 -1
- package/build/pg-export.d.ts +0 -3
- package/build/pg-export.js.map +0 -1
- package/build/pg-migrate.d.ts +0 -2
- package/build/tests-export.d.ts +0 -1
- package/build/tests-export.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WireRowData.js","sourceRoot":"","sources":["../../src/drivers/WireRowData.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WireRowData.js","names":["#rowCount","#payloadBytes","#rowSlices","#chunks","#columns","#rowBase","#readCell","#fields","#cellLength","#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,422 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let joist_core = require("joist-core");
|
|
3
|
+
//#region src/drivers/binaryParsers.ts
|
|
4
|
+
/**
|
|
5
|
+
* Joist's registry of PostgreSQL *binary-format* cell parsers, used by `WireRowData` for lazy
|
|
6
|
+
* `em.find`/`em.load` results (which request binary output; see `executeRowDataQuery`).
|
|
7
|
+
*
|
|
8
|
+
* This registry is deliberately **separate from `pg.types`**: `pg.types.setTypeParser` and
|
|
9
|
+
* pool/client `TypeOverrides` continue to govern classic *text* results (knex, `pool.query`,
|
|
10
|
+
* non-lazy drivers), while binary cells decode wire-bytes -> values directly — ints via
|
|
11
|
+
* `readInt32BE`, timestamps via µs arithmetic, Temporal values constructed without ever
|
|
12
|
+
* materializing a string. There is no fallback from one registry to the other:
|
|
13
|
+
*
|
|
14
|
+
* - Built-in parsers cover the standard scalar/array types below; `setupLatestPgTypes`
|
|
15
|
+
* registers the date/time parsers appropriate to Date-vs-Temporal mode.
|
|
16
|
+
* - Custom/extension types (native enums, citext, domains, hstore, ...) must be registered
|
|
17
|
+
* explicitly with {@link setBinaryTypeParser} — text-like types can use
|
|
18
|
+
* {@link binaryTextParser}, arrays of registered elements can use {@link binaryArrayParser}.
|
|
19
|
+
* - A query selecting a column whose oid has no registered parser **fails** with a descriptive
|
|
20
|
+
* error (see `WireRowData.setRowDescription`), rather than guessing at a lossy decoding.
|
|
21
|
+
*
|
|
22
|
+
* Values produced here should match what the classic text path produces for the same column
|
|
23
|
+
* (i.e. `numeric` stays a string, `int8` stays a string, Date-mode timestamps become `Date`s),
|
|
24
|
+
* so entities hydrate identically in either mode; Temporal-mode parsers construct
|
|
25
|
+
* `Temporal.PlainDate`/`ZonedDateTime`/etc. directly, and the temporal mappers pass
|
|
26
|
+
* already-constructed instances through.
|
|
27
|
+
*/
|
|
28
|
+
function setBinaryTypeParser(oid, parse) {
|
|
29
|
+
parsers.set(oid, parse);
|
|
30
|
+
}
|
|
31
|
+
/** Returns the registered binary parser for `oid`, i.e. for tests to save/restore. */
|
|
32
|
+
function getBinaryTypeParser(oid) {
|
|
33
|
+
return parsers.get(oid);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Auto-registers binary parsers for the database's text-like dynamic-oid types — native enums
|
|
37
|
+
* and citext, plus their array types — so apps get those for free.
|
|
38
|
+
*
|
|
39
|
+
* `PostgresDriver` calls this lazily before its first lazy query; apps can also call it
|
|
40
|
+
* directly (i.e. at boot) if they want the registrations eagerly. Explicit
|
|
41
|
+
* `setBinaryTypeParser` registrations are never overwritten.
|
|
42
|
+
*/
|
|
43
|
+
async function registerDatabaseBinaryParsers(pool) {
|
|
44
|
+
const [{ rows: settings }, { rows }] = await Promise.all([pool.query(`select current_setting('TimeZone') as tz`), pool.query(`select t.oid, t.typarray
|
|
45
|
+
from pg_type t
|
|
46
|
+
where t.typtype = 'e'
|
|
47
|
+
or t.typname = 'citext'
|
|
48
|
+
or (t.typtype = 'd' and (select b.typcategory from pg_type b where b.oid = t.typbasetype) = 'S')`)]);
|
|
49
|
+
setSessionTimeZone(settings[0].tz);
|
|
50
|
+
for (const row of rows) {
|
|
51
|
+
const oid = Number(row.oid);
|
|
52
|
+
if (getBinaryTypeParser(oid) === void 0) setBinaryTypeParser(oid, binaryTextParser);
|
|
53
|
+
const arrayOid = Number(row.typarray);
|
|
54
|
+
if (arrayOid !== 0 && getBinaryTypeParser(arrayOid) === void 0) setBinaryTypeParser(arrayOid, binaryArrayParser);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sets the session `TimeZone` used to zone temporal-mode `timestamptz` loads; normally captured
|
|
59
|
+
* automatically by {@link registerDatabaseBinaryParsers}. One zone per process — pools with
|
|
60
|
+
* differing session TimeZones are not supported by the binary path.
|
|
61
|
+
*/
|
|
62
|
+
function setSessionTimeZone(timeZone) {
|
|
63
|
+
sessionTimeZone = timeZone === "Etc/UTC" ? "UTC" : timeZone;
|
|
64
|
+
}
|
|
65
|
+
let sessionTimeZone = "UTC";
|
|
66
|
+
/** Decodes a cell's bytes as utf8 text, i.e. for text-like custom types (enums, citext, domains). */
|
|
67
|
+
function binaryTextParser(chunk, start, length) {
|
|
68
|
+
return chunk.toString("utf8", start, start + length);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Decodes a binary array cell into a JS array of element values.
|
|
72
|
+
*
|
|
73
|
+
* The element oid is embedded in the wire format, and each element decodes through this
|
|
74
|
+
* registry — so arrays of any registered type (including custom-registered oids and the
|
|
75
|
+
* mode-appropriate temporal types) work without separate element wiring. Registered for the
|
|
76
|
+
* standard `_type` oids below; register it for custom array oids as needed.
|
|
77
|
+
*/
|
|
78
|
+
function binaryArrayParser(chunk, start, length) {
|
|
79
|
+
const nDims = chunk.readInt32BE(start);
|
|
80
|
+
if (nDims === 0) return [];
|
|
81
|
+
const elemOid = chunk.readInt32BE(start + 8);
|
|
82
|
+
const parse = parsers.get(elemOid) ?? fail(`joist-orm: no binary type parser registered for array element oid ${elemOid}; see setBinaryTypeParser`);
|
|
83
|
+
const dims = [];
|
|
84
|
+
for (let d = 0; d < nDims; d++) dims.push(chunk.readInt32BE(start + 12 + d * 8));
|
|
85
|
+
let pos = start + 12 + nDims * 8;
|
|
86
|
+
function readDim(dim) {
|
|
87
|
+
const values = [];
|
|
88
|
+
for (let i = 0; i < dims[dim]; i++) if (dim < nDims - 1) values.push(readDim(dim + 1));
|
|
89
|
+
else {
|
|
90
|
+
const len = chunk.readInt32BE(pos);
|
|
91
|
+
pos += 4;
|
|
92
|
+
if (len === -1) values.push(null);
|
|
93
|
+
else {
|
|
94
|
+
values.push(parse(chunk, pos, len));
|
|
95
|
+
pos += len;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return values;
|
|
99
|
+
}
|
|
100
|
+
return readDim(0);
|
|
101
|
+
}
|
|
102
|
+
/** Decodes binary `date` cells to `Date`s, matching postgres-date's text semantics; Date mode. */
|
|
103
|
+
function binaryDateToDate(chunk, start) {
|
|
104
|
+
const days = chunk.readInt32BE(start);
|
|
105
|
+
if (days === INFINITY_DAYS) return Infinity;
|
|
106
|
+
if (days === NEG_INFINITY_DAYS) return -Infinity;
|
|
107
|
+
const [year, month, day] = civilFromDays(days + PG_EPOCH_DAYS);
|
|
108
|
+
const date = new Date(year, month - 1, day);
|
|
109
|
+
if (year < 100) date.setFullYear(year);
|
|
110
|
+
return date;
|
|
111
|
+
}
|
|
112
|
+
/** Decodes binary `timestamp` (without zone) cells to local-time `Date`s; Date mode. */
|
|
113
|
+
function binaryTimestampToDate(chunk, start) {
|
|
114
|
+
const pgMicros = chunk.readBigInt64BE(start);
|
|
115
|
+
if (pgMicros === INFINITY_US) return Infinity;
|
|
116
|
+
if (pgMicros === NEG_INFINITY_US) return -Infinity;
|
|
117
|
+
const { days, us } = splitPgMicros(pgMicros);
|
|
118
|
+
const [year, month, day] = civilFromDays(days);
|
|
119
|
+
const seconds = Math.floor(us / 1e6);
|
|
120
|
+
const date = new Date(year, month - 1, day, Math.floor(seconds / 3600), Math.floor(seconds / 60 % 60), seconds % 60, Math.floor(us % 1e6 / 1e3));
|
|
121
|
+
if (year < 100) date.setFullYear(year);
|
|
122
|
+
return date;
|
|
123
|
+
}
|
|
124
|
+
/** Decodes binary `timestamptz` cells to `Date`s (µs floor to ms, like the text parse); Date mode. */
|
|
125
|
+
function binaryTimestamptzToDate(chunk, start) {
|
|
126
|
+
const pgMicros = chunk.readBigInt64BE(start);
|
|
127
|
+
if (pgMicros === INFINITY_US) return Infinity;
|
|
128
|
+
if (pgMicros === NEG_INFINITY_US) return -Infinity;
|
|
129
|
+
const epochMicros = pgMicros + PG_EPOCH_US;
|
|
130
|
+
let ms = epochMicros / 1000n;
|
|
131
|
+
if (epochMicros % 1000n < 0n) ms -= 1n;
|
|
132
|
+
return new Date(Number(ms));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Registers the Temporal-mode binary parsers: date/time/timestamp/timestamptz cells construct
|
|
136
|
+
* `Temporal` values *directly* from the wire µs/days — no intermediate strings, no
|
|
137
|
+
* `temporalMappers.fromDb` parsing (the mappers pass already-constructed instances through).
|
|
138
|
+
*
|
|
139
|
+
* `timestamptz` matches the text path's zoning exactly: classic parsing zones the value by the
|
|
140
|
+
* offset the session's `TimeZone` rendered (normalizing `+00` to `UTC`), so we compute the
|
|
141
|
+
* session zone's offset at each instant (see `setSessionTimeZone`; the configured
|
|
142
|
+
* `temporal.timeZone` only governs `now`-conversions, not loads).
|
|
143
|
+
*/
|
|
144
|
+
function registerTemporalBinaryParsers() {
|
|
145
|
+
const { Temporal: t } = (0, joist_core.requireTemporal)();
|
|
146
|
+
setBinaryTypeParser(oids.DATE, (chunk, start) => {
|
|
147
|
+
const days = chunk.readInt32BE(start);
|
|
148
|
+
if (days === INFINITY_DAYS || days === NEG_INFINITY_DAYS) failTemporalInfinity("date");
|
|
149
|
+
const [year, month, day] = civilFromDays(days + PG_EPOCH_DAYS);
|
|
150
|
+
return new t.PlainDate(year, month, day);
|
|
151
|
+
});
|
|
152
|
+
setBinaryTypeParser(1083, (chunk, start) => {
|
|
153
|
+
const us = Number(chunk.readBigInt64BE(start));
|
|
154
|
+
const seconds = Math.floor(us / 1e6);
|
|
155
|
+
return new t.PlainTime(Math.floor(seconds / 3600), Math.floor(seconds / 60 % 60), seconds % 60, Math.floor(us % 1e6 / 1e3), us % 1e3);
|
|
156
|
+
});
|
|
157
|
+
setBinaryTypeParser(oids.TIMESTAMP, (chunk, start) => {
|
|
158
|
+
const pgMicros = chunk.readBigInt64BE(start);
|
|
159
|
+
if (pgMicros === INFINITY_US || pgMicros === NEG_INFINITY_US) failTemporalInfinity("timestamp");
|
|
160
|
+
const { days, us } = splitPgMicros(pgMicros);
|
|
161
|
+
const [year, month, day] = civilFromDays(days);
|
|
162
|
+
const seconds = Math.floor(us / 1e6);
|
|
163
|
+
return new t.PlainDateTime(year, month, day, Math.floor(seconds / 3600), Math.floor(seconds / 60 % 60), seconds % 60, Math.floor(us % 1e6 / 1e3), us % 1e3);
|
|
164
|
+
});
|
|
165
|
+
setBinaryTypeParser(oids.TIMESTAMPTZ, (chunk, start) => {
|
|
166
|
+
const pgMicros = chunk.readBigInt64BE(start);
|
|
167
|
+
if (pgMicros === INFINITY_US || pgMicros === NEG_INFINITY_US) failTemporalInfinity("timestamptz");
|
|
168
|
+
const instant = t.Instant.fromEpochNanoseconds((pgMicros + PG_EPOCH_US) * 1000n);
|
|
169
|
+
if (sessionTimeZone === "UTC") return instant.toZonedDateTimeISO("UTC");
|
|
170
|
+
const zoned = instant.toZonedDateTimeISO(sessionTimeZone);
|
|
171
|
+
const { offset } = zoned;
|
|
172
|
+
return offset === "+00:00" ? zoned.withTimeZone("UTC") : zoned.withTimeZone(offset);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const PG_EPOCH_US = 946684800000000n;
|
|
176
|
+
const PG_EPOCH_DAYS = 10957;
|
|
177
|
+
const US_PER_DAY = 86400000000n;
|
|
178
|
+
const INFINITY_US = 9223372036854775807n;
|
|
179
|
+
const NEG_INFINITY_US = -9223372036854775808n;
|
|
180
|
+
const INFINITY_DAYS = 2147483647;
|
|
181
|
+
const NEG_INFINITY_DAYS = -2147483648;
|
|
182
|
+
const oids = {
|
|
183
|
+
BOOL: 16,
|
|
184
|
+
BYTEA: 17,
|
|
185
|
+
INT8: 20,
|
|
186
|
+
INT2: 21,
|
|
187
|
+
INT4: 23,
|
|
188
|
+
TEXT: 25,
|
|
189
|
+
OID: 26,
|
|
190
|
+
JSON: 114,
|
|
191
|
+
FLOAT4: 700,
|
|
192
|
+
FLOAT8: 701,
|
|
193
|
+
BPCHAR: 1042,
|
|
194
|
+
VARCHAR: 1043,
|
|
195
|
+
DATE: 1082,
|
|
196
|
+
TIMESTAMP: 1114,
|
|
197
|
+
TIMESTAMPTZ: 1184,
|
|
198
|
+
NUMERIC: 1700,
|
|
199
|
+
UUID: 2950,
|
|
200
|
+
JSONB: 3802
|
|
201
|
+
};
|
|
202
|
+
const parsers = /* @__PURE__ */ new Map();
|
|
203
|
+
setBinaryTypeParser(oids.BOOL, (chunk, start) => chunk[start] !== 0);
|
|
204
|
+
setBinaryTypeParser(oids.INT2, (chunk, start) => chunk.readInt16BE(start));
|
|
205
|
+
setBinaryTypeParser(oids.INT4, (chunk, start) => chunk.readInt32BE(start));
|
|
206
|
+
setBinaryTypeParser(oids.OID, (chunk, start) => chunk.readUInt32BE(start));
|
|
207
|
+
setBinaryTypeParser(oids.INT8, (chunk, start) => chunk.readBigInt64BE(start).toString());
|
|
208
|
+
setBinaryTypeParser(oids.FLOAT4, (chunk, start) => readFloat4(chunk, start));
|
|
209
|
+
setBinaryTypeParser(oids.FLOAT8, (chunk, start) => chunk.readDoubleBE(start));
|
|
210
|
+
setBinaryTypeParser(oids.TEXT, binaryTextParser);
|
|
211
|
+
setBinaryTypeParser(oids.VARCHAR, binaryTextParser);
|
|
212
|
+
setBinaryTypeParser(oids.BPCHAR, binaryTextParser);
|
|
213
|
+
setBinaryTypeParser(19, binaryTextParser);
|
|
214
|
+
setBinaryTypeParser(oids.UUID, (chunk, start) => renderUuid(chunk, start));
|
|
215
|
+
setBinaryTypeParser(oids.BYTEA, copyBytes);
|
|
216
|
+
setBinaryTypeParser(oids.JSON, (chunk, start, length) => JSON.parse(chunk.toString("utf8", start, start + length)));
|
|
217
|
+
setBinaryTypeParser(oids.JSONB, (chunk, start, length) => JSON.parse(chunk.toString("utf8", start + 1, start + length)));
|
|
218
|
+
setBinaryTypeParser(oids.NUMERIC, renderNumeric);
|
|
219
|
+
setBinaryTypeParser(3614, renderTsVector);
|
|
220
|
+
setBinaryTypeParser(3910, (chunk, start) => renderRange(chunk, start, (c, s) => {
|
|
221
|
+
const text = renderTimestamp(c.readBigInt64BE(s), "+00");
|
|
222
|
+
return text === "infinity" || text === "-infinity" ? text : `"${text}"`;
|
|
223
|
+
}));
|
|
224
|
+
setBinaryTypeParser(1083, (chunk, start) => renderTimeOfDay(Number(chunk.readBigInt64BE(start))));
|
|
225
|
+
for (const arrayOid of [
|
|
226
|
+
1e3,
|
|
227
|
+
1001,
|
|
228
|
+
1005,
|
|
229
|
+
1007,
|
|
230
|
+
1009,
|
|
231
|
+
1014,
|
|
232
|
+
1015,
|
|
233
|
+
1016,
|
|
234
|
+
1021,
|
|
235
|
+
1022,
|
|
236
|
+
1182,
|
|
237
|
+
1183,
|
|
238
|
+
1115,
|
|
239
|
+
1185,
|
|
240
|
+
1231,
|
|
241
|
+
2951,
|
|
242
|
+
199,
|
|
243
|
+
3807,
|
|
244
|
+
3643,
|
|
245
|
+
3911
|
|
246
|
+
]) setBinaryTypeParser(arrayOid, binaryArrayParser);
|
|
247
|
+
setBinaryTypeParser(oids.DATE, binaryDateToDate);
|
|
248
|
+
setBinaryTypeParser(oids.TIMESTAMP, binaryTimestampToDate);
|
|
249
|
+
setBinaryTypeParser(oids.TIMESTAMPTZ, binaryTimestamptzToDate);
|
|
250
|
+
/** Splits pg timestamp µs into days-since-1970 and µs-within-day, flooring correctly pre-epoch. */
|
|
251
|
+
function splitPgMicros(pgMicros) {
|
|
252
|
+
const epochMicros = pgMicros + PG_EPOCH_US;
|
|
253
|
+
let days = epochMicros / US_PER_DAY;
|
|
254
|
+
let micros = epochMicros % US_PER_DAY;
|
|
255
|
+
if (micros < 0n) {
|
|
256
|
+
days -= 1n;
|
|
257
|
+
micros += US_PER_DAY;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
days: Number(days),
|
|
261
|
+
us: Number(micros)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/** Fails on the ±infinity wire sentinels, which have no Temporal representation. */
|
|
265
|
+
function failTemporalInfinity(type) {
|
|
266
|
+
return fail(`joist-orm: cannot represent an 'infinity' ${type} as a Temporal value`);
|
|
267
|
+
}
|
|
268
|
+
/** Reads a float4 as its shortest round-trip decimal, matching pg's shortest text output. */
|
|
269
|
+
function readFloat4(chunk, start) {
|
|
270
|
+
const value = chunk.readFloatBE(start);
|
|
271
|
+
if (!Number.isFinite(value)) return value;
|
|
272
|
+
if (value === 0) return value;
|
|
273
|
+
for (let precision = 1; precision <= 9; precision++) {
|
|
274
|
+
const shortest = Number(value.toPrecision(precision));
|
|
275
|
+
if (Math.fround(shortest) === value) return shortest;
|
|
276
|
+
}
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
/** Copies the exact cell bytes, i.e. for bytea values. */
|
|
280
|
+
function copyBytes(chunk, start, length) {
|
|
281
|
+
const cell = Buffer.allocUnsafe(length);
|
|
282
|
+
chunk.copy(cell, 0, start, start + length);
|
|
283
|
+
return cell;
|
|
284
|
+
}
|
|
285
|
+
/** Renders a binary uuid (16 bytes) as the canonical dashed-hex string. */
|
|
286
|
+
function renderUuid(chunk, start) {
|
|
287
|
+
const hex = chunk.toString("hex", start, start + 16);
|
|
288
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
289
|
+
}
|
|
290
|
+
/** Renders a binary numeric (base-10000 digit groups) to pg's text form, i.e. `-12.340`. */
|
|
291
|
+
function renderNumeric(chunk, start) {
|
|
292
|
+
const nDigits = chunk.readInt16BE(start);
|
|
293
|
+
const weight = chunk.readInt16BE(start + 2);
|
|
294
|
+
const sign = chunk.readUInt16BE(start + 4);
|
|
295
|
+
const dscale = chunk.readUInt16BE(start + 6);
|
|
296
|
+
if (sign === 49152) return "NaN";
|
|
297
|
+
if (sign === 53248) return "Infinity";
|
|
298
|
+
if (sign === 61440) return "-Infinity";
|
|
299
|
+
let integer = "";
|
|
300
|
+
for (let w = weight, i = 0; w >= 0; w--, i++) {
|
|
301
|
+
const group = i < nDigits ? chunk.readUInt16BE(start + 8 + i * 2) : 0;
|
|
302
|
+
integer += integer === "" ? String(group) : String(group).padStart(4, "0");
|
|
303
|
+
}
|
|
304
|
+
if (integer === "") integer = "0";
|
|
305
|
+
if (dscale === 0) return sign === 16384 ? `-${integer}` : integer;
|
|
306
|
+
let fraction = "";
|
|
307
|
+
for (let k = 1; fraction.length < dscale; k++) {
|
|
308
|
+
const i = weight + k;
|
|
309
|
+
const group = i >= 0 && i < nDigits ? chunk.readUInt16BE(start + 8 + i * 2) : 0;
|
|
310
|
+
fraction += String(group).padStart(4, "0");
|
|
311
|
+
}
|
|
312
|
+
fraction = fraction.slice(0, dscale);
|
|
313
|
+
return `${sign === 16384 ? "-" : ""}${integer}.${fraction}`;
|
|
314
|
+
}
|
|
315
|
+
/** Renders a binary tsvector (lexeme cstrings + position/weight words) to pg's text form, i.e. `'new':2A`. */
|
|
316
|
+
function renderTsVector(chunk, start) {
|
|
317
|
+
const count = chunk.readInt32BE(start);
|
|
318
|
+
let pos = start + 4;
|
|
319
|
+
const lexemes = [];
|
|
320
|
+
for (let i = 0; i < count; i++) {
|
|
321
|
+
const end = chunk.indexOf(0, pos);
|
|
322
|
+
const word = chunk.toString("utf8", pos, end).replace(/\\/g, "\\\\").replace(/'/g, "''");
|
|
323
|
+
pos = end + 1;
|
|
324
|
+
const nPositions = chunk.readUInt16BE(pos);
|
|
325
|
+
pos += 2;
|
|
326
|
+
const positions = [];
|
|
327
|
+
for (let p = 0; p < nPositions; p++) {
|
|
328
|
+
const entry = chunk.readUInt16BE(pos);
|
|
329
|
+
pos += 2;
|
|
330
|
+
positions.push(`${entry & 16383}${weightSuffixes[entry >> 14]}`);
|
|
331
|
+
}
|
|
332
|
+
lexemes.push(positions.length > 0 ? `'${word}':${positions.join(",")}` : `'${word}'`);
|
|
333
|
+
}
|
|
334
|
+
return lexemes.join(" ");
|
|
335
|
+
}
|
|
336
|
+
const weightSuffixes = [
|
|
337
|
+
"",
|
|
338
|
+
"C",
|
|
339
|
+
"B",
|
|
340
|
+
"A"
|
|
341
|
+
];
|
|
342
|
+
/** Renders a binary range (flags byte + length-prefixed bounds) to pg's text form, i.e. `["a","b")`. */
|
|
343
|
+
function renderRange(chunk, start, bound) {
|
|
344
|
+
const flags = chunk[start];
|
|
345
|
+
if (flags & 1) return "empty";
|
|
346
|
+
let pos = start + 1;
|
|
347
|
+
let lower = "";
|
|
348
|
+
let upper = "";
|
|
349
|
+
if (!(flags & 8)) {
|
|
350
|
+
const len = chunk.readInt32BE(pos);
|
|
351
|
+
lower = bound(chunk, pos + 4);
|
|
352
|
+
pos += 4 + len;
|
|
353
|
+
}
|
|
354
|
+
if (!(flags & 16)) upper = bound(chunk, pos + 4);
|
|
355
|
+
return `${flags & 2 ? "[" : "("}${lower},${upper}${flags & 4 ? "]" : ")"}`;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Renders the `YYYY-MM-DD` part, converting astronomical years to pg's BC numbering
|
|
359
|
+
* (astronomical year 0 = `0001 BC`); timestamps append the ` BC` marker after the time/zone.
|
|
360
|
+
*/
|
|
361
|
+
function renderDatePart(epochDays) {
|
|
362
|
+
const [year, month, day] = civilFromDays(epochDays);
|
|
363
|
+
const bc = year <= 0;
|
|
364
|
+
const displayYear = bc ? 1 - year : year;
|
|
365
|
+
return {
|
|
366
|
+
text: `${String(displayYear).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
|
|
367
|
+
bc
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/** Renders a binary timestamp (µs since 2000-01-01) to pg's text form, i.e. `2020-01-02 03:04:05.678+00`. */
|
|
371
|
+
function renderTimestamp(pgMicros, suffix) {
|
|
372
|
+
if (pgMicros === INFINITY_US) return "infinity";
|
|
373
|
+
if (pgMicros === NEG_INFINITY_US) return "-infinity";
|
|
374
|
+
const { days, us } = splitPgMicros(pgMicros);
|
|
375
|
+
const { text: date, bc } = renderDatePart(days);
|
|
376
|
+
return `${date} ${renderTimeOfDay(us)}${suffix}${bc ? " BC" : ""}`;
|
|
377
|
+
}
|
|
378
|
+
/** Renders µs-since-midnight to pg's time text, i.e. `03:04:05.678` with trailing zeros trimmed. */
|
|
379
|
+
function renderTimeOfDay(us) {
|
|
380
|
+
const seconds = Math.floor(us / 1e6);
|
|
381
|
+
const hh = String(Math.floor(seconds / 3600)).padStart(2, "0");
|
|
382
|
+
const mm = String(Math.floor(seconds / 60 % 60)).padStart(2, "0");
|
|
383
|
+
const ss = String(seconds % 60).padStart(2, "0");
|
|
384
|
+
let fraction = "";
|
|
385
|
+
const usPart = us % 1e6;
|
|
386
|
+
if (usPart > 0) fraction = `.${String(usPart).padStart(6, "0")}`.replace(/0+$/, "");
|
|
387
|
+
return `${hh}:${mm}:${ss}${fraction}`;
|
|
388
|
+
}
|
|
389
|
+
/** Converts days-since-1970 to a civil [year, month, day], i.e. Howard Hinnant's algorithm. */
|
|
390
|
+
function civilFromDays(epochDays) {
|
|
391
|
+
const z = epochDays + 719468;
|
|
392
|
+
const era = Math.floor(z / 146097);
|
|
393
|
+
const doe = z - era * 146097;
|
|
394
|
+
const yoe = Math.floor((doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365);
|
|
395
|
+
const y = yoe + era * 400;
|
|
396
|
+
const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100));
|
|
397
|
+
const mp = Math.floor((5 * doy + 2) / 153);
|
|
398
|
+
const d = doy - Math.floor((153 * mp + 2) / 5) + 1;
|
|
399
|
+
const m = mp < 10 ? mp + 3 : mp - 9;
|
|
400
|
+
return [
|
|
401
|
+
m <= 2 ? y + 1 : y,
|
|
402
|
+
m,
|
|
403
|
+
d
|
|
404
|
+
];
|
|
405
|
+
}
|
|
406
|
+
/** Throws an `Error` with `message`. */
|
|
407
|
+
function fail(message) {
|
|
408
|
+
throw new Error(message);
|
|
409
|
+
}
|
|
410
|
+
//#endregion
|
|
411
|
+
exports.binaryArrayParser = binaryArrayParser;
|
|
412
|
+
exports.binaryDateToDate = binaryDateToDate;
|
|
413
|
+
exports.binaryTextParser = binaryTextParser;
|
|
414
|
+
exports.binaryTimestampToDate = binaryTimestampToDate;
|
|
415
|
+
exports.binaryTimestamptzToDate = binaryTimestamptzToDate;
|
|
416
|
+
exports.getBinaryTypeParser = getBinaryTypeParser;
|
|
417
|
+
exports.registerDatabaseBinaryParsers = registerDatabaseBinaryParsers;
|
|
418
|
+
exports.registerTemporalBinaryParsers = registerTemporalBinaryParsers;
|
|
419
|
+
exports.setBinaryTypeParser = setBinaryTypeParser;
|
|
420
|
+
exports.setSessionTimeZone = setSessionTimeZone;
|
|
421
|
+
|
|
422
|
+
//# sourceMappingURL=binaryParsers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binaryParsers.cjs","names":["requireTemporal"],"sources":["../../src/drivers/binaryParsers.ts"],"sourcesContent":["import { requireTemporal } from \"joist-core\";\n\n/**\n * Joist's registry of PostgreSQL *binary-format* cell parsers, used by `WireRowData` for lazy\n * `em.find`/`em.load` results (which request binary output; see `executeRowDataQuery`).\n *\n * This registry is deliberately **separate from `pg.types`**: `pg.types.setTypeParser` and\n * pool/client `TypeOverrides` continue to govern classic *text* results (knex, `pool.query`,\n * non-lazy drivers), while binary cells decode wire-bytes -> values directly — ints via\n * `readInt32BE`, timestamps via µs arithmetic, Temporal values constructed without ever\n * materializing a string. There is no fallback from one registry to the other:\n *\n * - Built-in parsers cover the standard scalar/array types below; `setupLatestPgTypes`\n * registers the date/time parsers appropriate to Date-vs-Temporal mode.\n * - Custom/extension types (native enums, citext, domains, hstore, ...) must be registered\n * explicitly with {@link setBinaryTypeParser} — text-like types can use\n * {@link binaryTextParser}, arrays of registered elements can use {@link binaryArrayParser}.\n * - A query selecting a column whose oid has no registered parser **fails** with a descriptive\n * error (see `WireRowData.setRowDescription`), rather than guessing at a lossy decoding.\n *\n * Values produced here should match what the classic text path produces for the same column\n * (i.e. `numeric` stays a string, `int8` stays a string, Date-mode timestamps become `Date`s),\n * so entities hydrate identically in either mode; Temporal-mode parsers construct\n * `Temporal.PlainDate`/`ZonedDateTime`/etc. directly, and the temporal mappers pass\n * already-constructed instances through.\n */\nexport function setBinaryTypeParser(oid: number, parse: BinaryParse): void {\n parsers.set(oid, parse);\n}\n\n/** Returns the registered binary parser for `oid`, i.e. for tests to save/restore. */\nexport function getBinaryTypeParser(oid: number): BinaryParse | undefined {\n return parsers.get(oid);\n}\n\n/** Decodes one binary cell directly from the payload chunk; `length` is the cell's byte length. */\nexport type BinaryParse = (chunk: Buffer, start: number, length: number) => any;\n\n/**\n * Auto-registers binary parsers for the database's text-like dynamic-oid types — native enums\n * and citext, plus their array types — so apps get those for free.\n *\n * `PostgresDriver` calls this lazily before its first lazy query; apps can also call it\n * directly (i.e. at boot) if they want the registrations eagerly. Explicit\n * `setBinaryTypeParser` registrations are never overwritten.\n */\nexport async function registerDatabaseBinaryParsers(pool: {\n query(sql: string): Promise<{ rows: any[] }>;\n}): Promise<void> {\n // Also capture the session's TimeZone, which zones temporal-mode timestamptz loads to match\n // what classic text parsing would have produced (pg renders timestamps in the session zone)\n const [{ rows: settings }, { rows }] = await Promise.all([\n pool.query(`select current_setting('TimeZone') as tz`),\n pool.query(\n `select t.oid, t.typarray\n from pg_type t\n where t.typtype = 'e'\n or t.typname = 'citext'\n or (t.typtype = 'd' and (select b.typcategory from pg_type b where b.oid = t.typbasetype) = 'S')`,\n ),\n ]);\n setSessionTimeZone(settings[0].tz);\n for (const row of rows) {\n const oid = Number(row.oid);\n if (getBinaryTypeParser(oid) === undefined) setBinaryTypeParser(oid, binaryTextParser);\n const arrayOid = Number(row.typarray);\n if (arrayOid !== 0 && getBinaryTypeParser(arrayOid) === undefined) {\n setBinaryTypeParser(arrayOid, binaryArrayParser);\n }\n }\n}\n\n/**\n * Sets the session `TimeZone` used to zone temporal-mode `timestamptz` loads; normally captured\n * automatically by {@link registerDatabaseBinaryParsers}. One zone per process — pools with\n * differing session TimeZones are not supported by the binary path.\n */\nexport function setSessionTimeZone(timeZone: string): void {\n sessionTimeZone = timeZone === \"Etc/UTC\" ? \"UTC\" : timeZone;\n}\n\nlet sessionTimeZone = \"UTC\";\n\n/** Decodes a cell's bytes as utf8 text, i.e. for text-like custom types (enums, citext, domains). */\nexport function binaryTextParser(chunk: Buffer, start: number, length: number): string {\n return chunk.toString(\"utf8\", start, start + length);\n}\n\n/**\n * Decodes a binary array cell into a JS array of element values.\n *\n * The element oid is embedded in the wire format, and each element decodes through this\n * registry — so arrays of any registered type (including custom-registered oids and the\n * mode-appropriate temporal types) work without separate element wiring. Registered for the\n * standard `_type` oids below; register it for custom array oids as needed.\n */\nexport function binaryArrayParser(chunk: Buffer, start: number, length: number): any[] {\n const nDims = chunk.readInt32BE(start);\n if (nDims === 0) return [];\n const elemOid = chunk.readInt32BE(start + 8);\n const parse =\n parsers.get(elemOid) ??\n fail(`joist-orm: no binary type parser registered for array element oid ${elemOid}; see setBinaryTypeParser`);\n const dims: number[] = [];\n for (let d = 0; d < nDims; d++) dims.push(chunk.readInt32BE(start + 12 + d * 8));\n let pos = start + 12 + nDims * 8;\n function readDim(dim: number): any[] {\n const values: any[] = [];\n for (let i = 0; i < dims[dim]; i++) {\n if (dim < nDims - 1) {\n values.push(readDim(dim + 1));\n } else {\n const len = chunk.readInt32BE(pos);\n pos += 4;\n if (len === -1) {\n values.push(null);\n } else {\n values.push(parse(chunk, pos, len));\n pos += len;\n }\n }\n }\n return values;\n }\n return readDim(0);\n}\n\n/** Decodes binary `date` cells to `Date`s, matching postgres-date's text semantics; Date mode. */\nexport function binaryDateToDate(chunk: Buffer, start: number): any {\n const days = chunk.readInt32BE(start);\n if (days === INFINITY_DAYS) return Infinity;\n if (days === NEG_INFINITY_DAYS) return -Infinity;\n const [year, month, day] = civilFromDays(days + PG_EPOCH_DAYS);\n const date = new Date(year, month - 1, day);\n // Mirror postgres-date's fixup for years 0-99 being interpreted as 1900-1999\n if (year < 100) date.setFullYear(year);\n return date;\n}\n\n/** Decodes binary `timestamp` (without zone) cells to local-time `Date`s; Date mode. */\nexport function binaryTimestampToDate(chunk: Buffer, start: number): any {\n const pgMicros = chunk.readBigInt64BE(start);\n if (pgMicros === INFINITY_US) return Infinity;\n if (pgMicros === NEG_INFINITY_US) return -Infinity;\n const { days, us } = splitPgMicros(pgMicros);\n const [year, month, day] = civilFromDays(days);\n const seconds = Math.floor(us / 1_000_000);\n const date = new Date(\n year,\n month - 1,\n day,\n Math.floor(seconds / 3600),\n Math.floor((seconds / 60) % 60),\n seconds % 60,\n Math.floor((us % 1_000_000) / 1000),\n );\n if (year < 100) date.setFullYear(year);\n return date;\n}\n\n/** Decodes binary `timestamptz` cells to `Date`s (µs floor to ms, like the text parse); Date mode. */\nexport function binaryTimestamptzToDate(chunk: Buffer, start: number): any {\n const pgMicros = chunk.readBigInt64BE(start);\n if (pgMicros === INFINITY_US) return Infinity;\n if (pgMicros === NEG_INFINITY_US) return -Infinity;\n const epochMicros = pgMicros + PG_EPOCH_US;\n let ms = epochMicros / 1000n;\n if (epochMicros % 1000n < 0n) ms -= 1n;\n return new Date(Number(ms));\n}\n\n/**\n * Registers the Temporal-mode binary parsers: date/time/timestamp/timestamptz cells construct\n * `Temporal` values *directly* from the wire µs/days — no intermediate strings, no\n * `temporalMappers.fromDb` parsing (the mappers pass already-constructed instances through).\n *\n * `timestamptz` matches the text path's zoning exactly: classic parsing zones the value by the\n * offset the session's `TimeZone` rendered (normalizing `+00` to `UTC`), so we compute the\n * session zone's offset at each instant (see `setSessionTimeZone`; the configured\n * `temporal.timeZone` only governs `now`-conversions, not loads).\n */\nexport function registerTemporalBinaryParsers(): void {\n const { Temporal: t } = requireTemporal();\n setBinaryTypeParser(oids.DATE, (chunk, start) => {\n const days = chunk.readInt32BE(start);\n if (days === INFINITY_DAYS || days === NEG_INFINITY_DAYS) failTemporalInfinity(\"date\");\n const [year, month, day] = civilFromDays(days + PG_EPOCH_DAYS);\n return new t.PlainDate(year, month, day);\n });\n setBinaryTypeParser(1083 /* time */, (chunk, start) => {\n const us = Number(chunk.readBigInt64BE(start));\n const seconds = Math.floor(us / 1_000_000);\n return new t.PlainTime(\n Math.floor(seconds / 3600),\n Math.floor((seconds / 60) % 60),\n seconds % 60,\n Math.floor((us % 1_000_000) / 1000),\n us % 1000,\n );\n });\n setBinaryTypeParser(oids.TIMESTAMP, (chunk, start) => {\n const pgMicros = chunk.readBigInt64BE(start);\n if (pgMicros === INFINITY_US || pgMicros === NEG_INFINITY_US) failTemporalInfinity(\"timestamp\");\n const { days, us } = splitPgMicros(pgMicros);\n const [year, month, day] = civilFromDays(days);\n const seconds = Math.floor(us / 1_000_000);\n return new t.PlainDateTime(\n year,\n month,\n day,\n Math.floor(seconds / 3600),\n Math.floor((seconds / 60) % 60),\n seconds % 60,\n Math.floor((us % 1_000_000) / 1000),\n us % 1000,\n );\n });\n setBinaryTypeParser(oids.TIMESTAMPTZ, (chunk, start) => {\n const pgMicros = chunk.readBigInt64BE(start);\n if (pgMicros === INFINITY_US || pgMicros === NEG_INFINITY_US) failTemporalInfinity(\"timestamptz\");\n const instant = t.Instant.fromEpochNanoseconds((pgMicros + PG_EPOCH_US) * 1000n);\n if (sessionTimeZone === \"UTC\") return instant.toZonedDateTimeISO(\"UTC\");\n // Zone by the session zone's offset at this instant, i.e. what pg's text rendering carries\n const zoned = instant.toZonedDateTimeISO(sessionTimeZone);\n const { offset } = zoned;\n return offset === \"+00:00\" ? zoned.withTimeZone(\"UTC\") : zoned.withTimeZone(offset);\n });\n}\n\n// Microseconds between the Postgres epoch (2000-01-01) and the Unix epoch (1970-01-01)\nconst PG_EPOCH_US = 946_684_800_000_000n;\nconst PG_EPOCH_DAYS = 10_957;\nconst US_PER_DAY = 86_400_000_000n;\n// The wire sentinels for `infinity` / `-infinity` timestamps and dates\nconst INFINITY_US = 0x7fffffffffffffffn;\nconst NEG_INFINITY_US = -0x8000000000000000n;\nconst INFINITY_DAYS = 0x7fffffff;\nconst NEG_INFINITY_DAYS = -0x80000000;\n\n// pg's builtin oids, inlined to avoid importing pg here (these are protocol constants)\nconst oids = {\n BOOL: 16,\n BYTEA: 17,\n INT8: 20,\n INT2: 21,\n INT4: 23,\n TEXT: 25,\n OID: 26,\n JSON: 114,\n FLOAT4: 700,\n FLOAT8: 701,\n BPCHAR: 1042,\n VARCHAR: 1043,\n DATE: 1082,\n TIMESTAMP: 1114,\n TIMESTAMPTZ: 1184,\n NUMERIC: 1700,\n UUID: 2950,\n JSONB: 3802,\n};\n\nconst parsers = new Map<number, BinaryParse>();\n\n// The standard scalar builtins; values match what the classic text path produces for the same\n// column, i.e. int8/numeric stay strings, bytea stays a Buffer (byte-exact, where classic pg's\n// binary handling is utf8-lossy)\nsetBinaryTypeParser(oids.BOOL, (chunk, start) => chunk[start] !== 0);\nsetBinaryTypeParser(oids.INT2, (chunk, start) => chunk.readInt16BE(start));\nsetBinaryTypeParser(oids.INT4, (chunk, start) => chunk.readInt32BE(start));\nsetBinaryTypeParser(oids.OID, (chunk, start) => chunk.readUInt32BE(start));\nsetBinaryTypeParser(oids.INT8, (chunk, start) => chunk.readBigInt64BE(start).toString());\nsetBinaryTypeParser(oids.FLOAT4, (chunk, start) => readFloat4(chunk, start));\nsetBinaryTypeParser(oids.FLOAT8, (chunk, start) => chunk.readDoubleBE(start));\nsetBinaryTypeParser(oids.TEXT, binaryTextParser);\nsetBinaryTypeParser(oids.VARCHAR, binaryTextParser);\nsetBinaryTypeParser(oids.BPCHAR, binaryTextParser);\nsetBinaryTypeParser(19 /* name */, binaryTextParser);\nsetBinaryTypeParser(oids.UUID, (chunk, start) => renderUuid(chunk, start));\nsetBinaryTypeParser(oids.BYTEA, copyBytes);\nsetBinaryTypeParser(oids.JSON, (chunk, start, length) => JSON.parse(chunk.toString(\"utf8\", start, start + length)));\n// jsonb payloads have a 1-byte version prefix before the JSON text\nsetBinaryTypeParser(oids.JSONB, (chunk, start, length) =>\n JSON.parse(chunk.toString(\"utf8\", start + 1, start + length)),\n);\nsetBinaryTypeParser(oids.NUMERIC, renderNumeric);\nsetBinaryTypeParser(3614 /* tsvector */, renderTsVector);\nsetBinaryTypeParser(3910 /* tstzrange */, (chunk, start) =>\n renderRange(chunk, start, (c, s) => {\n // pg quotes finite bounds (they contain spaces) but renders infinity bounds bare\n const text = renderTimestamp(c.readBigInt64BE(s), \"+00\");\n return text === \"infinity\" || text === \"-infinity\" ? text : `\"${text}\"`;\n }),\n);\n// Rendered like pg's text output, which is also what the classic text path yields (no parser)\nsetBinaryTypeParser(1083 /* time */, (chunk, start) => renderTimeOfDay(Number(chunk.readBigInt64BE(start))));\n\n// The standard `_type` array oids; elements decode through the registry (see binaryArrayParser)\nfor (const arrayOid of [\n 1000, // bool[]\n 1001, // bytea[]\n 1005, // int2[]\n 1007, // int4[]\n 1009, // text[]\n 1014, // bpchar[]\n 1015, // varchar[]\n 1016, // int8[]\n 1021, // float4[]\n 1022, // float8[]\n 1182, // date[]\n 1183, // time[]\n 1115, // timestamp[]\n 1185, // timestamptz[]\n 1231, // numeric[]\n 2951, // uuid[]\n 199, // json[]\n 3807, // jsonb[]\n 3643, // tsvector[]\n 3911, // tstzrange[]\n]) {\n setBinaryTypeParser(arrayOid, binaryArrayParser);\n}\n\n// Default the date/time oids to Date-mode semantics; `setupLatestPgTypes` re-registers the\n// Temporal-mode parsers when the app runs with `temporal` configured\nsetBinaryTypeParser(oids.DATE, binaryDateToDate);\nsetBinaryTypeParser(oids.TIMESTAMP, binaryTimestampToDate);\nsetBinaryTypeParser(oids.TIMESTAMPTZ, binaryTimestamptzToDate);\n\n/** Splits pg timestamp µs into days-since-1970 and µs-within-day, flooring correctly pre-epoch. */\nfunction splitPgMicros(pgMicros: bigint): { days: number; us: number } {\n const epochMicros = pgMicros + PG_EPOCH_US;\n let days = epochMicros / US_PER_DAY;\n let micros = epochMicros % US_PER_DAY;\n if (micros < 0n) {\n days -= 1n;\n micros += US_PER_DAY;\n }\n return { days: Number(days), us: Number(micros) };\n}\n\n/** Fails on the ±infinity wire sentinels, which have no Temporal representation. */\nfunction failTemporalInfinity(type: string): never {\n return fail(`joist-orm: cannot represent an 'infinity' ${type} as a Temporal value`);\n}\n\n/** Reads a float4 as its shortest round-trip decimal, matching pg's shortest text output. */\nfunction readFloat4(chunk: Buffer, start: number): number {\n const value = chunk.readFloatBE(start);\n if (!Number.isFinite(value)) return value;\n // ±0 as-is: toPrecision would drop -0's sign, and === cannot tell the zeros apart\n if (value === 0) return value;\n // The raw float32 -> float64 widening (i.e. 0.1f -> 0.10000000149...) diverges from the text\n // path, which parses pg's shortest repr; find the shortest decimal that round-trips instead\n // (binary32 needs at most 9 significant decimal digits)\n for (let precision = 1; precision <= 9; precision++) {\n const shortest = Number(value.toPrecision(precision));\n if (Math.fround(shortest) === value) return shortest;\n }\n return value;\n}\n\n/** Copies the exact cell bytes, i.e. for bytea values. */\nfunction copyBytes(chunk: Buffer, start: number, length: number): Buffer {\n const cell = Buffer.allocUnsafe(length);\n chunk.copy(cell, 0, start, start + length);\n return cell;\n}\n\n/** Renders a binary uuid (16 bytes) as the canonical dashed-hex string. */\nfunction renderUuid(chunk: Buffer, start: number): string {\n const hex = chunk.toString(\"hex\", start, start + 16);\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** Renders a binary numeric (base-10000 digit groups) to pg's text form, i.e. `-12.340`. */\nfunction renderNumeric(chunk: Buffer, start: number): string {\n const nDigits = chunk.readInt16BE(start);\n const weight = chunk.readInt16BE(start + 2);\n const sign = chunk.readUInt16BE(start + 4);\n const dscale = chunk.readUInt16BE(start + 6);\n if (sign === 0xc000) return \"NaN\";\n if (sign === 0xd000) return \"Infinity\";\n if (sign === 0xf000) return \"-Infinity\";\n // Integer part: digit groups from `weight` down to 0 (missing groups are zero)\n let integer = \"\";\n for (let w = weight, i = 0; w >= 0; w--, i++) {\n const group = i < nDigits ? chunk.readUInt16BE(start + 8 + i * 2) : 0;\n integer += integer === \"\" ? String(group) : String(group).padStart(4, \"0\");\n }\n if (integer === \"\") integer = \"0\";\n if (dscale === 0) return sign === 0x4000 ? `-${integer}` : integer;\n // Fraction part: the group at weight -k is digits[weight + k]; pad/trim to exactly `dscale` digits\n let fraction = \"\";\n for (let k = 1; fraction.length < dscale; k++) {\n const i = weight + k;\n const group = i >= 0 && i < nDigits ? chunk.readUInt16BE(start + 8 + i * 2) : 0;\n fraction += String(group).padStart(4, \"0\");\n }\n fraction = fraction.slice(0, dscale);\n return `${sign === 0x4000 ? \"-\" : \"\"}${integer}.${fraction}`;\n}\n\n/** Renders a binary tsvector (lexeme cstrings + position/weight words) to pg's text form, i.e. `'new':2A`. */\nfunction renderTsVector(chunk: Buffer, start: number): string {\n const count = chunk.readInt32BE(start);\n let pos = start + 4;\n const lexemes: string[] = [];\n for (let i = 0; i < count; i++) {\n const end = chunk.indexOf(0, pos);\n // pg's output doubles both backslashes and quotes inside lexemes\n const word = chunk.toString(\"utf8\", pos, end).replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"''\");\n pos = end + 1;\n const nPositions = chunk.readUInt16BE(pos);\n pos += 2;\n const positions: string[] = [];\n for (let p = 0; p < nPositions; p++) {\n // Each word entry packs the weight in the top 2 bits (3=A, 2=B, 1=C, 0=D/default)\n const entry = chunk.readUInt16BE(pos);\n pos += 2;\n positions.push(`${entry & 0x3fff}${weightSuffixes[entry >> 14]}`);\n }\n lexemes.push(positions.length > 0 ? `'${word}':${positions.join(\",\")}` : `'${word}'`);\n }\n return lexemes.join(\" \");\n}\n\nconst weightSuffixes = [\"\", \"C\", \"B\", \"A\"];\n\n/** Renders a binary range (flags byte + length-prefixed bounds) to pg's text form, i.e. `[\"a\",\"b\")`. */\nfunction renderRange(chunk: Buffer, start: number, bound: (c: Buffer, s: number) => string): string {\n const flags = chunk[start];\n if (flags & 0x01) return \"empty\";\n let pos = start + 1;\n let lower = \"\";\n let upper = \"\";\n if (!(flags & 0x08)) {\n const len = chunk.readInt32BE(pos);\n lower = bound(chunk, pos + 4);\n pos += 4 + len;\n }\n if (!(flags & 0x10)) {\n upper = bound(chunk, pos + 4);\n }\n return `${flags & 0x02 ? \"[\" : \"(\"}${lower},${upper}${flags & 0x04 ? \"]\" : \")\"}`;\n}\n\n/** Renders days-since-1970 as pg's date text, i.e. `2020-01-02` or `0001-01-01 BC`. */\nfunction renderDate(epochDays: number): string {\n const { text, bc } = renderDatePart(epochDays);\n return bc ? `${text} BC` : text;\n}\n\n/**\n * Renders the `YYYY-MM-DD` part, converting astronomical years to pg's BC numbering\n * (astronomical year 0 = `0001 BC`); timestamps append the ` BC` marker after the time/zone.\n */\nfunction renderDatePart(epochDays: number): { text: string; bc: boolean } {\n const [year, month, day] = civilFromDays(epochDays);\n const bc = year <= 0;\n const displayYear = bc ? 1 - year : year;\n return {\n text: `${String(displayYear).padStart(4, \"0\")}-${String(month).padStart(2, \"0\")}-${String(day).padStart(2, \"0\")}`,\n bc,\n };\n}\n\n/** Renders a binary timestamp (µs since 2000-01-01) to pg's text form, i.e. `2020-01-02 03:04:05.678+00`. */\nfunction renderTimestamp(pgMicros: bigint, suffix: string): string {\n if (pgMicros === INFINITY_US) return \"infinity\";\n if (pgMicros === NEG_INFINITY_US) return \"-infinity\";\n const { days, us } = splitPgMicros(pgMicros);\n const { text: date, bc } = renderDatePart(days);\n return `${date} ${renderTimeOfDay(us)}${suffix}${bc ? \" BC\" : \"\"}`;\n}\n\n/** Renders µs-since-midnight to pg's time text, i.e. `03:04:05.678` with trailing zeros trimmed. */\nfunction renderTimeOfDay(us: number): string {\n const seconds = Math.floor(us / 1_000_000);\n const hh = String(Math.floor(seconds / 3600)).padStart(2, \"0\");\n const mm = String(Math.floor((seconds / 60) % 60)).padStart(2, \"0\");\n const ss = String(seconds % 60).padStart(2, \"0\");\n // pg renders up to 6 fractional digits with trailing zeros trimmed, and no \".\" when zero\n let fraction = \"\";\n const usPart = us % 1_000_000;\n if (usPart > 0) fraction = `.${String(usPart).padStart(6, \"0\")}`.replace(/0+$/, \"\");\n return `${hh}:${mm}:${ss}${fraction}`;\n}\n\n/** Converts days-since-1970 to a civil [year, month, day], i.e. Howard Hinnant's algorithm. */\nfunction civilFromDays(epochDays: number): [number, number, number] {\n const z = epochDays + 719_468;\n const era = Math.floor(z / 146_097);\n const doe = z - era * 146_097;\n const yoe = Math.floor((doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365);\n const y = yoe + era * 400;\n const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100));\n const mp = Math.floor((5 * doy + 2) / 153);\n const d = doy - Math.floor((153 * mp + 2) / 5) + 1;\n const m = mp < 10 ? mp + 3 : mp - 9;\n return [m <= 2 ? y + 1 : y, m, d];\n}\n\n/** Throws an `Error` with `message`. */\nfunction fail(message: string): never {\n throw new Error(message);\n}\n"],"mappings":"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"}
|