@crvouga/mockingbird-service-postgres 1.5.1 → 1.7.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.
package/dist/admin.js CHANGED
@@ -717,12 +717,12 @@ function bootAdmin(config) {
717
717
  throw new Error(`admin shell is missing #${id}`);
718
718
  return node;
719
719
  };
720
- const errorMessage = (data, fallback) => {
720
+ const errorMessage = (data, fallback2) => {
721
721
  if (!isRecord(data))
722
- return fallback;
722
+ return fallback2;
723
723
  const error = data.error;
724
724
  if (!isRecord(error) || typeof error.message !== "string" || error.message === "") {
725
- return fallback;
725
+ return fallback2;
726
726
  }
727
727
  return error.message;
728
728
  };
@@ -981,8 +981,8 @@ function bootAdmin(config) {
981
981
  const data = await api("GET", "/namespaces");
982
982
  const select = el("namespace", HTMLSelectElement);
983
983
  const listed2 = requireList(isRecord(data) ? data.namespaces : void 0, "Namespaces");
984
- const fallback = isRecord(data) && typeof data.default === "string" && data.default !== "" ? data.default : "default";
985
- const names = (listed2.length > 0 ? listed2.map((name) => String(name)) : [fallback]).slice();
984
+ const fallback2 = isRecord(data) && typeof data.default === "string" && data.default !== "" ? data.default : "default";
985
+ const names = (listed2.length > 0 ? listed2.map((name) => String(name)) : [fallback2]).slice();
986
986
  if (!names.includes(state.namespace))
987
987
  names.unshift(state.namespace);
988
988
  select.innerHTML = names.map((name) => `<option value="${esc(name)}">${esc(name)}</option>`).join("");
@@ -1561,29 +1561,30 @@ var createControlPlane = (context) => {
1561
1561
  return json(200, { status: "ok", reset: target === "*" ? context.namespaces() : [target] });
1562
1562
  },
1563
1563
  "GET /namespaces": () => json(200, { default: context.defaultNamespace, namespaces: context.namespaces() }),
1564
- "GET /clock": () => json(200, context.clock.state()),
1565
- "POST /clock": ({ body }) => {
1564
+ "GET /clock": ({ namespace }) => json(200, (context.namespaceClock?.(namespace) ?? context.clock).state()),
1565
+ "POST /clock": ({ body, namespace }) => {
1566
+ const clock = context.namespaceClock?.(namespace) ?? context.clock;
1566
1567
  if (!isRecord2(body))
1567
1568
  return adminError(400, "expected a JSON object");
1568
1569
  if (body.reset === true)
1569
- context.clock.reset();
1570
+ clock.reset();
1570
1571
  if (body.freeze === true)
1571
- context.clock.freeze();
1572
+ clock.freeze();
1572
1573
  if (body.set !== void 0) {
1573
1574
  const instant = parseInstant(body.set);
1574
1575
  if (instant === void 0)
1575
1576
  return adminError(400, "set: expected epoch ms or ISO-8601");
1576
- context.clock.set(instant);
1577
+ clock.set(instant);
1577
1578
  }
1578
1579
  if (body.advance !== void 0) {
1579
1580
  const delta = parseDuration(body.advance);
1580
1581
  if (delta === void 0)
1581
1582
  return adminError(400, 'advance: expected ms or "15m"-style');
1582
- context.clock.advance(delta);
1583
+ clock.advance(delta);
1583
1584
  }
1584
1585
  if (body.freeze === false)
1585
- context.clock.unfreeze();
1586
- return json(200, context.clock.state());
1586
+ clock.unfreeze();
1587
+ return json(200, clock.state());
1587
1588
  },
1588
1589
  "GET /faults": () => json(200, { faults: context.faults.list() }),
1589
1590
  "POST /faults": ({ body, namespace }) => {
@@ -2425,7 +2426,33 @@ var faultResponse = (rule) => {
2425
2426
  };
2426
2427
  var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) => {
2427
2428
  const entries = [];
2429
+ let isolated = false;
2430
+ const scopedRngs = /* @__PURE__ */ new Map();
2431
+ const random = (namespace) => {
2432
+ if (!isolated || namespace === "default")
2433
+ return rng;
2434
+ let scoped = scopedRngs.get(namespace);
2435
+ if (!scoped) {
2436
+ scoped = createRng(rng.seed);
2437
+ scopedRngs.set(namespace, scoped);
2438
+ }
2439
+ return scoped;
2440
+ };
2428
2441
  return {
2442
+ isolateNamespaces() {
2443
+ isolated = true;
2444
+ },
2445
+ snapshot(namespace) {
2446
+ return {
2447
+ rules: structuredClone(entries.map((entry, position) => ({
2448
+ ...entry.rule,
2449
+ remaining: entry.remaining,
2450
+ hits: entry.hits,
2451
+ position
2452
+ })).filter((entry) => entry.namespace === namespace)),
2453
+ rngState: random(namespace).state()
2454
+ };
2455
+ },
2429
2456
  add(rule) {
2430
2457
  const existing = entries.findIndex((e) => e.rule.id === rule.id);
2431
2458
  const entry = { rule, remaining: rule.count ?? null, hits: 0 };
@@ -2445,6 +2472,16 @@ var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((reso
2445
2472
  },
2446
2473
  clear() {
2447
2474
  entries.length = 0;
2475
+ rng.reset();
2476
+ scopedRngs.clear();
2477
+ },
2478
+ restore(namespace, state) {
2479
+ for (let i = entries.length - 1; i >= 0; i--)
2480
+ if (entries[i]?.rule.namespace === namespace)
2481
+ entries.splice(i, 1);
2482
+ for (const { remaining, hits, position, ...rule } of state.rules)
2483
+ entries.splice(Math.min(position, entries.length), 0, { rule, remaining, hits });
2484
+ random(namespace).setState(state.rngState);
2448
2485
  },
2449
2486
  async take(candidate) {
2450
2487
  const hits = [];
@@ -2454,7 +2491,7 @@ var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((reso
2454
2491
  if (!matches(entry.rule, candidate))
2455
2492
  continue;
2456
2493
  const rate = entry.rule.rate ?? 1;
2457
- if (rng.next() >= rate)
2494
+ if (random(candidate.namespace).next() >= rate)
2458
2495
  continue;
2459
2496
  entry.hits++;
2460
2497
  if (entry.remaining !== null)
@@ -2521,7 +2558,8 @@ var createJournal = (size = DEFAULT_JOURNAL_SIZE) => {
2521
2558
  };
2522
2559
 
2523
2560
  // ../core/dist/metrics.js
2524
- var createMetrics = () => {
2561
+ var createMetrics = (partition = true) => {
2562
+ const namespaces = /* @__PURE__ */ new Map();
2525
2563
  let requests = 0;
2526
2564
  let faults = 0;
2527
2565
  let totalDurationMs = 0;
@@ -2529,6 +2567,14 @@ var createMetrics = () => {
2529
2567
  const unmatched = /* @__PURE__ */ new Map();
2530
2568
  return {
2531
2569
  record(entry) {
2570
+ if (partition) {
2571
+ let scoped = namespaces.get(entry.namespace);
2572
+ if (!scoped) {
2573
+ scoped = createMetrics(false);
2574
+ namespaces.set(entry.namespace, scoped);
2575
+ }
2576
+ scoped.record(entry);
2577
+ }
2532
2578
  requests++;
2533
2579
  totalDurationMs += entry.durationMs;
2534
2580
  if (entry.faultId !== void 0)
@@ -2540,7 +2586,7 @@ var createMetrics = () => {
2540
2586
  unmatched.set(route, (unmatched.get(route) ?? 0) + 1);
2541
2587
  }
2542
2588
  },
2543
- report: () => ({
2589
+ report: (namespace) => namespace !== void 0 ? (namespaces.get(namespace) ?? createMetrics(false)).report() : {
2544
2590
  requests,
2545
2591
  byOperation: Object.fromEntries([...byOperation].sort(([a], [b]) => a.localeCompare(b))),
2546
2592
  unmatched: [...unmatched].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([route, count]) => {
@@ -2549,8 +2595,13 @@ var createMetrics = () => {
2549
2595
  }),
2550
2596
  faults,
2551
2597
  totalDurationMs
2552
- }),
2553
- reset() {
2598
+ },
2599
+ reset(namespace) {
2600
+ if (namespace !== void 0) {
2601
+ namespaces.delete(namespace);
2602
+ return;
2603
+ }
2604
+ namespaces.clear();
2554
2605
  requests = 0;
2555
2606
  faults = 0;
2556
2607
  totalDurationMs = 0;
@@ -2629,9 +2680,9 @@ var kindFromType = (type) => {
2629
2680
  return "unknown";
2630
2681
  return "string";
2631
2682
  };
2632
- var countParam = (value, fallback, max) => {
2683
+ var countParam = (value, fallback2, max) => {
2633
2684
  if (value === null)
2634
- return fallback;
2685
+ return fallback2;
2635
2686
  if (!/^\d+$/.test(value))
2636
2687
  return void 0;
2637
2688
  return Math.min(max, Number(value));
@@ -6344,7 +6395,13 @@ var DatabaseState = class _DatabaseState {
6344
6395
  this.settings.set("lc_numeric", "C");
6345
6396
  this.settings.set("lc_time", "C");
6346
6397
  this.settings.set("default_transaction_isolation", "read committed");
6398
+ this.settings.set("lock_timeout", "0");
6399
+ this.settings.set("idle_in_transaction_session_timeout", "0");
6400
+ this.settings.set("transaction_timeout", "0");
6347
6401
  this.settings.set("statement_timeout", "0");
6402
+ this.settings.set("check_function_bodies", "on");
6403
+ this.settings.set("xmloption", "content");
6404
+ this.settings.set("row_security", "on");
6348
6405
  this.settings.set("array_nulls", "on");
6349
6406
  this.settings.set("backslash_quote", "safe_encoding");
6350
6407
  }
@@ -9946,6 +10003,19 @@ function exactDegTan(x) {
9946
10003
  return Math.tan(x * Math.PI / 180);
9947
10004
  }
9948
10005
 
10006
+ // src/sql/deparse.ts
10007
+ function quoteIdent(name) {
10008
+ if (/^[a-z_][a-z0-9_$]*$/.test(name)) return name;
10009
+ return `"${name.replaceAll('"', '""')}"`;
10010
+ }
10011
+
10012
+ // src/runtime/database-context.ts
10013
+ var contexts = /* @__PURE__ */ new WeakMap();
10014
+ var fallback = { name: "postgres", names: () => ["postgres"] };
10015
+ function databaseCatalogContext(state) {
10016
+ return contexts.get(state) ?? fallback;
10017
+ }
10018
+
9949
10019
  // src/functions/misc-fns.ts
9950
10020
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
9951
10021
  function findSequenceForCall(ctx, name) {
@@ -10029,8 +10099,8 @@ function sequenceNextval(ctx, seq) {
10029
10099
  function getMiscFunctions() {
10030
10100
  const m = /* @__PURE__ */ new Map();
10031
10101
  m.set("version", () => tv("text", PG_VERSION_TEXT));
10032
- m.set("current_database", () => tv("name", "postgres"));
10033
- m.set("current_catalog", () => tv("name", "postgres"));
10102
+ m.set("current_database", (ctx) => tv("name", databaseCatalogContext(ctx.state).name));
10103
+ m.set("current_catalog", (ctx) => tv("name", databaseCatalogContext(ctx.state).name));
10034
10104
  m.set("current_schema", (ctx) => {
10035
10105
  const path = ctx.state.effectiveSearchPath();
10036
10106
  const first = path.find((s) => ctx.state.schemas.has(s));
@@ -10152,7 +10222,7 @@ function getMiscFunctions() {
10152
10222
  if (!col.identity) return tv("text", null);
10153
10223
  return tv(
10154
10224
  "text",
10155
- col.identity.sequence.split(".").map((p) => p).join(".")
10225
+ col.identity.sequence.split(".").map(quoteIdent).join(".")
10156
10226
  );
10157
10227
  })
10158
10228
  );
@@ -17402,14 +17472,19 @@ var Parser = class {
17402
17472
  parseIdentityOptions() {
17403
17473
  const options = {};
17404
17474
  if (this.eatPunct("(")) {
17405
- Object.assign(options, this.parseSequenceOptions());
17475
+ Object.assign(options, this.parseSequenceOptions(true));
17406
17476
  this.expectPunct(")");
17407
17477
  }
17408
17478
  return options;
17409
17479
  }
17410
- parseSequenceOptions() {
17480
+ parseSequenceOptions(identity = false) {
17411
17481
  const options = {};
17412
17482
  for (; ; ) {
17483
+ if (identity && this.eatKw("sequence")) {
17484
+ this.expectKw("name");
17485
+ options.sequenceName = this.qualifiedName();
17486
+ continue;
17487
+ }
17413
17488
  if (this.eatKw("increment")) {
17414
17489
  this.eatKw("by");
17415
17490
  options.increment = this.parseSignedBigInt();
@@ -23411,6 +23486,27 @@ function parseCsvLine(line, delim, quote) {
23411
23486
  }
23412
23487
  return fields;
23413
23488
  }
23489
+ function splitCsvRecords(data, quote) {
23490
+ const records = [];
23491
+ let start = 0;
23492
+ let quoted = false;
23493
+ for (let i = 0; i < data.length; i++) {
23494
+ const char = data[i];
23495
+ if (char === quote) {
23496
+ if (quoted && data[i + 1] === quote) i++;
23497
+ else quoted = !quoted;
23498
+ continue;
23499
+ }
23500
+ if (char === "\n" && !quoted) {
23501
+ const end = i > start && data[i - 1] === "\r" ? i - 1 : i;
23502
+ records.push(data.slice(start, end));
23503
+ start = i + 1;
23504
+ }
23505
+ }
23506
+ if (quoted) throw pgError("invalid_text_representation", "unterminated CSV quoted field", "22P04");
23507
+ if (start < data.length) records.push(data.slice(start));
23508
+ return records;
23509
+ }
23414
23510
  function executeCopyFromData(env, stmt, data) {
23415
23511
  const format = String(stmt.options.format ?? "text").toLowerCase();
23416
23512
  if (format !== "text" && format !== "csv") throw unsupported(`COPY format ${format}`);
@@ -23421,7 +23517,7 @@ function executeCopyFromData(env, stmt, data) {
23421
23517
  const nullStr = String(stmt.options.null ?? (format === "csv" ? "" : "\\N"));
23422
23518
  const quote = String(stmt.options.quote ?? '"');
23423
23519
  const header = stmt.options.header === true || String(stmt.options.header ?? "").toLowerCase() === "true";
23424
- let lines = data.split(/\r?\n/);
23520
+ let lines = format === "csv" ? splitCsvRecords(data, quote) : data.split(/\r?\n/);
23425
23521
  const endMarker = lines.indexOf("\\.");
23426
23522
  if (endMarker !== -1) lines = lines.slice(0, endMarker);
23427
23523
  if (lines.length > 0 && lines[lines.length - 1] === "") lines = lines.slice(0, -1);
@@ -24155,7 +24251,8 @@ function pgSettings(ctx) {
24155
24251
  "pg_settings"
24156
24252
  );
24157
24253
  }
24158
- function pgDatabase() {
24254
+ function pgDatabase(ctx) {
24255
+ const names = databaseCatalogContext(ctx.state).names();
24159
24256
  return rel(
24160
24257
  [
24161
24258
  ["oid", "oid"],
@@ -24164,7 +24261,7 @@ function pgDatabase() {
24164
24261
  ["datistemplate", "bool"],
24165
24262
  ["datallowconn", "bool"]
24166
24263
  ],
24167
- [[5, "postgres", 6, false, true]],
24264
+ names.map((name, index) => [5 + index, name, 6, false, true]),
24168
24265
  "pg_database"
24169
24266
  );
24170
24267
  }
@@ -24199,13 +24296,14 @@ function pgTrigger(ctx) {
24199
24296
  "pg_trigger"
24200
24297
  );
24201
24298
  }
24202
- var CATALOG_NAME = "postgres";
24299
+ var catalogName = (state) => databaseCatalogContext(state).name;
24203
24300
  function infoSchemata(state) {
24301
+ const catalog = catalogName(state);
24204
24302
  const rows = [
24205
- [CATALOG_NAME, "pg_catalog", OWNER],
24206
- [CATALOG_NAME, "information_schema", OWNER]
24303
+ [catalog, "pg_catalog", OWNER],
24304
+ [catalog, "information_schema", OWNER]
24207
24305
  ];
24208
- for (const s of state.schemas.values()) rows.push([CATALOG_NAME, s.name, OWNER]);
24306
+ for (const s of state.schemas.values()) rows.push([catalog, s.name, OWNER]);
24209
24307
  return rel(
24210
24308
  [
24211
24309
  ["catalog_name", "name"],
@@ -24217,13 +24315,14 @@ function infoSchemata(state) {
24217
24315
  );
24218
24316
  }
24219
24317
  function infoTables(ctx) {
24318
+ const catalog = catalogName(ctx.state);
24220
24319
  const rows = [];
24221
24320
  for (const schema of ctx.state.schemas.values()) {
24222
24321
  for (const t of schema.tables.values()) {
24223
- rows.push([CATALOG_NAME, t.schema, t.name, t.temp ? "LOCAL TEMPORARY" : "BASE TABLE", "YES"]);
24322
+ rows.push([catalog, t.schema, t.name, t.temp ? "LOCAL TEMPORARY" : "BASE TABLE", "YES"]);
24224
24323
  }
24225
24324
  for (const v of schema.views.values()) {
24226
- if (!v.materialized) rows.push([CATALOG_NAME, v.schema, v.name, "VIEW", "NO"]);
24325
+ if (!v.materialized) rows.push([catalog, v.schema, v.name, "VIEW", "NO"]);
24227
24326
  }
24228
24327
  }
24229
24328
  return rel(
@@ -24239,6 +24338,7 @@ function infoTables(ctx) {
24239
24338
  );
24240
24339
  }
24241
24340
  function infoColumns(ctx) {
24341
+ const catalog = catalogName(ctx.state);
24242
24342
  const rows = [];
24243
24343
  for (const t of allTables(ctx.state)) {
24244
24344
  t.columns.forEach((c, i) => {
@@ -24249,7 +24349,7 @@ function infoColumns(ctx) {
24249
24349
  const dataType = isArrayType(id) ? "ARRAY" : isEnumType(id) ? "USER-DEFINED" : typeDisplayName(id);
24250
24350
  const udt = isArrayType(id) ? `_${arrayUdt(id)}` : isEnumType(id) ? id.slice(5).split(".").pop() : id;
24251
24351
  rows.push([
24252
- CATALOG_NAME,
24352
+ catalog,
24253
24353
  t.schema,
24254
24354
  t.name,
24255
24355
  c.name,
@@ -24294,10 +24394,11 @@ function arrayUdt(t) {
24294
24394
  return isEnumType(elem) ? elem.slice(5).split(".").pop() : elem;
24295
24395
  }
24296
24396
  function infoViews(ctx) {
24397
+ const catalog = catalogName(ctx.state);
24297
24398
  const rows = [];
24298
24399
  for (const schema of ctx.state.schemas.values()) {
24299
24400
  for (const v of schema.views.values()) {
24300
- if (!v.materialized) rows.push([CATALOG_NAME, v.schema, v.name, null]);
24401
+ if (!v.materialized) rows.push([catalog, v.schema, v.name, null]);
24301
24402
  }
24302
24403
  }
24303
24404
  return rel(
@@ -24312,10 +24413,11 @@ function infoViews(ctx) {
24312
24413
  );
24313
24414
  }
24314
24415
  function infoSequences(ctx) {
24416
+ const catalog = catalogName(ctx.state);
24315
24417
  const rows = [];
24316
24418
  for (const s of allSequences(ctx.state)) {
24317
24419
  rows.push([
24318
- CATALOG_NAME,
24420
+ catalog,
24319
24421
  s.schema,
24320
24422
  s.name,
24321
24423
  typeDisplayName(s.dataType),
@@ -24343,11 +24445,12 @@ function infoSequences(ctx) {
24343
24445
  );
24344
24446
  }
24345
24447
  function infoTableConstraints(ctx) {
24448
+ const catalog = catalogName(ctx.state);
24346
24449
  const rows = [];
24347
24450
  for (const t of allTables(ctx.state)) {
24348
24451
  for (const c of t.constraints) {
24349
24452
  const type = c.kind === "primary_key" ? "PRIMARY KEY" : c.kind === "unique" ? "UNIQUE" : c.kind === "check" ? "CHECK" : "FOREIGN KEY";
24350
- rows.push([CATALOG_NAME, t.schema, c.name, CATALOG_NAME, t.schema, t.name, type]);
24453
+ rows.push([catalog, t.schema, c.name, catalog, t.schema, t.name, type]);
24351
24454
  }
24352
24455
  }
24353
24456
  return rel(
@@ -24365,12 +24468,13 @@ function infoTableConstraints(ctx) {
24365
24468
  );
24366
24469
  }
24367
24470
  function infoKeyColumnUsage(ctx) {
24471
+ const catalog = catalogName(ctx.state);
24368
24472
  const rows = [];
24369
24473
  for (const t of allTables(ctx.state)) {
24370
24474
  for (const c of t.constraints) {
24371
24475
  if (c.kind !== "primary_key" && c.kind !== "unique" && c.kind !== "foreign_key") continue;
24372
24476
  c.columns.forEach((col, i) => {
24373
- rows.push([CATALOG_NAME, t.schema, c.name, CATALOG_NAME, t.schema, t.name, col, i + 1]);
24477
+ rows.push([catalog, t.schema, c.name, catalog, t.schema, t.name, col, i + 1]);
24374
24478
  });
24375
24479
  }
24376
24480
  }
@@ -24390,12 +24494,13 @@ function infoKeyColumnUsage(ctx) {
24390
24494
  );
24391
24495
  }
24392
24496
  function infoRoutines(ctx) {
24497
+ const catalog = catalogName(ctx.state);
24393
24498
  const rows = [];
24394
24499
  for (const schema of ctx.state.schemas.values()) {
24395
24500
  for (const fns of schema.functions.values()) {
24396
24501
  for (const f of fns) {
24397
24502
  rows.push([
24398
- CATALOG_NAME,
24503
+ catalog,
24399
24504
  f.schema,
24400
24505
  f.name,
24401
24506
  "FUNCTION",
@@ -24452,7 +24557,7 @@ function buildCatalogRelation(ctx, schema, name) {
24452
24557
  case "pg_settings":
24453
24558
  return pgSettings(ctx);
24454
24559
  case "pg_database":
24455
- return pgDatabase();
24560
+ return pgDatabase(ctx);
24456
24561
  case "pg_roles":
24457
24562
  case "pg_user":
24458
24563
  return pgRoles();
@@ -24633,6 +24738,11 @@ var MAX_IDENT = 63;
24633
24738
  function truncIdent(s) {
24634
24739
  return s.length > MAX_IDENT ? s.slice(0, MAX_IDENT) : s;
24635
24740
  }
24741
+ function identitySequenceTarget(env, tableSchema, defaultName, options) {
24742
+ const parts = options.sequenceName;
24743
+ if (!parts || parts.length === 0) return { schema: tableSchema, name: defaultName };
24744
+ return targetSchema(env, parts);
24745
+ }
24636
24746
  var SEQ_LIMITS = {
24637
24747
  int2: { min: -32768n, max: 32767n },
24638
24748
  int4: { min: -2147483648n, max: 2147483647n },
@@ -24809,8 +24919,8 @@ function buildColumn(env, schema, tableName, def, out, taken) {
24809
24919
  break;
24810
24920
  }
24811
24921
  case "generated_identity": {
24812
- const seqName = truncIdent(`${tableName}_${def.name}_seq`);
24813
- const seq = buildSequence(env, schema, seqName, c.options, false);
24922
+ const target = identitySequenceTarget(env, schema, truncIdent(`${tableName}_${def.name}_seq`), c.options);
24923
+ const seq = buildSequence(env, target.schema, target.name, c.options, false);
24814
24924
  if (!c.options.as) {
24815
24925
  seq.dataType = col.type.id === "int2" || col.type.id === "int4" || col.type.id === "int8" ? col.type.id : "int8";
24816
24926
  const limits = SEQ_LIMITS[seq.dataType];
@@ -24819,7 +24929,7 @@ function buildColumn(env, schema, tableName, def, out, taken) {
24819
24929
  }
24820
24930
  seq.ownedBy = { table: tableName, column: def.name };
24821
24931
  out.sequences.push(seq);
24822
- col.identity = { always: c.always, sequence: `${schema.name}.${seqName}` };
24932
+ col.identity = { always: c.always, sequence: `${target.schema.name}.${target.name}` };
24823
24933
  col.notNull = true;
24824
24934
  break;
24825
24935
  }
@@ -24955,10 +25065,11 @@ function executeCreateTable(env, stmt) {
24955
25065
  throw pgError("invalid_table_definition", `multiple primary keys for table "${name}" are not allowed`, "42P16");
24956
25066
  }
24957
25067
  for (const seq of built.sequences) {
24958
- if (schema.hasRelation(seq.name)) {
25068
+ const seqSchema = state.getSchema(seq.schema);
25069
+ if (seqSchema.hasRelation(seq.name)) {
24959
25070
  throw pgError("duplicate_table", `relation "${seq.name}" already exists`, "42P07");
24960
25071
  }
24961
- schema.sequences.set(seq.name, seq);
25072
+ seqSchema.sequences.set(seq.name, seq);
24962
25073
  }
24963
25074
  const table = new TableData(schema.name, name, built.columns, state.nextOid(), stmt.temp);
24964
25075
  table.constraints = built.constraints;
@@ -25310,7 +25421,13 @@ function executeAlterTable(env, stmt) {
25310
25421
  const built = { columns: [], constraints: [], sequences: [] };
25311
25422
  const taken = constraintNames(table);
25312
25423
  const col = buildColumn(env, schema, table.name, action.column, built, taken);
25313
- for (const seq of built.sequences) schema.sequences.set(seq.name, seq);
25424
+ for (const seq of built.sequences) {
25425
+ const seqSchema = state.getSchema(seq.schema);
25426
+ if (seqSchema.hasRelation(seq.name)) {
25427
+ throw pgError("duplicate_table", `relation "${seq.name}" already exists`, "42P07");
25428
+ }
25429
+ seqSchema.sequences.set(seq.name, seq);
25430
+ }
25314
25431
  table.columns.push(col);
25315
25432
  table.constraints.push(...built.constraints);
25316
25433
  for (let i = 0; i < rows.length; i++) {
@@ -25630,12 +25747,32 @@ function executeAlterTable(env, stmt) {
25630
25747
  "42P16"
25631
25748
  );
25632
25749
  }
25633
- const seqName = truncIdent(`${table.name}_${action.column}_seq`);
25634
- const seq = buildSequence(env, schema, seqName, action.options, false);
25750
+ if (!col.notNull) {
25751
+ throw pgError(
25752
+ "object_not_in_prerequisite_state",
25753
+ `column "${action.column}" of relation "${table.name}" must be declared NOT NULL before identity can be added`,
25754
+ "55000"
25755
+ );
25756
+ }
25757
+ const target = identitySequenceTarget(
25758
+ env,
25759
+ schema,
25760
+ truncIdent(`${table.name}_${action.column}_seq`),
25761
+ action.options
25762
+ );
25763
+ if (target.schema.hasRelation(target.name)) {
25764
+ throw pgError("duplicate_table", `relation "${target.name}" already exists`, "42P07");
25765
+ }
25766
+ const seq = buildSequence(env, target.schema, target.name, action.options, false);
25767
+ if (!action.options.as) {
25768
+ seq.dataType = col.type.id === "int2" || col.type.id === "int4" || col.type.id === "int8" ? col.type.id : "int8";
25769
+ const limits = SEQ_LIMITS[seq.dataType];
25770
+ if (action.options.maxValue === void 0) seq.maxValue = seq.increment > 0n ? limits.max : -1n;
25771
+ if (action.options.minValue === void 0) seq.minValue = seq.increment > 0n ? 1n : limits.min;
25772
+ }
25635
25773
  seq.ownedBy = { table: table.name, column: action.column };
25636
- schema.sequences.set(seqName, seq);
25637
- col.identity = { always: true, sequence: `${schema.name}.${seqName}` };
25638
- col.notNull = true;
25774
+ target.schema.sequences.set(target.name, seq);
25775
+ col.identity = { always: action.always, sequence: `${target.schema.name}.${target.name}` };
25639
25776
  break;
25640
25777
  }
25641
25778
  case "drop_identity": {
@@ -26504,7 +26641,7 @@ if (typeof disposeKey === "symbol") {
26504
26641
 
26505
26642
  // src/admin.ts
26506
26643
  var QUERY_CAP = 500;
26507
- var quoteIdent = (name) => `"${name.replaceAll('"', '""')}"`;
26644
+ var quoteIdent2 = (name) => `"${name.replaceAll('"', '""')}"`;
26508
26645
  var bounded = (value) => {
26509
26646
  if (!Number.isSafeInteger(value) || value < 0) throw new Error("limit and offset must be non-negative integers");
26510
26647
  return value;
@@ -26577,7 +26714,7 @@ var adapt = (db) => ({
26577
26714
  tables: () => listed(db),
26578
26715
  page(schema, table, limit, offset) {
26579
26716
  const found = requireTable(db, schema, table);
26580
- const from = `${quoteIdent(schema)}.${quoteIdent(table)}`;
26717
+ const from = `${quoteIdent2(schema)}.${quoteIdent2(table)}`;
26581
26718
  const take = bounded(limit);
26582
26719
  const skip = bounded(offset);
26583
26720
  const totalRow = db.query(`SELECT count(*) AS count FROM ${from}`);