@mason-data/cli 0.8.0 → 0.10.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.
Files changed (118) hide show
  1. package/README.md +19 -8
  2. package/dist/src/api/error.js +4 -0
  3. package/dist/src/api/postgres/catalog-worker.js +49 -2
  4. package/dist/src/api/postgres/catalog.js +166 -32
  5. package/dist/src/api/postgres/listener.js +11 -3
  6. package/dist/src/api/postgres/proxy.js +129 -0
  7. package/dist/src/api/postgres/schema.js +6 -0
  8. package/dist/src/api/postgres/server.js +527 -103
  9. package/dist/src/api/postgres/translate.js +47 -2
  10. package/dist/src/cli/background.js +18 -19
  11. package/dist/src/cli/bridge-stdin.js +101 -0
  12. package/dist/src/cli/command.js +337 -15
  13. package/dist/src/cli/commands.js +458 -169
  14. package/dist/src/cli/credentials.js +182 -0
  15. package/dist/src/cli/demo.js +2 -2
  16. package/dist/src/cli/deploy.js +680 -0
  17. package/dist/src/cli/dev.js +148 -27
  18. package/dist/src/cli/doctor.js +122 -36
  19. package/dist/src/cli/generated-files.js +143 -0
  20. package/dist/src/cli/guides.js +116 -16
  21. package/dist/src/cli/hosted.js +850 -0
  22. package/dist/src/cli/init.js +154 -33
  23. package/dist/src/cli/login.js +292 -0
  24. package/dist/src/cli/machine.js +125 -40
  25. package/dist/src/cli/main.js +59 -10
  26. package/dist/src/cli/mason.cjs +17 -0
  27. package/dist/src/cli/mcp.js +17 -14
  28. package/dist/src/cli/output-gate.js +176 -0
  29. package/dist/src/cli/page-share.js +96 -0
  30. package/dist/src/cli/pg-tls.js +1 -1
  31. package/dist/src/cli/pin.js +6 -2
  32. package/dist/src/cli/pool-size.cjs +85 -0
  33. package/dist/src/cli/ports.js +2 -0
  34. package/dist/src/cli/preflight.js +130 -39
  35. package/dist/src/cli/project.js +100 -1
  36. package/dist/src/cli/readiness.js +42 -6
  37. package/dist/src/cli/registry.js +89 -36
  38. package/dist/src/cli/replica-hosted.js +1324 -0
  39. package/dist/src/cli/replica.js +114 -0
  40. package/dist/src/cli/replication-mode.js +5 -0
  41. package/dist/src/cli/request-filter.js +16 -6
  42. package/dist/src/cli/roles.js +2 -1
  43. package/dist/src/cli/run-server.js +179 -9
  44. package/dist/src/cli/secret-input.js +193 -0
  45. package/dist/src/cli/security.js +57 -10
  46. package/dist/src/cli/serve.js +65 -9
  47. package/dist/src/cli/share-run.js +51 -8
  48. package/dist/src/cli/share.js +23 -18
  49. package/dist/src/cli/source-edit.js +10 -4
  50. package/dist/src/cli/source-role.js +343 -0
  51. package/dist/src/cli/sources.js +50 -23
  52. package/dist/src/cli/style.js +16 -1
  53. package/dist/src/cli/supervise.js +15 -23
  54. package/dist/src/cli/sync.js +17 -8
  55. package/dist/src/cli/token-hosted.js +343 -0
  56. package/dist/src/cli/tunnel.js +1 -1
  57. package/dist/src/cli/ui-hosted.js +163 -0
  58. package/dist/src/cli/ui-ssh.js +460 -0
  59. package/dist/src/cli/ui.js +162 -17
  60. package/dist/src/cli/usage.js +19 -15
  61. package/dist/src/cli/user-hosted.js +364 -0
  62. package/dist/src/cli/user.js +275 -105
  63. package/dist/src/demo/seed.js +26 -0
  64. package/dist/src/duck/analyze.js +36 -20
  65. package/dist/src/duck/collation.js +266 -0
  66. package/dist/src/duck/constant-key.js +94 -0
  67. package/dist/src/duck/distinct-key.js +283 -26
  68. package/dist/src/duck/events.js +39 -8
  69. package/dist/src/duck/executor-worker.js +2 -2
  70. package/dist/src/duck/executor.js +6 -5
  71. package/dist/src/duck/explain.js +4 -0
  72. package/dist/src/duck/functions.js +448 -49
  73. package/dist/src/duck/gaps.js +34 -16
  74. package/dist/src/duck/generated-plan.js +1070 -0
  75. package/dist/src/duck/generated.js +906 -0
  76. package/dist/src/duck/grants.js +1 -1
  77. package/dist/src/duck/held-types.js +64 -0
  78. package/dist/src/duck/history.js +4 -0
  79. package/dist/src/duck/jsonb-order.js +9 -12
  80. package/dist/src/duck/kept-route.js +6 -5
  81. package/dist/src/duck/kept.js +9 -7
  82. package/dist/src/duck/late.js +1469 -40
  83. package/dist/src/duck/libc-bound.js +341 -0
  84. package/dist/src/duck/libc-order.js +892 -126
  85. package/dist/src/duck/pg-eval-worker.js +7 -1
  86. package/dist/src/duck/pg-eval.js +6 -4
  87. package/dist/src/duck/pgtree.js +774 -23
  88. package/dist/src/duck/plan.js +275 -30
  89. package/dist/src/duck/publication.js +14 -0
  90. package/dist/src/duck/requests.js +9 -5
  91. package/dist/src/duck/resolved.js +117 -2
  92. package/dist/src/duck/rewrite.js +4567 -583
  93. package/dist/src/duck/row-filter.js +12 -6
  94. package/dist/src/duck/statement.js +19 -0
  95. package/dist/src/duck/store.js +294 -68
  96. package/dist/src/duck/stream.js +9 -5
  97. package/dist/src/duck/sync.js +602 -126
  98. package/dist/src/duck/token.js +4 -1
  99. package/dist/src/duck/types.js +63 -7
  100. package/dist/src/duck/usage.js +6 -4
  101. package/dist/src/duck/users.js +110 -9
  102. package/dist/src/duck/verified.js +159 -2
  103. package/dist/src/duck/views.js +4 -3
  104. package/dist/src/lib/cidr.js +177 -0
  105. package/dist/src/lib/database-url.js +55 -10
  106. package/dist/src/lib/instant.js +50 -0
  107. package/dist/src/lib/log-buffer.js +13 -4
  108. package/dist/src/lib/log-read.js +196 -0
  109. package/dist/src/lib/pg-numeric.js +387 -49
  110. package/dist/src/lib/secret-mask.js +142 -0
  111. package/dist/src/lib/table-sync.js +84 -19
  112. package/dist/src/web/app.js +9 -4
  113. package/dist/src/web/pages/status.js +178 -13
  114. package/dist/src/web/pages/syncs.js +1 -1
  115. package/dist/src/web/pages/tables.js +8 -3
  116. package/dist/src/web/pages/users.js +4 -3
  117. package/dist/src/web/shared.js +19 -3
  118. package/package.json +8 -7
