@crvouga/mockingbird-service-postgres 1.5.1 → 1.6.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,4 @@
1
+ export type DatabaseCatalogContext = {
2
+ name: string;
3
+ names: () => readonly string[];
4
+ };
@@ -1,3 +1,4 @@
1
1
  import type { SelectStmt } from "../ast/nodes.js";
2
2
  /** Minimal SELECT deparsing for pg_get_viewdef / information_schema. */
3
3
  export declare function deparseSelect(stmt: SelectStmt): string;
4
+ export declare function quoteIdent(name: string): string;
package/dist/unstable.js CHANGED
@@ -6524,6 +6524,19 @@ function exactDegTan(x) {
6524
6524
  return Math.tan(x * Math.PI / 180);
6525
6525
  }
6526
6526
 
6527
+ // src/sql/deparse.ts
6528
+ function quoteIdent(name) {
6529
+ if (/^[a-z_][a-z0-9_$]*$/.test(name)) return name;
6530
+ return `"${name.replaceAll('"', '""')}"`;
6531
+ }
6532
+
6533
+ // src/runtime/database-context.ts
6534
+ var contexts = /* @__PURE__ */ new WeakMap();
6535
+ var fallback = { name: "postgres", names: () => ["postgres"] };
6536
+ function databaseCatalogContext(state) {
6537
+ return contexts.get(state) ?? fallback;
6538
+ }
6539
+
6527
6540
  // src/functions/misc-fns.ts
