joist-orm 2.4.0-next.40 → 2.4.0-next.41

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.
@@ -33,23 +33,24 @@ function getBinaryTypeParser(oid) {
33
33
  return parsers.get(oid);
34
34
  }
35
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.
36
+ * Auto-registers binary parsers for the database's dynamic-oid types — native enums, citext,
37
+ * text-like domains, and pgvector's `vector` — plus their array types, so apps get those for free.
38
38
  *
39
39
  * `PostgresDriver` calls this lazily before its first lazy query; apps can also call it
40
40
  * directly (i.e. at boot) if they want the registrations eagerly. Explicit
41
41
  * `setBinaryTypeParser` registrations are never overwritten.
42
42
  */
43
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
44
+ const [{ rows: settings }, { rows }] = await Promise.all([pool.query(`select current_setting('TimeZone') as tz`), pool.query(`select t.oid, t.typarray, t.typname
45
45
  from pg_type t
46
46
  where t.typtype = 'e'
47
47
  or t.typname = 'citext'
48
+ or t.typname = 'vector'
48
49
  or (t.typtype = 'd' and (select b.typcategory from pg_type b where b.oid = t.typbasetype) = 'S')`)]);
49
50
  setSessionTimeZone(settings[0].tz);
50
51
  for (const row of rows) {
51
52
  const oid = Number(row.oid);
52
- if (getBinaryTypeParser(oid) === void 0) setBinaryTypeParser(oid, binaryTextParser);
53
+ if (getBinaryTypeParser(oid) === void 0) setBinaryTypeParser(oid, row.typname === "vector" ? binaryVectorParser : binaryTextParser);
53
54
  const arrayOid = Number(row.typarray);
54
55
  if (arrayOid !== 0 && getBinaryTypeParser(arrayOid) === void 0) setBinaryTypeParser(arrayOid, binaryArrayParser);
55
56
  }
@@ -276,6 +277,18 @@ function readFloat4(chunk, start) {
276
277
  }
277
278
  return value;
278
279
  }
280
+ /**
281
+ * Decodes a binary pgvector cell (`int16 dim`, `int16 unused`, then `dim` float4s) to a `number[]`.
282
+ *
283
+ * Unlike other parsers this skips text parity (`VectorSerde` parses the text literal) to avoid
284
+ * rendering and re-parsing a potentially large string; `VectorSerde` accepts either shape.
285
+ */
286
+ function binaryVectorParser(chunk, start) {
287
+ const dim = chunk.readInt16BE(start);
288
+ const values = new Array(dim);
289
+ for (let i = 0; i < dim; i++) values[i] = readFloat4(chunk, start + 4 + i * 4);
290
+ return values;
291
+ }
279
292
  /** Copies the exact cell bytes, i.e. for bytea values. */