@@ -18,9 +18,10 @@
18
18
  * string, a quoted name, a dollar-quoted body and a comment, never in a `::` cast.
19
19
  */
20
20
  import { deparseSync } from "pgsql-deparser";
21
- import { gapRefusal, StatementError } from "../api/postgres/server.js";
21
+ import { gapRefusal, StatementError } from "./statement.js";
22
22
  import { parseSql } from "../api/postgres/parser.js";
23
23
  import { analyze, catalogRows } from "./analyze.js";
24
+ import { sessionSetSql } from "../api/postgres/catalog.js";
24
25
  import { treeDifference } from "./rewrite.js";
25
26
  /** an attribute's name: what `:name` reads and `--set name=value` sets */
26
27
  export const ATTRIBUTE_NAME_RE = /^[a-z_][a-z0-9_]{0,62}$/;
@@ -183,7 +184,7 @@ export async function filterTypes(run, f, shapes) {
183
184
  const message = (r.M ?? "Postgres refused it").replace(/\$(\d+)/g, (m, k) => names[Number(k) - 1] !== undefined ? `:${names[Number(k) - 1]}` : m);
184
185
  return { problem: `${f.at}.where: ${message}${at} — the predicate is checked by Postgres as SELECT 1 FROM ${f.table} WHERE ${f.where.text}` };
185
186
  };
186
- const first = await analyze(run, sql, names.map(() => 0), "public");
187
+ const first = await analyze(run, sql, names.map(() => 0));
187
188
  if ("refused" in first)
188
189
  return said(first.refused);
189
190
  if (hasSubquery(first.tree))
@@ -215,7 +216,7 @@ export async function filterTypes(run, f, shapes) {
215
216
  }