6528
6541
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
6529
6542
  function findSequenceForCall(ctx, name) {
@@ -6607,8 +6620,8 @@ function sequenceNextval(ctx, seq) {
6607
6620
  function getMiscFunctions() {
6608
6621
  const m = /* @__PURE__ */ new Map();
6609
6622
  m.set("version", () => tv("text", PG_VERSION_TEXT));
6610
- m.set("current_database", () => tv("name", "postgres"));
6611
- m.set("current_catalog", () => tv("name", "postgres"));
6623
+ m.set("current_database", (ctx) => tv("name", databaseCatalogContext(ctx.state).name));
6624
+ m.set("current_catalog", (ctx) => tv("name", databaseCatalogContext(ctx.state).name));
6612
6625
  m.set("current_schema", (ctx) => {
6613
6626
  const path = ctx.state.effectiveSearchPath();
6614
6627
  const first = path.find((s) => ctx.state.schemas.has(s));
@@ -6730,7 +6743,7 @@ function getMiscFunctions() {
6730
6743
  if (!col.identity) return tv("text", null);
6731
6744
  return tv(
6732
6745
  "text",
6733
- col.identity.sequence.split(".").map((p) => p).join(".")
6746
+ col.identity.sequence.split(".").map(quoteIdent).join(".")
6734
6747
  );
6735
6748
  })
6736
6749
  );
@@ -8989,7 +9002,8 @@ function pgSettings(ctx) {
8989
9002
  "pg_settings"
8990
9003
  );
8991
9004
  }
8992
- function pgDatabase() {
9005
+ function pgDatabase(ctx) {
9006
+ const names = databaseCatalogContext(ctx.state).names();
8993
9007
  return rel(
8994
9008
  [
8995
9009
  ["oid", "oid"],
@@ -8998,7 +9012,7 @@ function pgDatabase() {
8998
9012
  ["datistemplate", "bool"],
8999
9013
  ["datallowconn", "bool"]
9000
9014
  ],
9001
- [[5, "postgres", 6, false, true]],
9015
+ names.map((name, index) => [5 + index, name, 6, false, true]),
9002
9016
  "pg_database"
9003
9017
  );
9004
9018
  }
@@ -9033,13 +9047,14 @@ function pgTrigger(ctx) {
9033
9047
  "pg_trigger"
9034
9048
  );
9035
9049
  }
9036
- var CATALOG_NAME = "postgres";
9050
+ var catalogName = (state) => databaseCatalogContext(state).name;
9037
9051
  function infoSchemata(state) {
9052
+ const catalog = catalogName(state);
9038
9053
  const rows = [
9039
- [CATALOG_NAME, "pg_catalog", OWNER],
9040
- [CATALOG_NAME, "information_schema", OWNER]
9054
+ [catalog, "pg_catalog", OWNER],
9055
+ [catalog, "information_schema", OWNER]
9041
9056
  ];
9042
- for (const s of state.schemas.values()) rows.push([CATALOG_NAME, s.name, OWNER]);
9057
+ for (const s of state.schemas.values()) rows.push([catalog, s.name, OWNER]);
9043
9058
  return rel(
9044
9059
  [
9045
9060
  ["catalog_name", "name"],
@@ -9051,13 +9066,14 @@ function infoSchemata(state) {
9051
9066
  );
9052
9067
  }
9053
9068
  function infoTables(ctx) {
9069
+ const catalog = catalogName(ctx.state);
9054
9070
  const rows = [];
9055
9071
  for (const schema of ctx.state.schemas.values()) {
9056
9072
  for (const t of schema.tables.values()) {
9057
- rows.push([CATALOG_NAME, t.schema, t.name, t.temp ? "LOCAL TEMPORARY" : "BASE TABLE", "YES"]);
9073
+ rows.push([catalog, t.schema, t.name, t.temp ? "LOCAL TEMPORARY" : "BASE TABLE", "YES"]);
9058
9074
  }
9059
9075
  for (const v of schema.views.values()) {
9060
- if (!v.materialized) rows.push([CATALOG_NAME, v.schema, v.name, "VIEW", "NO"]);
9076
+ if (!v.materialized) rows.push([catalog, v.schema, v.name, "VIEW", "NO"]);
9061
9077
  }
9062
9078
  }
9063
9079
  return rel(
@@ -9073,6 +9089,7 @@ function infoTables(ctx) {
9073
9089
  );
9074
9090
  }
9075
9091
  function infoColumns(ctx) {
9092
+ const catalog = catalogName(ctx.state);
9076
9093
  const rows = [];
9077
9094
  for (const t of allTables(ctx.state)) {
9078
9095
  t.columns.forEach((c, i) => {
@@ -9083,7 +9100,7 @@ function infoColumns(ctx) {
9083
9100
  const dataType = isArrayType(id) ? "ARRAY" : isEnumType(id) ? "USER-DEFINED" : typeDisplayName(id);
9084
9101
  const udt = isArrayType(id) ? `_${arrayUdt(id)}` : isEnumType(id) ? id.slice(5).split(".").pop() : id;
9085
9102
  rows.push([
9086
- CATALOG_NAME,
9103
+ catalog,
9087
9104
  t.schema,
9088
9105
  t.name,
9089
9106
  c.name,
@@ -9128,10 +9145,11 @@ function arrayUdt(t) {
9128
9145
  return isEnumType(elem) ? elem.slice(5).split(".").pop() : elem;
9129
9146
  }
9130
9147
  function infoViews(ctx) {
9148
+ const catalog = catalogName(ctx.state);
9131
9149
  const rows = [];
9132
9150
  for (const schema of ctx.state.schemas.values()) {
9133
9151
  for (const v of schema.views.values()) {
9134
- if (!v.materialized) rows.push([CATALOG_NAME, v.schema, v.name, null]);
9152
+ if (!v.materialized) rows.push([catalog, v.schema, v.name, null]);
9135
9153
  }
9136
9154
  }
9137
9155
  return rel(
@@ -9146,10 +9164,11 @@ function infoViews(ctx) {
9146
9164
  );
9147
9165
  }
9148
9166
  function infoSequences(ctx) {
9167
+ const catalog = catalogName(ctx.state);
9149
9168
  const rows = [];
9150
9169
  for (const s of allSequences(ctx.state)) {
9151
9170
  rows.push([
9152
- CATALOG_NAME,
9171
+ catalog,
9153
9172
  s.schema,
9154
9173
  s.name,
9155
9174
  typeDisplayName(s.dataType),
@@ -9177,11 +9196,12 @@ function infoSequences(ctx) {
9177
9196
  );
9178
9197
  }
9179
9198
  function infoTableConstraints(ctx) {
9199
+ const catalog = catalogName(ctx.state);
9180
9200
  const rows = [];
9181
9201
  for (const t of allTables(ctx.state)) {
9182
9202
  for (const c of t.constraints) {
9183
9203
  const type = c.kind === "primary_key" ? "PRIMARY KEY" : c.kind === "unique" ? "UNIQUE" : c.kind === "check" ? "CHECK" : "FOREIGN KEY";
9184
- rows.push([CATALOG_NAME, t.schema, c.name, CATALOG_NAME, t.schema, t.name, type]);
9204
+ rows.push([catalog, t.schema, c.name, catalog, t.schema, t.name, type]);
9185
9205
  }
9186
9206
  }
9187
9207
  return rel(
@@ -9199,12 +9219,13 @@ function infoTableConstraints(ctx) {
9199
9219
  );
9200
9220
  }
9201
9221
  function infoKeyColumnUsage(ctx) {
9222
+ const catalog = catalogName(ctx.state);
9202
9223
  const rows = [];
9203
9224
  for (const t of allTables(ctx.state)) {
9204
9225
  for (const c of t.constraints) {
9205
9226
  if (c.kind !== "primary_key" && c.kind !== "unique" && c.kind !== "foreign_key") continue;
9206
9227
  c.columns.forEach((col, i) => {
9207
- rows.push([CATALOG_NAME, t.schema, c.name, CATALOG_NAME, t.schema, t.name, col, i + 1]);
9228
+ rows.push([catalog, t.schema, c.name, catalog, t.schema, t.name, col, i + 1]);
9208
9229
  });
9209
9230
  }
9210
9231
  }
@@ -9224,12 +9245,13 @@ function infoKeyColumnUsage(ctx) {
9224
9245
  );
9225
9246
  }
9226
9247
  function infoRoutines(ctx) {
9248
+ const catalog = catalogName(ctx.state);
9227
9249
  const rows = [];
9228
9250
  for (const schema of ctx.state.schemas.values()) {
9229
9251
  for (const fns of schema.functions.values()) {
9230
9252
  for (const f of fns) {
9231
9253
  rows.push([
9232
- CATALOG_NAME,
9254
+ catalog,
9233
9255
  f.schema,
9234
9256
  f.name,
9235
9257
  "FUNCTION",
@@ -9286,7 +9308,7 @@ function buildCatalogRelation(ctx, schema, name) {
9286
9308
  case "pg_settings":
9287
9309
  return pgSettings(ctx);
9288
9310
  case "pg_database":
9289
- return pgDatabase();
9311
+ return pgDatabase(ctx);
9290
9312
  case "pg_roles":
9291
9313
  case "pg_user":
9292
9314
  return pgRoles();
@@ -11438,14 +11460,19 @@ var Parser = class {
11438
11460
  parseIdentityOptions() {
11439
11461
  const options = {};
11440
11462
  if (this.eatPunct("(")) {
11441
- Object.assign(options, this.parseSequenceOptions());
11463
+ Object.assign(options, this.parseSequenceOptions(true));
11442
11464
  this.expectPunct(")");
11443
11465
  }
11444
11466
  return options;
11445
11467
  }
11446
- parseSequenceOptions() {
11468
+ parseSequenceOptions(identity = false) {
11447
11469
  const options = {};
11448
11470
  for (; ; ) {
11471
+ if (identity && this.eatKw("sequence")) {
11472
+ this.expectKw("name");
11473
+ options.sequenceName = this.qualifiedName();
11474
+ continue;
11475
+ }
11449
11476
  if (this.eatKw("increment")) {
11450
11477
  this.eatKw("by");
11451
11478
  options.increment = this.parseSignedBigInt();
@@ -20020,7 +20047,13 @@ var DatabaseState = class _DatabaseState {
20020
20047
  this.settings.set("lc_numeric", "C");
20021
20048
  this.settings.set("lc_time", "C");
20022
20049
  this.settings.set("default_transaction_isolation", "read committed");
20050
+ this.settings.set("lock_timeout", "0");
20051
+ this.settings.set("idle_in_transaction_session_timeout", "0");
20052
+ this.settings.set("transaction_timeout", "0");
20023
20053
  this.settings.set("statement_timeout", "0");
20054
+ this.settings.set("check_function_bodies", "on");
20055
+ this.settings.set("xmloption", "content");
20056
+ this.settings.set("row_security", "on");
20024
20057
  this.settings.set("array_nulls", "on");
20025
20058
  this.settings.set("backslash_quote", "safe_encoding");
20026
20059
  }
@@ -20310,6 +20343,11 @@ var MAX_IDENT = 63;
20310
20343
  function truncIdent(s) {
20311
20344
  return s.length > MAX_IDENT ? s.slice(0, MAX_IDENT) : s;
20312
20345
  }
20346
+ function identitySequenceTarget(env, tableSchema, defaultName, options) {
20347
+ const parts = options.sequenceName;
20348
+ if (!parts || parts.length === 0) return { schema: tableSchema, name: defaultName };
20349
+ return targetSchema(env, parts);
20350
+ }
20313
20351
  var SEQ_LIMITS = {
20314
20352
  int2: { min: -32768n, max: 32767n },
20315
20353
  int4: { min: -2147483648n, max: 2147483647n },
@@ -20486,8 +20524,8 @@ function buildColumn(env, schema, tableName, def, out, taken) {
20486
20524
  break;
20487
20525
  }
20488
20526
  case "generated_identity": {
20489
- const seqName = truncIdent(`${tableName}_${def.name}_seq`);
20490
- const seq = buildSequence(env, schema, seqName, c.options, false);
20527
+ const target = identitySequenceTarget(env, schema, truncIdent(`${tableName}_${def.name}_seq`), c.options);
20528
+ const seq = buildSequence(env, target.schema, target.name, c.options, false);
20491
20529
  if (!c.options.as) {
20492
20530
  seq.dataType = col.type.id === "int2" || col.type.id === "int4" || col.type.id === "int8" ? col.type.id : "int8";
20493
20531
  const limits = SEQ_LIMITS[seq.dataType];
@@ -20496,7 +20534,7 @@ function buildColumn(env, schema, tableName, def, out, taken) {
20496
20534
  }
20497
20535
  seq.ownedBy = { table: tableName, column: def.name };
20498
20536
  out.sequences.push(seq);
20499
- col.identity = { always: c.always, sequence: `${schema.name}.${seqName}` };
20537
+ col.identity = { always: c.always, sequence: `${target.schema.name}.${target.name}` };
20500
20538
  col.notNull = true;
20501
20539
  break;
20502
20540
  }
@@ -20632,10 +20670,11 @@ function executeCreateTable(env, stmt) {
20632
20670
  throw pgError("invalid_table_definition", `multiple primary keys for table "${name}" are not allowed`, "42P16");
20633
20671
  }
20634
20672
  for (const seq of built.sequences) {
20635
- if (schema.hasRelation(seq.name)) {
20673
+ const seqSchema = state.getSchema(seq.schema);
20674
+ if (seqSchema.hasRelation(seq.name)) {
20636
20675
  throw pgError("duplicate_table", `relation "${seq.name}" already exists`, "42P07");
20637
20676
  }
20638
- schema.sequences.set(seq.name, seq);
20677
+ seqSchema.sequences.set(seq.name, seq);
20639
20678
  }
20640
20679
  const table = new TableData(schema.name, name, built.columns, state.nextOid(), stmt.temp);
20641
20680
  table.constraints = built.constraints;
@@ -20987,7 +21026,13 @@ function executeAlterTable(env, stmt) {
20987
21026
  const built = { columns: [], constraints: [], sequences: [] };
20988
21027
  const taken = constraintNames(table);
20989
21028
  const col = buildColumn(env, schema, table.name, action.column, built, taken);
20990
- for (const seq of built.sequences) schema.sequences.set(seq.name, seq);
21029
+ for (const seq of built.sequences) {
21030
+ const seqSchema = state.getSchema(seq.schema);
21031
+ if (seqSchema.hasRelation(seq.name)) {
21032
+ throw pgError("duplicate_table", `relation "${seq.name}" already exists`, "42P07");
21033
+ }
21034
+ seqSchema.sequences.set(seq.name, seq);
21035
+ }
20991
21036
  table.columns.push(col);
20992
21037
  table.constraints.push(...built.constraints);
20993
21038
  for (let i = 0; i < rows.length; i++) {
@@ -21307,12 +21352,32 @@ function executeAlterTable(env, stmt) {
21307
21352
  "42P16"
21308
21353
  );
21309
21354
  }
21310
- const seqName = truncIdent(`${table.name}_${action.column}_seq`);
21311
- const seq = buildSequence(env, schema, seqName, action.options, false);
21355
+ if (!col.notNull) {
21356
+ throw pgError(
21357
+ "object_not_in_prerequisite_state",
21358
+ `column "${action.column}" of relation "${table.name}" must be declared NOT NULL before identity can be added`,
21359
+ "55000"
21360
+ );
21361
+ }
21362
+ const target = identitySequenceTarget(
21363
+ env,
21364
+ schema,
21365
+ truncIdent(`${table.name}_${action.column}_seq`),
21366
+ action.options
21367
+ );
21368
+ if (target.schema.hasRelation(target.name)) {
21369
+ throw pgError("duplicate_table", `relation "${target.name}" already exists`, "42P07");
21370
+ }
21371
+ const seq = buildSequence(env, target.schema, target.name, action.options, false);
21372
+ if (!action.options.as) {
21373
+ seq.dataType = col.type.id === "int2" || col.type.id === "int4" || col.type.id === "int8" ? col.type.id : "int8";
21374
+ const limits = SEQ_LIMITS[seq.dataType];
21375
+ if (action.options.maxValue === void 0) seq.maxValue = seq.increment > 0n ? limits.max : -1n;
21376
+ if (action.options.minValue === void 0) seq.minValue = seq.increment > 0n ? 1n : limits.min;
21377
+ }
21312
21378
  seq.ownedBy = { table: table.name, column: action.column };
21313
- schema.sequences.set(seqName, seq);
21314
- col.identity = { always: true, sequence: `${schema.name}.${seqName}` };
21315
- col.notNull = true;
21379
+ target.schema.sequences.set(target.name, seq);
21380
+ col.identity = { always: action.always, sequence: `${target.schema.name}.${target.name}` };
21316
21381
  break;
21317
21382
  }
21318
21383
  case "drop_identity": {