@sqlanvil/cli 1.27.0 → 1.27.2

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 (2) hide show
  1. package/bundle.js +149 -43
  2. package/package.json +1 -1
package/bundle.js CHANGED
@@ -50646,7 +50646,7 @@ function collectEvaluationQueries(queryOrAction, concatenate, queryModifier = (q
50646
50646
  .filter(validationQuery => !!validationQuery.query);
50647
50647
  }
50648
50648
 
50649
- const version = "1.27.0";
50649
+ const version = "1.27.2";
50650
50650
  const dataformVersion = "3.0.61";
50651
50651
 
50652
50652
  async function build(compiledGraph, runConfig, dbadapter) {
@@ -51821,6 +51821,12 @@ class BigQueryDbAdapter {
51821
51821
  })
51822
51822
  .promise();
51823
51823
  }
51824
+ queryStream(statement) {
51825
+ return this.getClient().createQueryStream({
51826
+ query: statement,
51827
+ location: this.bigQueryCredentials.location || undefined
51828
+ });
51829
+ }
51824
51830
  async executeRaw(statement, options = { rowLimit: 1000 }) {
51825
51831
  if (!statement) {
51826
51832
  throw new Error("Query string cannot be empty");
@@ -52251,11 +52257,12 @@ class PgPoolExecutor {
52251
52257
  console.error("Error thrown when releasing pg.Client", e.message, e.stack);
52252
52258
  }
52253
52259
  };
52260
+ const onClientError = (err) => {
52261
+ console.error("pg.Client client error", err.message, err.stack);
52262
+ releaseOnce(err);
52263
+ };
52254
52264
  try {
52255
- client.on("error", err => {
52256
- console.error("pg.Client client error", err.message, err.stack);
52257
- releaseOnce(err);
52258
- });
52265
+ client.on("error", onClientError);
52259
52266
  return await callback({
52260
52267
  execute: async (statement, options = { rowLimit: 1000, byteLimit: 1024 * 1024 }) => {
52261
52268
  return await new Promise((resolve, reject) => {
@@ -52290,6 +52297,7 @@ class PgPoolExecutor {
52290
52297
  });
52291
52298
  }
52292
52299
  finally {
52300
+ client.removeListener("error", onClientError);
52293
52301
  releaseOnce();
52294
52302
  }
52295
52303
  }
@@ -52578,12 +52586,13 @@ class PostgresDbAdapter {
52578
52586
 
52579
52587
  const MAX_PARAMS_PER_INSERT = 60000;
52580
52588
  const quoteIdent = (id) => `"${String(id).replace(/"/g, '""')}"`;
52581
- async function loadRowsIntoPostgres(args) {
52589
+ async function createPgLoader(args) {
52582
52590
  var _a;
52583
- const { target, columnTypes, rows } = args;
52591
+ const { target, columnTypes } = args;
52584
52592
  const cols = Object.keys(columnTypes);
52585
52593
  const coerce = args.coerce || ((v) => (v === undefined ? null : v));
52586
52594
  const pg = await PostgresDbAdapter.create(args.pg, {
52595
+ concurrencyLimit: 1,
52587
52596
  disableSslForTestsOnly: args.disableSslForTestsOnly
52588
52597
  });
52589
52598
  try {
@@ -52603,39 +52612,73 @@ async function loadRowsIntoPostgres(args) {
52603
52612
  await pg.execute(`drop table ${qualified} cascade`);
52604
52613
  }
52605
52614
  await pg.execute(`create table ${qualified} (${colDefs})`);
52606
- const colIdents = cols.map(quoteIdent).join(", ");
52607
- const batchRows = Math.max(1, Math.min(1000, Math.floor(MAX_PARAMS_PER_INSERT / cols.length)));
52608
- for (let i = 0; i < rows.length; i += batchRows) {
52609
- const batch = rows.slice(i, i + batchRows);
52610
- const params = [];
52611
- const tuples = batch.map((row, r) => {
52612
- const placeholders = cols.map((c, ci) => `$${r * cols.length + ci + 1}`);
52613
- cols.forEach(c => params.push(coerce(row[c])));
52614
- return `(${placeholders.join(", ")})`;
52615
- });
52616
- await pg.execute(`insert into ${qualified} (${colIdents}) values ${tuples.join(", ")}`, {
52617
- params
52618
- });
52615
+ }
52616
+ catch (e) {
52617
+ await pg.close();
52618
+ throw e;
52619
+ }
52620
+ const colIdents = cols.map(quoteIdent).join(", ");
52621
+ const qualified = `${quoteIdent(target.schema)}.${quoteIdent(target.name)}`;
52622
+ const batchRows = Math.max(1, Math.min(1000, Math.floor(MAX_PARAMS_PER_INSERT / cols.length)));
52623
+ return {
52624
+ batchRows,
52625
+ async loadBatch(rows) {
52626
+ for (let i = 0; i < rows.length; i += batchRows) {
52627
+ const batch = rows.slice(i, i + batchRows);
52628
+ const params = [];
52629
+ const tuples = batch.map((row, r) => {
52630
+ const placeholders = cols.map((c, ci) => `$${r * cols.length + ci + 1}`);
52631
+ cols.forEach(c => params.push(coerce(row[c])));
52632
+ return `(${placeholders.join(", ")})`;
52633
+ });
52634
+ await pg.execute(`insert into ${qualified} (${colIdents}) values ${tuples.join(", ")}`, {
52635
+ params
52636
+ });
52637
+ }
52638
+ },
52639
+ async close() {
52640
+ await pg.close();
52619
52641
  }
52642
+ };
52643
+ }
52644
+ async function loadRowsIntoPostgres(args) {
52645
+ const loader = await createPgLoader(args);
52646
+ try {
52647
+ await loader.loadBatch(args.rows);
52620
52648
  }
52621
52649
  finally {
52622
- await pg.close();
52650
+ await loader.close();
52623
52651
  }
52624
52652
  }
52625
52653
 
52654
+ var __asyncValues = (undefined && undefined.__asyncValues) || function (o) {
52655
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
52656
+ var m = o[Symbol.asyncIterator], i;
52657
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
52658
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
52659
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
52660
+ };
52626
52661
  const DEFAULT_ROW_CAP$1 = 1000000;
52627
52662
  const DEFAULT_BYTE_CAP$1 = 512 * 1024 * 1024;
52628
52663
  function coerce(v) {
52664
+ var _a;
52629
52665
  if (v === null || v === undefined) {
52630
52666
  return null;
52631
52667
  }
52632
- if (typeof v === "object" && v !== null && "value" in v) {
52633
- return v.value;
52668
+ if (typeof v === "object") {
52669
+ if ("value" in v) {
52670
+ return v.value;
52671
+ }
52672
+ if (((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === "Big" ||
52673
+ (typeof v.s === "number" && typeof v.e === "number" && Array.isArray(v.c))) {
52674
+ return v.toString();
52675
+ }
52634
52676
  }
52635
52677
  return v;
52636
52678
  }
52637
52679
  async function runBigQueryExtract(args) {
52638
- var _a, _b;
52680
+ var e_1, _a;
52681
+ var _b, _c, _d;
52639
52682
  const { spec, target, connectionCredentials } = args;
52640
52683
  if ((spec.platform || "bigquery") !== "bigquery") {
52641
52684
  throw new Error(`bigquery runner-extract got a "${spec.platform}" source.`);
@@ -52654,26 +52697,57 @@ async function runBigQueryExtract(args) {
52654
52697
  accessToken: conn.accessToken,
52655
52698
  credentials: conn.credentials
52656
52699
  }));
52657
- const rowCap = (_a = args.rowCap) !== null && _a !== void 0 ? _a : DEFAULT_ROW_CAP$1;
52658
- const byteCap = (_b = args.byteCap) !== null && _b !== void 0 ? _b : DEFAULT_BYTE_CAP$1;
52700
+ const rowCap = (_b = args.rowCap) !== null && _b !== void 0 ? _b : DEFAULT_ROW_CAP$1;
52701
+ const byteCap = (_c = args.byteCap) !== null && _c !== void 0 ? _c : DEFAULT_BYTE_CAP$1;
52659
52702
  const colList = cols.map(c => "`" + c + "`").join(", ");
52660
52703
  const fqn = "`" + `${spec.project}.${spec.dataset}.${spec.sourceName}` + "`";
52661
- const { rows } = await bq.execute(`select ${colList} from ${fqn}`, {
52662
- rowLimit: rowCap,
52663
- byteLimit: byteCap
52664
- });
52665
- if (rows.length >= rowCap) {
52666
- console.warn(`runner-extract: ${target.schema}.${target.name} truncated at ${rowCap} rows (source is larger).`);
52667
- }
52668
- await loadRowsIntoPostgres({
52704
+ const loader = await createPgLoader({
52669
52705
  pg: args.pg,
52670
52706
  target,
52671
52707
  columnTypes: spec.columnTypes,
52672
- rows,
52673
52708
  coerce,
52674
52709
  disableSslForTestsOnly: args.disableSslForTestsOnly
52675
52710
  });
52676
- return { rowCount: rows.length };
52711
+ let rowCount = 0;
52712
+ let bytes = 0;
52713
+ let truncated = false;
52714
+ try {
52715
+ const stream = bq.queryStream(`select ${colList} from ${fqn}`);
52716
+ let batch = [];
52717
+ try {
52718
+ for (var _e = __asyncValues(stream), _f; _f = await _e.next(), !_f.done;) {
52719
+ const row = _f.value;
52720
+ batch.push(row);
52721
+ rowCount++;
52722
+ bytes += Buffer.byteLength((_d = JSON.stringify(row)) !== null && _d !== void 0 ? _d : "", "utf8");
52723
+ if (rowCount >= rowCap || bytes >= byteCap) {
52724
+ truncated = true;
52725
+ break;
52726
+ }
52727
+ if (batch.length >= loader.batchRows) {
52728
+ await loader.loadBatch(batch);
52729
+ batch = [];
52730
+ }
52731
+ }
52732
+ }
52733
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
52734
+ finally {
52735
+ try {
52736
+ if (_f && !_f.done && (_a = _e.return)) await _a.call(_e);
52737
+ }
52738
+ finally { if (e_1) throw e_1.error; }
52739
+ }
52740
+ if (batch.length > 0) {
52741
+ await loader.loadBatch(batch);
52742
+ }
52743
+ }
52744
+ finally {
52745
+ await loader.close();
52746
+ }
52747
+ if (truncated) {
52748
+ console.warn(`runner-extract: ${target.schema}.${target.name} truncated at ${rowCount} rows / ${bytes} bytes (source is larger).`);
52749
+ }
52750
+ return { rowCount };
52677
52751
  }
52678
52752
 
52679
52753
  class MySqlPoolExecutor {
@@ -53501,6 +53575,8 @@ class Runner {
53501
53575
  this.stopped = false;
53502
53576
  this.cancelled = false;
53503
53577
  this.timedOut = false;
53578
+ this.runningExtracts = 0;
53579
+ this.extractWaiters = [];
53504
53580
  this.allActionTargets = new Set(graph.actions.map(action => targetStringifier.stringify(action.target)));
53505
53581
  this.runResult = Object.assign({ actions: [] }, partiallyExecutedRunResult);
53506
53582
  this.warehouseStateByTarget = new Map();
@@ -53515,6 +53591,21 @@ class Runner {
53515
53591
  this.eEmitter = new EventEmitter__default["default"]();
53516
53592
  this.eEmitter.setMaxListeners(0);
53517
53593
  }
53594
+ async acquireExtractSlot() {
53595
+ if (this.runningExtracts < Runner.MAX_CONCURRENT_EXTRACTS) {
53596
+ this.runningExtracts++;
53597
+ return;
53598
+ }
53599
+ await new Promise(resolve => this.extractWaiters.push(resolve));
53600
+ this.runningExtracts++;
53601
+ }
53602
+ releaseExtractSlot() {
53603
+ this.runningExtracts--;
53604
+ const next = this.extractWaiters.shift();
53605
+ if (next) {
53606
+ next();
53607
+ }
53608
+ }
53518
53609
  onChange(listener) {
53519
53610
  this.changeListeners.push(listener);
53520
53611
  return this;
@@ -53830,12 +53921,18 @@ class Runner {
53830
53921
  const extractor = ((_m = action === null || action === void 0 ? void 0 : action.extract) === null || _m === void 0 ? void 0 : _m.platform) === "mysql"
53831
53922
  ? this.executionOptions.mysqlExtract || runMysqlExtract
53832
53923
  : this.executionOptions.bigQueryExtract || runBigQueryExtract;
53833
- await extractor({
53834
- spec: action === null || action === void 0 ? void 0 : action.extract,
53835
- target: action === null || action === void 0 ? void 0 : action.target,
53836
- pg: this.executionOptions.warehouseConnection,
53837
- connectionCredentials: this.executionOptions.connectionCredentials || {}
53838
- });
53924
+ await this.acquireExtractSlot();
53925
+ try {
53926
+ await extractor({
53927
+ spec: action === null || action === void 0 ? void 0 : action.extract,
53928
+ target: action === null || action === void 0 ? void 0 : action.target,
53929
+ pg: this.executionOptions.warehouseConnection,
53930
+ connectionCredentials: this.executionOptions.connectionCredentials || {}
53931
+ });
53932
+ }
53933
+ finally {
53934
+ this.releaseExtractSlot();
53935
+ }
53839
53936
  taskResult.status = sqlanvil.TaskResult.ExecutionStatus.SUCCESSFUL;
53840
53937
  }
53841
53938
  catch (e) {
@@ -53883,6 +53980,7 @@ class Runner {
53883
53980
  return taskResult.status;
53884
53981
  }
53885
53982
  }
53983
+ Runner.MAX_CONCURRENT_EXTRACTS = 4;
53886
53984
  class Timer {
53887
53985
  constructor(startTimeMillis) {
53888
53986
  this.startTimeMillis = startTimeMillis;
@@ -54182,12 +54280,18 @@ async function writeParquet(rows, outPath, columns) {
54182
54280
  await fs__namespace.remove(tmp).catch(() => undefined);
54183
54281
  }
54184
54282
  }
54283
+ const normalizeValue = (v) => typeof v === "bigint"
54284
+ ? v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER)
54285
+ ? Number(v)
54286
+ : v.toString()
54287
+ : v;
54185
54288
  async function queryParquet(sql, views) {
54186
54289
  return withDuckdb(async (conn) => {
54187
54290
  for (const view of views) {
54188
54291
  await runAsync(conn, `create view ${view.name} as select * from read_parquet('${view.glob}')`);
54189
54292
  }
54190
- return allAsync(conn, sql);
54293
+ const rows = await allAsync(conn, sql);
54294
+ return rows.map((row) => Object.fromEntries(Object.entries(row).map(([k, v]) => [k, normalizeValue(v)])));
54191
54295
  });
54192
54296
  }
54193
54297
 
@@ -56508,6 +56612,8 @@ function createYargsCli(cli) {
56508
56612
  for (const command of cli.commands) {
56509
56613
  yargsChain = yargsChain.command(command.format, command.description, (yargsChainer) => createOptionsChain(yargsChainer, command), async (argv) => {
56510
56614
  const exitCode = await command.processFn(argv);
56615
+ await new Promise(resolve => process.stdout.write("", () => resolve()));
56616
+ await new Promise(resolve => process.stderr.write("", () => resolve()));
56511
56617
  process.exit(exitCode);
56512
56618
  });
56513
56619
  }
package/package.json CHANGED
@@ -71,7 +71,7 @@
71
71
  "bin": {
72
72
  "sqlanvil": "bundle.js"
73
73
  },
74
- "version": "1.27.0",
74
+ "version": "1.27.2",
75
75
  "name": "@sqlanvil/cli",
76
76
  "description": "sqlanvil command line interface.",
77
77
  "main": "bundle.js"