216
217
  if (mismatch !== null) {
217
218
  // Postgres's own refusal, the parameter declared of the shape the file says
218
- const again = await analyze(run, sql, declared, "public");
219
+ const again = await analyze(run, sql, declared);
219
220
  if ("refused" in again)
220
221
  return { problem: `${said(again.refused).problem} (${mismatch})` };
221
222
  return { problem: `${f.at}.where: ${mismatch}` };
@@ -278,7 +279,7 @@ export function bindFilter(f, types, values) {
278
279
  export async function attributeRefused(run, rows, tables) {
279
280
  for (const table of tables) {
280
281
  for (const a of rows.get(table)?.attributes ?? []) {
281
- const r = await analyze(run, `SELECT ${a.sql}`, [], "public");
282
+ const r = await analyze(run, `SELECT ${a.sql}`, []);
282
283
  if ("refused" in r)
283
284
  return { name: a.name, type: a.type, at: a.at, where: a.where, problem: r.refused.M ?? "Postgres refused it" };
284
285
  }
@@ -544,7 +545,7 @@ async function carryKeyDependency(catalog, tree, reads, analysis, oids) {
544
545
  * security: a filtered table's whole row (a subquery's is a record), a name both a WITH query and a filtered table, a
545
546
  * TABLESAMPLE of one, a column qualified by its schema beside another item of the table's name.
546
547
  */
547
- export async function expandRowFilters(catalog, stmt, analysis, searchPathSql, filters) {
548
+ export async function expandRowFilters(catalog, stmt, analysis, under, filters) {
548
549
  const read = relationsRead(analysis.tree);
549
550
  if (read.size === 0 || filters.size === 0)
550
551
  return null;
@@ -562,7 +563,7 @@ export async function expandRowFilters(catalog, stmt, analysis, searchPathSql, f
562
563
  const ranges = all.filter((n) => n.kind === "RangeVar");
563
564
  const ctes = new Set(all.filter((n) => n.kind === "CommonTableExpr").map((n) => n.body.ctename));
564
565
  const spelled = ranges.map((r) => [r.body.catalogname, r.body.schemaname, r.body.relname].filter((x) => typeof x === "string").map(quoteIdent).join("."));
565
- const resolved = spelled.length === 0 ? [] : await catalogRows(catalog, `SET LOCAL search_path = ${searchPathSql}, pg_catalog; SELECT v.i::text, c.oid::text FROM (VALUES ${spelled.map((s, i) => `(${i}, ${literal(s)})`).join(", ")}) AS v(i, name) ` +
566
+ const resolved = spelled.length === 0 ? [] : await catalogRows(catalog, `${sessionSetSql(under, true)}; SELECT v.i::text, c.oid::text FROM (VALUES ${spelled.map((s, i) => `(${i}, ${literal(s)})`).join(", ")}) AS v(i, name) ` +
566
567
  `JOIN pg_class c ON c.oid = to_regclass(v.name) WHERE c.relkind = 'r'`);
567
568
  const asFiltered = new Map();
568
569
  for (const [i, oid] of resolved) {
@@ -591,6 +592,11 @@ export async function expandRowFilters(catalog, stmt, analysis, searchPathSql, f
591
592
  if ([...filteredRead.values()].some((v) => !found.has(v.table))) {
592
593
  throw refused("Mason could not tell which of the statement's names are the tables its role filters (a Mason gap: report it, with the statement)", "write each table's name qualified by its schema");
593
594
  }
595
+ // the printer below (pgsql-deparser) writes FETCH … WITH TIES as a LIMIT, which the read-back refuses as a report-it
596
+ // gap: said by name here instead, at any depth (a set operation's arm is a body of its own, unwrapped)
597
+ if (JSON.stringify(tree).includes("\"limitOption\":\"LIMIT_OPTION_WITH_TIES\"")) {
598
+ throw refused("Mason cannot yet answer FETCH … WITH TIES in a statement that reads a table its role filters", "write ORDER BY … LIMIT n where the ties do not matter");
599
+ }
594
600
  // a column qualified by its table's schema (`public.orders.id`, Metabase writes every column so) names the subquery by
595
601
  // its alias alone: sound only where no other item of the statement has the table's name
596
602
  const named = all.flatMap((n) => {
@@ -0,0 +1,19 @@
1
+ import { gapMark } from "./gaps.js";
2
+ /** A statement's error as Postgres raises it, from outside the listener (the DuckDB runner's): the fields, and the SQL
3
+ * its position is in. */
4
+ export class StatementError extends Error {
5
+ fields;
6
+ sql;
7
+ /** the registry entry (src/duck/gaps.ts) that refused the statement, as the refusal was built with it (`gapRefusal`,
8
+ * src/duck/store.ts pgErrorOf): what the request log records as `gap`; null for every other error */
9
+ gap;
10
+ constructor(fields, sql = "", gap = null) { super(fields.message); this.fields = fields; this.sql = sql; this.gap = gap; }
11
+ }
12
+ /**
13
+ * A REFUSAL BY A REGISTRY ENTRY (src/duck/gaps.ts), the one way one is built: 0A000, `Mason gap <id>` in its DETAIL (what
14
+ * the oracle and a reader read), followed by `detail` (docs/SQL-SUPPORT.md, or what it names), and the id itself on the
15
+ * error, so the request log records which entry refused it without reading the text back.
16
+ */
17
+ export function gapRefusal(gap, message, hint, sql = "", detail = " (docs/SQL-SUPPORT.md)") {
18
+ return new StatementError({ code: "0A000", message, hint, detail: `${gapMark(gap)}${detail}` }, sql, gap);
19
+ }