@crvouga/postgres-mem 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ /** Btree / hash index over row indices. Keys are pre-serialized (datumKey tuples). */
2
+ export declare class IndexStore {
3
+ readonly name: string;
4
+ readonly unique: boolean;
5
+ private entries;
6
+ constructor(name: string, unique?: boolean);
7
+ get size(): number;
8
+ checkUnique(key: string, rowIdx?: number): void;
9
+ insert(key: string, rowIdx: number): void;
10
+ remove(key: string, rowIdx: number): void;
11
+ lookup(key: string): readonly number[];
12
+ clear(): void;
13
+ clone(): IndexStore;
14
+ }
@@ -0,0 +1,11 @@
1
+ import { type UniqueSpec } from "../constraints/enforce.js";
2
+ import type { ExecEnv } from "../executor/relation.js";
3
+ import type { TableData } from "../storage/database-state.js";
4
+ import type { Datum } from "../types/value.js";
5
+ import { IndexStore } from "./index.js";
6
+ export declare function invalidateTableIndexes(table: TableData): void;
7
+ export declare function indexStoreFor(env: ExecEnv, table: TableData, spec: UniqueSpec): IndexStore;
8
+ export declare function indexInsertRow(env: ExecEnv, table: TableData, rowIdx: number, row: Datum[]): void;
9
+ export declare function indexRemoveRow(env: ExecEnv, table: TableData, rowIdx: number, row: Datum[]): void;
10
+ export declare function indexUpdateRow(env: ExecEnv, table: TableData, rowIdx: number, oldRow: Datum[], newRow: Datum[]): void;
11
+ export declare function rebuildTableIndexes(env: ExecEnv, table: TableData): void;
@@ -20,6 +20,8 @@ export declare class Parser {
20
20
  parseStatements(): Statement[];
21
21
  parseStatement(): Statement;
22
22
  private skipToStatementEnd;
23
+ /** Consume tokens until the matching `)` after an opening `(` already eaten. */
24
+ private skipBalancedCloseParen;
23
25
  private parseWithableStatement;
24
26
  private parseWithClause;
25
27
  parseSelectStmt(withClause?: WithClause | null): SelectStmt;
@@ -0,0 +1,15 @@
1
+ import type { Expr, FromItem } from "../ast/nodes.js";
2
+ import { type ExecEnv } from "../executor/relation.js";
3
+ import type { TableData } from "../storage/database-state.js";
4
+ import { type Datum, type TypeId } from "../types/value.js";
5
+ export interface ConstEquality {
6
+ column: string;
7
+ valueExpr: Expr;
8
+ }
9
+ export declare function equalityAgainstConst(expr: Expr): ConstEquality | null;
10
+ export declare function conjunctions(expr: Expr): Expr[];
11
+ /** Single-table PK / unique equality lookup: returns matching rows or null to scan. */
12
+ export declare function tryIndexedTableRows(env: ExecEnv, table: TableData, alias: string, where: Expr): Datum[][] | null;
13
+ export declare function tryIndexedFromItem(env: ExecEnv, item: FromItem, where: Expr | null): Datum[][] | null;
14
+ export declare function joinKeyFromRow(row: Datum[], colIdxs: number[], srcTypes: TypeId[], unifiedTypes: TypeId[], ctx: import("../expressions/context.js").EngineCtx): string | null;
15
+ export declare function rowsMatchEqKeys(ctx: import("../expressions/context.js").EngineCtx, left: Datum[], right: Datum[], leftIdxs: number[], rightIdxs: number[], leftTypes: TypeId[], rightTypes: TypeId[], unifiedTypes: TypeId[]): boolean;
@@ -0,0 +1,5 @@
1
+ /** Internal invariant failure — not a user SQL error. */
2
+ export declare function assert(condition: boolean, message: string): asserts condition;
3
+ export declare function assertDefined<T>(value: T | null | undefined, message: string): T;
4
+ export declare function assertBounds(value: number, min: number, max: number, label: string): void;
5
+ export declare function assertNever(value: never, message?: string): never;
@@ -1,3 +1,3 @@
1
1
  export { type Clock, DEFAULT_NOW, fixedClock, resolveClock, systemClock } from "./clock.js";
2
- export { type DatabaseOptions, DEFAULT_DATABASE_SEED, type RandomMode } from "./options.js";
2
+ export { type DatabaseOptions, DEFAULT_DATABASE_SEED, type Int8Mode, type RandomMode } from "./options.js";
3
3
  export { deriveSeed, OsEntropy, Prng } from "./prng.js";
@@ -1,6 +1,8 @@
1
1
  import type { Clock } from "./clock.js";
2
2
  /** Entropy source for `random()` / `gen_random_uuid()`. Default is seeded xorshift64*. */
3
3
  export type RandomMode = "deterministic" | "os";
4
+ /** How `int8` columns surface in query row objects. Default `"bigint"`. */
5
+ export type Int8Mode = "bigint" | "number" | "string";
4
6
  /** Options for {@link Database} construction. All fields are optional. */
5
7
  export interface DatabaseOptions {
6
8
  /**
@@ -20,6 +22,13 @@ export interface DatabaseOptions {
20
22
  * Pass a `Date`, `() => Date`, or `"system"` for wall-clock `now()` like PostgreSQL.
21
23
  */
22
24
  now?: Date | Clock | "system";
25
+ /**
26
+ * How `int8` / `bigint` columns surface in query row objects.
27
+ * Default `"bigint"` matches PostgreSQL's JS-unsafe 64-bit integers.
28
+ * `"number"` uses IEEE number (unsafe beyond `Number.MAX_SAFE_INTEGER`).
29
+ * `"string"` is JSON-safe.
30
+ */
31
+ int8?: Int8Mode;
23
32
  }
24
33
  /** Default {@link DatabaseOptions.seed} when constructing a {@link Database}. */
25
34
  export declare const DEFAULT_DATABASE_SEED = 1;
@@ -1,29 +1,22 @@
1
1
  import type { Clock } from "../runtime/clock.js";
2
2
  import type { Prng } from "../runtime/prng.js";
3
3
  import { DatabaseState } from "../storage/database-state.js";
4
- /** PRNG + clock captured alongside catalog/rows in a snapshot. */
4
+ /** PRNG + clock captured alongside catalog/rows. */
5
5
  export interface SnapshotRuntime {
6
- /** Unsigned 64-bit {@link Prng} state. */
7
6
  prngState: bigint;
8
- /** Clock instant as milliseconds since Unix epoch. */
9
7
  nowMs: number;
10
8
  }
11
9
  /** Result of {@link decodeDatabaseState}. */
12
10
  export interface DecodedSnapshot {
13
- /** Restored catalog and table data. */
14
11
  state: DatabaseState;
15
12
  runtime: SnapshotRuntime | null;
16
13
  }
17
14
  /**
18
15
  * Encode catalog, rows, and runtime into a postgres-mem `PGMM` snapshot blob
19
16
  * (not an on-disk PostgreSQL format).
20
- *
21
- * Prefer {@link Database.snapshot} unless you are serializing engine state directly.
22
17
  */
23
18
  export declare function encodeDatabaseState(state: DatabaseState, runtime: SnapshotRuntime): Uint8Array;
24
19
  /**
25
20
  * Decode a blob from {@link encodeDatabaseState} / {@link Database.snapshot}.
26
- *
27
- * @throws {PostgresError} If the magic, version, or payload is invalid.
28
21
  */
29
22
  export declare function decodeDatabaseState(snapshot: Uint8Array, prng: Prng, clock: Clock): DecodedSnapshot;
@@ -0,0 +1,63 @@
1
+ export declare function utf8Encode(s: string): Uint8Array;
2
+ export declare function utf8Decode(b: Uint8Array): string;
3
+ export declare function writeVarintU32(w: Writer, value: number): void;
4
+ export declare function readVarintU32(r: Reader): number;
5
+ export declare class Writer {
6
+ private buf;
7
+ private view;
8
+ private len;
9
+ constructor(capacity?: number);
10
+ get position(): number;
11
+ reserve(capacity: number): void;
12
+ private ensure;
13
+ align4(): void;
14
+ u8(value: number): void;
15
+ u32(value: number): void;
16
+ i32(value: number): void;
17
+ u64(value: bigint): void;
18
+ i64(value: bigint): void;
19
+ f64(value: number): void;
20
+ raw(value: Uint8Array): void;
21
+ /** Length-prefixed UTF-8. */
22
+ text(value: string): void;
23
+ /** Write UTF-8 at current position without length prefix (intern blob region). */
24
+ textBytes(value: string): void;
25
+ finish(): Uint8Array;
26
+ fail(): never;
27
+ }
28
+ export declare class Reader {
29
+ private readonly bytes;
30
+ private offset;
31
+ private readonly view;
32
+ constructor(bytes: Uint8Array);
33
+ get position(): number;
34
+ skipAlign4(): void;
35
+ u8(): number;
36
+ u32(): number;
37
+ i32(): number;
38
+ u64(): bigint;
39
+ i64(): bigint;
40
+ f64(): number;
41
+ raw(length: number): Uint8Array;
42
+ text(): string;
43
+ remaining(): number;
44
+ done(): boolean;
45
+ fail(): never;
46
+ }
47
+ export declare function writeBjv(w: Writer, value: unknown, forceIntern: (s: string) => number): void;
48
+ export declare function readBjv(r: Reader, intern: readonly string[]): unknown;
49
+ export declare class InternPool {
50
+ private readonly counts;
51
+ private readonly ids;
52
+ readonly list: string[];
53
+ constructor();
54
+ count(s: string): void;
55
+ /** Assign ids only to strings seen ≥2 times (plus empty string). */
56
+ finalize(): void;
57
+ /** Always intern (schema / catalog strings). */
58
+ forceId(s: string): number;
59
+ id(s: string): number;
60
+ }
61
+ /** Write intern table: count, offsets[], concatenated UTF-8 blob. */
62
+ export declare function writeInternTable(w: Writer, strings: readonly string[]): void;
63
+ export declare function readInternTable(r: Reader): string[];
@@ -0,0 +1,37 @@
1
+ import type { Datum } from "../types/value.js";
2
+ /** Column pack tags (PGMM v3). */
3
+ export declare const PACK_NULL = 0;
4
+ export declare const PACK_BOOL = 1;
5
+ export declare const PACK_FLOAT = 2;
6
+ export declare const PACK_INT = 3;
7
+ export declare const PACK_TEXT_INTERN = 4;
8
+ export declare const PACK_TEXT_INLINE = 5;
9
+ export declare const PACK_BLOB = 6;
10
+ export declare const PACK_TAGGED = 7;
11
+ export interface SlabColumn {
12
+ pack: number;
13
+ nullBitmap: Uint8Array | null;
14
+ /** Prefix sum of non-null rows for O(1) null-index lookup. */
15
+ nonNullPrefix?: Uint32Array;
16
+ /** Typed payload or inline blob region inside `buffer`. */
17
+ payload: Uint8Array;
18
+ /** For PACK_TEXT_INLINE: u32 offsets into payload per row. */
19
+ inlineOffsets?: Uint32Array;
20
+ /** For PACK_TAGGED: decoded values per non-null row in order. */
21
+ tagged?: Datum[];
22
+ /** For PACK_BLOB: one entry per non-null row (zero-copy views). */
23
+ blobChunks?: Uint8Array[];
24
+ }
25
+ /** Frozen columnar row storage; zero-copy views into snapshot buffer. */
26
+ export declare class ColumnarSlab {
27
+ readonly buffer: Uint8Array;
28
+ readonly rowCount: number;
29
+ readonly columns: SlabColumn[];
30
+ private readonly intern;
31
+ constructor(buffer: Uint8Array, rowCount: number, columns: SlabColumn[], intern: readonly string[]);
32
+ cell(rowIndex: number, col: number): Datum;
33
+ rowAt(rowIndex: number): Datum[];
34
+ scan(): Generator<Datum[]>;
35
+ materialize(): Datum[][];
36
+ }
37
+ export declare function packKindOf(value: Datum): number;
@@ -1,6 +1,7 @@
1
1
  import type { CreateTriggerStmt, Expr, SelectStmt, Statement } from "../ast/nodes.js";
2
2
  import type { Clock } from "../runtime/clock.js";
3
3
  import type { Prng } from "../runtime/prng.js";
4
+ import type { ColumnarSlab } from "./columnar-slab.js";
4
5
  import { type ColumnType, type Datum, type TypeId } from "../types/value.js";
5
6
  export interface ColumnMeta {
6
7
  name: string;
@@ -72,14 +73,33 @@ export declare class TableData {
72
73
  schema: string;
73
74
  columns: ColumnMeta[];
74
75
  rows: Datum[][];
76
+ /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
77
+ slab: ColumnarSlab | null;
75
78
  constraints: ConstraintMeta[];
76
79
  triggers: TriggerMeta[];
77
80
  temp: boolean;
78
81
  /** monotonically increasing oid-like id for catalog output */
79
82
  readonly oid: number;
83
+ /** >0 while shared with a clone or transaction snapshot. */
84
+ shareCount: number;
85
+ /** Derived unique/btree index maps; null until built or invalidated. */
86
+ indexStores: Map<string, import("../indexes/index.js").IndexStore> | null;
80
87
  constructor(schema: string, name: string, columns: ColumnMeta[], oid: number, temp?: boolean);
88
+ rowCount(): number;
89
+ rowAt(index: number): Datum[];
90
+ /** All rows for scans; materializes slab once into `rows` when needed. */
91
+ allRows(): Datum[][];
92
+ attachSlab(slab: ColumnarSlab): void;
93
+ materializeSlab(): void;
94
+ /** Writable row storage; materializes slab if needed. */
95
+ mutableRows(): Datum[][];
96
+ get frozen(): boolean;
97
+ freeze(): void;
98
+ thaw(): void;
81
99
  columnIndex(name: string): number;
82
100
  clone(): TableData;
101
+ /** Independent writable copy (row tuples copied so ALTER COLUMN is isolated). */
102
+ cloneForWrite(): TableData;
83
103
  }
84
104
  export interface ViewData {
85
105
  name: string;
@@ -95,6 +115,7 @@ export interface ViewData {
95
115
  }> | null;
96
116
  temp: boolean;
97
117
  oid: number;
118
+ shareCount?: number;
98
119
  }
99
120
  export interface SequenceData {
100
121
  name: string;
@@ -114,12 +135,14 @@ export interface SequenceData {
114
135
  dataType: TypeId;
115
136
  temp: boolean;
116
137
  oid: number;
138
+ shareCount?: number;
117
139
  }
118
140
  export interface EnumData {
119
141
  name: string;
120
142
  schema: string;
121
143
  labels: string[];
122
144
  oid: number;
145
+ shareCount?: number;
123
146
  }
124
147
  export interface DomainData {
125
148
  name: string;
@@ -132,6 +155,7 @@ export interface DomainData {
132
155
  expr: Expr;
133
156
  }>;
134
157
  oid: number;
158
+ shareCount?: number;
135
159
  }
136
160
  export interface FunctionData {
137
161
  name: string;
@@ -150,6 +174,7 @@ export interface FunctionData {
150
174
  rawBody: string | null;
151
175
  strict: boolean;
152
176
  oid: number;
177
+ jsImpl?: (...args: Array<null | boolean | number | bigint | string | Uint8Array>) => null | boolean | number | bigint | string | Uint8Array;
153
178
  }
154
179
  export declare class SchemaData {
155
180
  name: string;
@@ -165,6 +190,8 @@ export declare class SchemaData {
165
190
  /** all relation names (tables, views, sequences, indexes share pg_class namespace) */
166
191
  hasRelation(name: string): boolean;
167
192
  clone(): SchemaData;
193
+ /** Share table/sequence objects; copy maps so CREATE/DROP is isolated. */
194
+ cloneShallow(): SchemaData;
168
195
  }
169
196
  export interface PreparedStatement {
170
197
  name: string;
@@ -209,8 +236,16 @@ export declare class DatabaseState {
209
236
  findEnumByKey(key: string): EnumData | null;
210
237
  /** format_type()-style display name for a type OID (builtin or enum). */
211
238
  typeNameForOid(oid: number): string | null;
212
- /** deep clone for transaction snapshots (datums are immutable; rows copied) */
239
+ /** deep clone (datums are immutable; rows copied) */
213
240
  clone(): DatabaseState;
241
+ /** Share frozen catalog objects; copy maps so CREATE/DROP is isolated. */
242
+ cloneShallow(): DatabaseState;
243
+ freezeShared(): void;
244
+ thawShared(): void;
245
+ ensureWritableTable(table: TableData): TableData;
246
+ ensureWritableSequence(seq: SequenceData): SequenceData;
247
+ ensureWritableView(view: ViewData): ViewData;
248
+ ensureWritableEnum(en: EnumData): EnumData;
214
249
  /** copy the contents of `other` into this state (rollback restore) */
215
250
  restoreFrom(other: DatabaseState): void;
216
251
  }
@@ -1,18 +1,19 @@
1
1
  import type { DatabaseState } from "../storage/database-state.js";
2
2
  /**
3
- * Single-session transaction manager: BEGIN clones the whole state (datums are
4
- * immutable; rows are copied), ROLLBACK restores it. Savepoints stack inner
5
- * snapshots. The PRNG state participates so `random()` draws rewind on
6
- * rollback (determinism invariant, mirrors sqlite-mem).
3
+ * Single-session transaction manager with copy-on-write snapshots: BEGIN /
4
+ * SAVEPOINT freeze shared catalog objects and capture a shallow clone; writes
5
+ * copy-on-write via ensureWritableTable. ROLLBACK restores the snapshot.
7
6
  */
8
7
  export declare class TransactionManager {
9
8
  private readonly state;
10
9
  private base;
11
10
  private savepoints;
11
+ private freezeDepth;
12
12
  constructor(state: DatabaseState);
13
13
  get inTransaction(): boolean;
14
14
  private takeSnapshot;
15
15
  private restore;
16
+ private thawOnce;
16
17
  begin(): void;
17
18
  commit(): void;
18
19
  rollback(): void;
@@ -20,6 +21,5 @@ export declare class TransactionManager {
20
21
  releaseSavepoint(name: string): void;
21
22
  rollbackToSavepoint(name: string): void;
22
23
  private findSavepoint;
23
- /** abort any open transaction without restoring (used by Database.close) */
24
24
  reset(): void;
25
25
  }
@@ -0,0 +1,16 @@
1
+ import type { JsonbValue } from "./jsonb.js";
2
+ type PathStep = {
3
+ kind: "member";
4
+ name: string;
5
+ } | {
6
+ kind: "index";
7
+ index: number;
8
+ };
9
+ /** Parse a SQL/JSON path subset: `$`, `.key`, `."key"`, `[n]`. */
10
+ export declare function parseJsonpath(text: string): PathStep[];
11
+ /**
12
+ * First match of a jsonpath against a jsonb document.
13
+ * Missing path → SQL NULL (`null` return). JSON null is `{ j: "null" }`.
14
+ */
15
+ export declare function jsonpathQueryFirst(doc: JsonbValue, pathText: string): JsonbValue | null;
16
+ export {};