280
293
  function copyBytes(chunk, start, length) {
281
294
  const cell = Buffer.allocUnsafe(length);
@@ -1 +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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"}
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 dynamic-oid types — native enums, citext,\n * text-like domains, and pgvector's `vector` — 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, t.typname\n from pg_type t\n where t.typtype = 'e'\n or t.typname = 'citext'\n or t.typname = 'vector'\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) {\n setBinaryTypeParser(oid, row.typname === \"vector\" ? binaryVectorParser : binaryTextParser);\n }\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/**\n * Decodes a binary pgvector cell (`int16 dim`, `int16 unused`, then `dim` float4s) to a `number[]`.\n *\n * Unlike other parsers this skips text parity (`VectorSerde` parses the text literal) to avoid\n * rendering and re-parsing a potentially large string; `VectorSerde` accepts either shape.\n */\nfunction binaryVectorParser(chunk: Buffer, start: number): number[] {\n const dim = chunk.readInt16BE(start);\n const values = new Array<number>(dim);\n for (let i = 0; i < dim; i++) values[i] = readFloat4(chunk, start + 4 + i * 4);\n return values;\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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"}
@@ -29,8 +29,8 @@ export declare function getBinaryTypeParser(oid: number): BinaryParse | undefine
29
29
  /** Decodes one binary cell directly from the payload chunk; `length` is the cell's byte length. */
30
30
  export type BinaryParse = (chunk: Buffer, start: number, length: number) => any;
31
31
  /**
32
- * Auto-registers binary parsers for the database's text-like dynamic-oid types — native enums
33
- * and citext, plus their array types — so apps get those for free.
32
+ * Auto-registers binary parsers for the database's dynamic-oid types — native enums, citext,
33
+ * text-like domains, and pgvector's `vector` — plus their array types, so apps get those for free.
34
34
  *
35
35
  * `PostgresDriver` calls this lazily before its first lazy query; apps can also call it
36
36
  * directly (i.e. at boot) if they want the registrations eagerly. Explicit
@@ -1 +1 @@
1
- {"version":3,"file":"binaryParsers.d.cts","names":[],"sources":["../../src/drivers/binaryParsers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;wBA0BgB,oBAAoB,aAAa,OAAO;;wBAKxC,oBAAoB,cAAc;;YAKtC,eAAe,OAAO,QAAQ,eAAe;;;;;;;;;wBAUnC,8BAA8B;EAClD,MAAM,cAAc;IAAU;;IAC5B;;;;;;wBA6BY,mBAAmB;;wBAOnB,iBAAiB,OAAO,QAAQ,eAAe;;;;;;;;;wBAY/C,kBAAkB,OAAO,QAAQ,eAAe;;wBAgChD,iBAAiB,OAAO,QAAQ;;wBAYhC,sBAAsB,OAAO,QAAQ;;wBAqBrC,wBAAwB,OAAO,QAAQ;;;;;;;;;;;wBAoBvC"}
1
+ {"version":3,"file":"binaryParsers.d.cts","names":[],"sources":["../../src/drivers/binaryParsers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;wBA0BgB,oBAAoB,aAAa,OAAO;;wBAKxC,oBAAoB,cAAc;;YAKtC,eAAe,OAAO,QAAQ,eAAe;;;;;;;;;wBAUnC,8BAA8B;EAClD,MAAM,cAAc;IAAU;;IAC5B;;;;;;wBAgCY,mBAAmB;;wBAOnB,iBAAiB,OAAO,QAAQ,eAAe;;;;;;;;;wBAY/C,kBAAkB,OAAO,QAAQ,eAAe;;wBAgChD,iBAAiB,OAAO,QAAQ;;wBAYhC,sBAAsB,OAAO,QAAQ;;wBAqBrC,wBAAwB,OAAO,QAAQ;;;;;;;;;;;wBAoBvC"}
@@ -29,8 +29,8 @@ export declare function getBinaryTypeParser(oid: number): BinaryParse | undefine
29
29
  /** Decodes one binary cell directly from the payload chunk; `length` is the cell's byte length. */
30
30
  export type BinaryParse = (chunk: Buffer, start: number, length: number) => any;
31
31
  /**
32
- * Auto-registers binary parsers for the database's text-like dynamic-oid types — native enums
33
- * and citext, plus their array types — so apps get those for free.
32
+ * Auto-registers binary parsers for the database's dynamic-oid types — native enums, citext,
33
+ * text-like domains, and pgvector's `vector` — plus their array types, so apps get those for free.
34
34
  *
35
35
  * `PostgresDriver` calls this lazily before its first lazy query; apps can also call it
36
36
  * directly (i.e. at boot) if they want the registrations eagerly. Explicit
@@ -1 +1 @@
1
- {"version":3,"file":"binaryParsers.d.mts","names":[],"sources":["../../src/drivers/binaryParsers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;wBA0BgB,oBAAoB,aAAa,OAAO;;wBAKxC,oBAAoB,cAAc;;YAKtC,eAAe,OAAO,QAAQ,eAAe;;;;;;;;;wBAUnC,8BAA8B;EAClD,MAAM,cAAc;IAAU;;IAC5B;;;;;;wBA6BY,mBAAmB;;wBAOnB,iBAAiB,OAAO,QAAQ,eAAe;;;;;;;;;wBAY/C,kBAAkB,OAAO,QAAQ,eAAe;;wBAgChD,iBAAiB,OAAO,QAAQ;;wBAYhC,sBAAsB,OAAO,QAAQ;;wBAqBrC,wBAAwB,OAAO,QAAQ;;;;;;;;;;;wBAoBvC"}
1
+ {"version":3,"file":"binaryParsers.d.mts","names":[],"sources":["../../src/drivers/binaryParsers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;wBA0BgB,oBAAoB,aAAa,OAAO;;wBAKxC,oBAAoB,cAAc;;YAKtC,eAAe,OAAO,QAAQ,eAAe;;;;;;;;;wBAUnC,8BAA8B;EAClD,MAAM,cAAc;IAAU;;IAC5B;;;;;;wBAgCY,mBAAmB;;wBAOnB,iBAAiB,OAAO,QAAQ,eAAe;;;;;;;;;wBAY/C,kBAAkB,OAAO,QAAQ,eAAe;;wBAgChD,iBAAiB,OAAO,QAAQ;;wBAYhC,sBAAsB,OAAO,QAAQ;;wBAqBrC,wBAAwB,OAAO,QAAQ;;;;;;;;;;;wBAoBvC"}
@@ -32,23 +32,24 @@ function getBinaryTypeParser(oid) {
32
32
  return parsers.get(oid);
33
33
  }
34
34
  /**
35
- * Auto-registers binary parsers for the database's text-like dynamic-oid types — native enums
36
- * and citext, plus their array types — so apps get those for free.
35
+ * Auto-registers binary parsers for the database's dynamic-oid types — native enums, citext,
36
+ * text-like domains, and pgvector's `vector` — plus their array types, so apps get those for free.
37
37
  *
38
38
  * `PostgresDriver` calls this lazily before its first lazy query; apps can also call it
39
39
  * directly (i.e. at boot) if they want the registrations eagerly. Explicit
40
40
  * `setBinaryTypeParser` registrations are never overwritten.
41
41
  */
42
42
  async function registerDatabaseBinaryParsers(pool) {
43
- const [{ rows: settings }, { rows }] = await Promise.all([pool.query(`select current_setting('TimeZone') as tz`), pool.query(`select t.oid, t.typarray
43
+ const [{ rows: settings }, { rows }] = await Promise.all([pool.query(`select current_setting('TimeZone') as tz`), pool.query(`select t.oid, t.typarray, t.typname
44
44
  from pg_type t
45
45
  where t.typtype = 'e'
46
46
  or t.typname = 'citext'
47
+ or t.typname = 'vector'
47
48
  or (t.typtype = 'd' and (select b.typcategory from pg_type b where b.oid = t.typbasetype) = 'S')`)]);
48
49
  setSessionTimeZone(settings[0].tz);
49
50
  for (const row of rows) {
50
51
  const oid = Number(row.oid);
51
- if (getBinaryTypeParser(oid) === void 0) setBinaryTypeParser(oid, binaryTextParser);
52
+ if (getBinaryTypeParser(oid) === void 0) setBinaryTypeParser(oid, row.typname === "vector" ? binaryVectorParser : binaryTextParser);
52
53
  const arrayOid = Number(row.typarray);
53
54
  if (arrayOid !== 0 && getBinaryTypeParser(arrayOid) === void 0) setBinaryTypeParser(arrayOid, binaryArrayParser);
54
55
  }
@@ -275,6 +276,18 @@ function readFloat4(chunk, start) {
275
276
  }
276
277
  return value;
277
278
  }
279
+ /**
280
+ * Decodes a binary pgvector cell (`int16 dim`, `int16 unused`, then `dim` float4s) to a `number[]`.
281
+ *
282
+ * Unlike other parsers this skips text parity (`VectorSerde` parses the text literal) to avoid
283
+ * rendering and re-parsing a potentially large string; `VectorSerde` accepts either shape.
284
+ */
285
+ function binaryVectorParser(chunk, start) {
286
+ const dim = chunk.readInt16BE(start);
287
+ const values = new Array(dim);
288
+ for (let i = 0; i < dim; i++) values[i] = readFloat4(chunk, start + 4 + i * 4);
289
+ return values;
290
+ }
278
291
  /** Copies the exact cell bytes, i.e. for bytea values. */
279
292
  function copyBytes(chunk, start, length) {
280
293
  const cell = Buffer.allocUnsafe(length);
@@ -1 +1 @@
1
- {"version":3,"file":"binaryParsers.js","names":["fail"],"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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"}
1
+ {"version":3,"file":"binaryParsers.js","names":["fail"],"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 dynamic-oid types — native enums, citext,\n * text-like domains, and pgvector's `vector` — 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, t.typname\n from pg_type t\n where t.typtype = 'e'\n or t.typname = 'citext'\n or t.typname = 'vector'\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) {\n setBinaryTypeParser(oid, row.typname === \"vector\" ? binaryVectorParser : binaryTextParser);\n }\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/**\n * Decodes a binary pgvector cell (`int16 dim`, `int16 unused`, then `dim` float4s) to a `number[]`.\n *\n * Unlike other parsers this skips text parity (`VectorSerde` parses the text literal) to avoid\n * rendering and re-parsing a potentially large string; `VectorSerde` accepts either shape.\n */\nfunction binaryVectorParser(chunk: Buffer, start: number): number[] {\n const dim = chunk.readInt16BE(start);\n const values = new Array<number>(dim);\n for (let i = 0; i < dim; i++) values[i] = readFloat4(chunk, start + 4 + i * 4);\n return values;\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joist-orm",
3
- "version": "2.4.0-next.40",
3
+ "version": "2.4.0-next.41",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -201,14 +201,14 @@
201
201
  "build"
202
202
  ],
203
203
  "dependencies": {
204
- "joist-codegen": "2.4.0-next.40",
205
- "joist-core": "2.4.0-next.40",
206
- "joist-graphql-codegen": "2.4.0-next.40",
207
- "joist-graphql-resolver-utils": "2.4.0-next.40",
208
- "joist-knex": "2.4.0-next.40",
209
- "joist-migration-utils": "2.4.0-next.40",
210
- "joist-test-utils": "2.4.0-next.40",
211
- "joist-utils": "2.4.0-next.40"
204
+ "joist-codegen": "2.4.0-next.41",
205
+ "joist-core": "2.4.0-next.41",
206
+ "joist-graphql-codegen": "2.4.0-next.41",
207
+ "joist-graphql-resolver-utils": "2.4.0-next.41",
208
+ "joist-knex": "2.4.0-next.41",
209
+ "joist-migration-utils": "2.4.0-next.41",
210
+ "joist-test-utils": "2.4.0-next.41",
211
+ "joist-utils": "2.4.0-next.41"
212
212
  },
213
213
  "peerDependencies": {
214
214
  "knex": "^3.1.0",