@sqlanvil/cli 1.4.0 → 1.5.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/bundle.js CHANGED
@@ -35,6 +35,7 @@ var EventEmitter = require('events');
35
35
  var Long = require('long');
36
36
  var promisePoolExecutor = require('promise-pool-executor');
37
37
  var sizeof = require('object-sizeof');
38
+ var mysql = require('mysql2/promise');
38
39
  var QueryStream = require('pg-query-stream');
39
40
  var readlineSync = require('readline-sync');
40
41
  var untildify = require('untildify');
@@ -78,6 +79,7 @@ var pg__namespace = /*#__PURE__*/_interopNamespace(pg);
78
79
  var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
79
80
  var Long__default = /*#__PURE__*/_interopDefaultLegacy(Long);
80
81
  var sizeof__default = /*#__PURE__*/_interopDefaultLegacy(sizeof);
82
+ var mysql__namespace = /*#__PURE__*/_interopNamespace(mysql);
81
83
  var QueryStream__default = /*#__PURE__*/_interopDefaultLegacy(QueryStream);
82
84
  var readlineSync__namespace = /*#__PURE__*/_interopNamespace(readlineSync);
83
85
  var untildify__default = /*#__PURE__*/_interopDefaultLegacy(untildify);
@@ -14949,6 +14951,327 @@ const sqlanvil = $root.sqlanvil = (() => {
14949
14951
  return SupabaseConnection;
14950
14952
  })();
14951
14953
 
14954
+ sqlanvil.MysqlConnection = (function() {
14955
+
14956
+ /**
14957
+ * Properties of a MysqlConnection.
14958
+ * @memberof sqlanvil
14959
+ * @interface IMysqlConnection
14960
+ * @property {string|null} [host] MysqlConnection host
14961
+ * @property {number|null} [port] MysqlConnection port
14962
+ * @property {string|null} [database] MysqlConnection database
14963
+ * @property {string|null} [user] MysqlConnection user
14964
+ * @property {string|null} [password] MysqlConnection password
14965
+ * @property {string|null} [sslMode] MysqlConnection sslMode
14966
+ */
14967
+
14968
+ /**
14969
+ * Constructs a new MysqlConnection.
14970
+ * @memberof sqlanvil
14971
+ * @classdesc Represents a MysqlConnection.
14972
+ * @implements IMysqlConnection
14973
+ * @constructor
14974
+ * @param {sqlanvil.IMysqlConnection=} [properties] Properties to set
14975
+ */
14976
+ function MysqlConnection(properties) {
14977
+ if (properties)
14978
+ for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
14979
+ if (properties[keys[i]] != null)
14980
+ this[keys[i]] = properties[keys[i]];
14981
+ }
14982
+
14983
+ /**
14984
+ * MysqlConnection host.
14985
+ * @member {string} host
14986
+ * @memberof sqlanvil.MysqlConnection
14987
+ * @instance
14988
+ */
14989
+ MysqlConnection.prototype.host = "";
14990
+
14991
+ /**
14992
+ * MysqlConnection port.
14993
+ * @member {number} port
14994
+ * @memberof sqlanvil.MysqlConnection
14995
+ * @instance
14996
+ */
14997
+ MysqlConnection.prototype.port = 0;
14998
+
14999
+ /**
15000
+ * MysqlConnection database.
15001
+ * @member {string} database
15002
+ * @memberof sqlanvil.MysqlConnection
15003
+ * @instance
15004
+ */
15005
+ MysqlConnection.prototype.database = "";
15006
+
15007
+ /**
15008
+ * MysqlConnection user.
15009
+ * @member {string} user
15010
+ * @memberof sqlanvil.MysqlConnection
15011
+ * @instance
15012
+ */
15013
+ MysqlConnection.prototype.user = "";
15014
+
15015
+ /**
15016
+ * MysqlConnection password.
15017
+ * @member {string} password
15018
+ * @memberof sqlanvil.MysqlConnection
15019
+ * @instance
15020
+ */
15021
+ MysqlConnection.prototype.password = "";
15022
+
15023
+ /**
15024
+ * MysqlConnection sslMode.
15025
+ * @member {string} sslMode
15026
+ * @memberof sqlanvil.MysqlConnection
15027
+ * @instance
15028
+ */
15029
+ MysqlConnection.prototype.sslMode = "";
15030
+
15031
+ /**
15032
+ * Creates a new MysqlConnection instance using the specified properties.
15033
+ * @function create
15034
+ * @memberof sqlanvil.MysqlConnection
15035
+ * @static
15036
+ * @param {sqlanvil.IMysqlConnection=} [properties] Properties to set
15037
+ * @returns {sqlanvil.MysqlConnection} MysqlConnection instance
15038
+ */
15039
+ MysqlConnection.create = function create(properties) {
15040
+ return new MysqlConnection(properties);
15041
+ };
15042
+
15043
+ /**
15044
+ * Encodes the specified MysqlConnection message. Does not implicitly {@link sqlanvil.MysqlConnection.verify|verify} messages.
15045
+ * @function encode
15046
+ * @memberof sqlanvil.MysqlConnection
15047
+ * @static
15048
+ * @param {sqlanvil.IMysqlConnection} message MysqlConnection message or plain object to encode
15049
+ * @param {$protobuf.Writer} [writer] Writer to encode to
15050
+ * @returns {$protobuf.Writer} Writer
15051
+ */
15052
+ MysqlConnection.encode = function encode(message, writer) {
15053
+ if (!writer)
15054
+ writer = $Writer.create();
15055
+ if (message.host != null && Object.hasOwnProperty.call(message, "host"))
15056
+ writer.uint32(/* id 1, wireType 2 =*/10).string(message.host);
15057
+ if (message.port != null && Object.hasOwnProperty.call(message, "port"))
15058
+ writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.port);
15059
+ if (message.database != null && Object.hasOwnProperty.call(message, "database"))
15060
+ writer.uint32(/* id 3, wireType 2 =*/26).string(message.database);
15061
+ if (message.user != null && Object.hasOwnProperty.call(message, "user"))
15062
+ writer.uint32(/* id 4, wireType 2 =*/34).string(message.user);
15063
+ if (message.password != null && Object.hasOwnProperty.call(message, "password"))
15064
+ writer.uint32(/* id 5, wireType 2 =*/42).string(message.password);
15065
+ if (message.sslMode != null && Object.hasOwnProperty.call(message, "sslMode"))
15066
+ writer.uint32(/* id 6, wireType 2 =*/50).string(message.sslMode);
15067
+ return writer;
15068
+ };
15069
+
15070
+ /**
15071
+ * Encodes the specified MysqlConnection message, length delimited. Does not implicitly {@link sqlanvil.MysqlConnection.verify|verify} messages.
15072
+ * @function encodeDelimited
15073
+ * @memberof sqlanvil.MysqlConnection
15074
+ * @static
15075
+ * @param {sqlanvil.IMysqlConnection} message MysqlConnection message or plain object to encode
15076
+ * @param {$protobuf.Writer} [writer] Writer to encode to
15077
+ * @returns {$protobuf.Writer} Writer
15078
+ */
15079
+ MysqlConnection.encodeDelimited = function encodeDelimited(message, writer) {
15080
+ return this.encode(message, writer).ldelim();
15081
+ };
15082
+
15083
+ /**
15084
+ * Decodes a MysqlConnection message from the specified reader or buffer.
15085
+ * @function decode
15086
+ * @memberof sqlanvil.MysqlConnection
15087
+ * @static
15088
+ * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
15089
+ * @param {number} [length] Message length if known beforehand
15090
+ * @returns {sqlanvil.MysqlConnection} MysqlConnection
15091
+ * @throws {Error} If the payload is not a reader or valid buffer
15092
+ * @throws {$protobuf.util.ProtocolError} If required fields are missing
15093
+ */
15094
+ MysqlConnection.decode = function decode(reader, length, error) {
15095
+ if (!(reader instanceof $Reader))
15096
+ reader = $Reader.create(reader);
15097
+ let end = length === undefined ? reader.len : reader.pos + length, message = new $root.sqlanvil.MysqlConnection();
15098
+ while (reader.pos < end) {
15099
+ let tag = reader.uint32();
15100
+ if (tag === error)
15101
+ break;
15102
+ switch (tag >>> 3) {
15103
+ case 1: {
15104
+ message.host = reader.string();
15105
+ break;
15106
+ }
15107
+ case 2: {
15108
+ message.port = reader.uint32();
15109
+ break;
15110
+ }
15111
+ case 3: {
15112
+ message.database = reader.string();
15113
+ break;
15114
+ }
15115
+ case 4: {
15116
+ message.user = reader.string();
15117
+ break;
15118
+ }
15119
+ case 5: {
15120
+ message.password = reader.string();
15121
+ break;
15122
+ }
15123
+ case 6: {
15124
+ message.sslMode = reader.string();
15125
+ break;
15126
+ }
15127
+ default:
15128
+ reader.skipType(tag & 7);
15129
+ break;
15130
+ }
15131
+ }
15132
+ return message;
15133
+ };
15134
+
15135
+ /**
15136
+ * Decodes a MysqlConnection message from the specified reader or buffer, length delimited.
15137
+ * @function decodeDelimited
15138
+ * @memberof sqlanvil.MysqlConnection
15139
+ * @static
15140
+ * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
15141
+ * @returns {sqlanvil.MysqlConnection} MysqlConnection
15142
+ * @throws {Error} If the payload is not a reader or valid buffer
15143
+ * @throws {$protobuf.util.ProtocolError} If required fields are missing
15144
+ */
15145
+ MysqlConnection.decodeDelimited = function decodeDelimited(reader) {
15146
+ if (!(reader instanceof $Reader))
15147
+ reader = new $Reader(reader);
15148
+ return this.decode(reader, reader.uint32());
15149
+ };
15150
+
15151
+ /**
15152
+ * Verifies a MysqlConnection message.
15153
+ * @function verify
15154
+ * @memberof sqlanvil.MysqlConnection
15155
+ * @static
15156
+ * @param {Object.<string,*>} message Plain object to verify
15157
+ * @returns {string|null} `null` if valid, otherwise the reason why it is not
15158
+ */
15159
+ MysqlConnection.verify = function verify(message) {
15160
+ if (typeof message !== "object" || message === null)
15161
+ return "object expected";
15162
+ if (message.host != null && message.hasOwnProperty("host"))
15163
+ if (!$util.isString(message.host))
15164
+ return "host: string expected";
15165
+ if (message.port != null && message.hasOwnProperty("port"))
15166
+ if (!$util.isInteger(message.port))
15167
+ return "port: integer expected";
15168
+ if (message.database != null && message.hasOwnProperty("database"))
15169
+ if (!$util.isString(message.database))
15170
+ return "database: string expected";
15171
+ if (message.user != null && message.hasOwnProperty("user"))
15172
+ if (!$util.isString(message.user))
15173
+ return "user: string expected";
15174
+ if (message.password != null && message.hasOwnProperty("password"))
15175
+ if (!$util.isString(message.password))
15176
+ return "password: string expected";
15177
+ if (message.sslMode != null && message.hasOwnProperty("sslMode"))
15178
+ if (!$util.isString(message.sslMode))
15179
+ return "sslMode: string expected";
15180
+ return null;
15181
+ };
15182
+
15183
+ /**
15184
+ * Creates a MysqlConnection message from a plain object. Also converts values to their respective internal types.
15185
+ * @function fromObject
15186
+ * @memberof sqlanvil.MysqlConnection
15187
+ * @static
15188
+ * @param {Object.<string,*>} object Plain object
15189
+ * @returns {sqlanvil.MysqlConnection} MysqlConnection
15190
+ */
15191
+ MysqlConnection.fromObject = function fromObject(object) {
15192
+ if (object instanceof $root.sqlanvil.MysqlConnection)
15193
+ return object;
15194
+ let message = new $root.sqlanvil.MysqlConnection();
15195
+ if (object.host != null)
15196
+ message.host = String(object.host);
15197
+ if (object.port != null)
15198
+ message.port = object.port >>> 0;
15199
+ if (object.database != null)
15200
+ message.database = String(object.database);
15201
+ if (object.user != null)
15202
+ message.user = String(object.user);
15203
+ if (object.password != null)
15204
+ message.password = String(object.password);
15205
+ if (object.sslMode != null)
15206
+ message.sslMode = String(object.sslMode);
15207
+ return message;
15208
+ };
15209
+
15210
+ /**
15211
+ * Creates a plain object from a MysqlConnection message. Also converts values to other types if specified.
15212
+ * @function toObject
15213
+ * @memberof sqlanvil.MysqlConnection
15214
+ * @static
15215
+ * @param {sqlanvil.MysqlConnection} message MysqlConnection
15216
+ * @param {$protobuf.IConversionOptions} [options] Conversion options
15217
+ * @returns {Object.<string,*>} Plain object
15218
+ */
15219
+ MysqlConnection.toObject = function toObject(message, options) {
15220
+ if (!options)
15221
+ options = {};
15222
+ let object = {};
15223
+ if (options.defaults) {
15224
+ object.host = "";
15225
+ object.port = 0;
15226
+ object.database = "";
15227
+ object.user = "";
15228
+ object.password = "";
15229
+ object.sslMode = "";
15230
+ }
15231
+ if (message.host != null && message.hasOwnProperty("host"))
15232
+ object.host = message.host;
15233
+ if (message.port != null && message.hasOwnProperty("port"))
15234
+ object.port = message.port;
15235
+ if (message.database != null && message.hasOwnProperty("database"))
15236
+ object.database = message.database;
15237
+ if (message.user != null && message.hasOwnProperty("user"))
15238
+ object.user = message.user;
15239
+ if (message.password != null && message.hasOwnProperty("password"))
15240
+ object.password = message.password;
15241
+ if (message.sslMode != null && message.hasOwnProperty("sslMode"))
15242
+ object.sslMode = message.sslMode;
15243
+ return object;
15244
+ };
15245
+
15246
+ /**
15247
+ * Converts this MysqlConnection to JSON.
15248
+ * @function toJSON
15249
+ * @memberof sqlanvil.MysqlConnection
15250
+ * @instance
15251
+ * @returns {Object.<string,*>} JSON object
15252
+ */
15253
+ MysqlConnection.prototype.toJSON = function toJSON() {
15254
+ return this.constructor.toObject(this, $protobuf__namespace.util.toJSONOptions);
15255
+ };
15256
+
15257
+ /**
15258
+ * Gets the default type url for MysqlConnection
15259
+ * @function getTypeUrl
15260
+ * @memberof sqlanvil.MysqlConnection
15261
+ * @static
15262
+ * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
15263
+ * @returns {string} The default type url
15264
+ */
15265
+ MysqlConnection.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
15266
+ if (typeUrlPrefix === undefined) {
15267
+ typeUrlPrefix = "type.googleapis.com";
15268
+ }
15269
+ return typeUrlPrefix + "/sqlanvil.MysqlConnection";
15270
+ };
15271
+
15272
+ return MysqlConnection;
15273
+ })();
15274
+
14952
15275
  sqlanvil.WarehouseConfig = (function() {
14953
15276
 
14954
15277
  /**
@@ -14958,6 +15281,7 @@ const sqlanvil = $root.sqlanvil = (() => {
14958
15281
  * @property {sqlanvil.IBigQueryConnection|null} [bigquery] WarehouseConfig bigquery
14959
15282
  * @property {sqlanvil.IPostgresConnection|null} [postgres] WarehouseConfig postgres
14960
15283
  * @property {sqlanvil.ISupabaseConnection|null} [supabase] WarehouseConfig supabase
15284
+ * @property {sqlanvil.IMysqlConnection|null} [mysql] WarehouseConfig mysql
14961
15285
  */
14962
15286
 
14963
15287
  /**
@@ -14999,17 +15323,25 @@ const sqlanvil = $root.sqlanvil = (() => {
14999
15323
  */
15000
15324
  WarehouseConfig.prototype.supabase = null;
15001
15325
 
15326
+ /**
15327
+ * WarehouseConfig mysql.
15328
+ * @member {sqlanvil.IMysqlConnection|null|undefined} mysql
15329
+ * @memberof sqlanvil.WarehouseConfig
15330
+ * @instance
15331
+ */
15332
+ WarehouseConfig.prototype.mysql = null;
15333
+
15002
15334
  // OneOf field names bound to virtual getters and setters
15003
15335
  let $oneOfFields;
15004
15336
 
15005
15337
  /**
15006
15338
  * WarehouseConfig connection.
15007
- * @member {"bigquery"|"postgres"|"supabase"|undefined} connection
15339
+ * @member {"bigquery"|"postgres"|"supabase"|"mysql"|undefined} connection
15008
15340
  * @memberof sqlanvil.WarehouseConfig
15009
15341
  * @instance
15010
15342
  */
15011
15343
  Object.defineProperty(WarehouseConfig.prototype, "connection", {
15012
- get: $util.oneOfGetter($oneOfFields = ["bigquery", "postgres", "supabase"]),
15344
+ get: $util.oneOfGetter($oneOfFields = ["bigquery", "postgres", "supabase", "mysql"]),
15013
15345
  set: $util.oneOfSetter($oneOfFields)
15014
15346
  });
15015
15347
 
@@ -15043,6 +15375,8 @@ const sqlanvil = $root.sqlanvil = (() => {
15043
15375
  $root.sqlanvil.PostgresConnection.encode(message.postgres, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
15044
15376
  if (message.supabase != null && Object.hasOwnProperty.call(message, "supabase"))
15045
15377
  $root.sqlanvil.SupabaseConnection.encode(message.supabase, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
15378
+ if (message.mysql != null && Object.hasOwnProperty.call(message, "mysql"))
15379
+ $root.sqlanvil.MysqlConnection.encode(message.mysql, writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim();
15046
15380
  return writer;
15047
15381
  };
15048
15382
 
@@ -15091,6 +15425,10 @@ const sqlanvil = $root.sqlanvil = (() => {
15091
15425
  message.supabase = $root.sqlanvil.SupabaseConnection.decode(reader, reader.uint32());
15092
15426
  break;
15093
15427
  }
15428
+ case 4: {
15429
+ message.mysql = $root.sqlanvil.MysqlConnection.decode(reader, reader.uint32());
15430
+ break;
15431
+ }
15094
15432
  default:
15095
15433
  reader.skipType(tag & 7);
15096
15434
  break;
@@ -15155,6 +15493,16 @@ const sqlanvil = $root.sqlanvil = (() => {
15155
15493
  return "supabase." + error;
15156
15494
  }
15157
15495
  }
15496
+ if (message.mysql != null && message.hasOwnProperty("mysql")) {
15497
+ if (properties.connection === 1)
15498
+ return "connection: multiple values";
15499
+ properties.connection = 1;
15500
+ {
15501
+ let error = $root.sqlanvil.MysqlConnection.verify(message.mysql);
15502
+ if (error)
15503
+ return "mysql." + error;
15504
+ }
15505
+ }
15158
15506
  return null;
15159
15507
  };
15160
15508
 
@@ -15185,6 +15533,11 @@ const sqlanvil = $root.sqlanvil = (() => {
15185
15533
  throw TypeError(".sqlanvil.WarehouseConfig.supabase: object expected");
15186
15534
  message.supabase = $root.sqlanvil.SupabaseConnection.fromObject(object.supabase);
15187
15535
  }
15536
+ if (object.mysql != null) {
15537
+ if (typeof object.mysql !== "object")
15538
+ throw TypeError(".sqlanvil.WarehouseConfig.mysql: object expected");
15539
+ message.mysql = $root.sqlanvil.MysqlConnection.fromObject(object.mysql);
15540
+ }
15188
15541
  return message;
15189
15542
  };
15190
15543
 
@@ -15216,6 +15569,11 @@ const sqlanvil = $root.sqlanvil = (() => {
15216
15569
  if (options.oneofs)
15217
15570
  object.connection = "supabase";
15218
15571
  }
15572
+ if (message.mysql != null && message.hasOwnProperty("mysql")) {
15573
+ object.mysql = $root.sqlanvil.MysqlConnection.toObject(message.mysql, options);
15574
+ if (options.oneofs)
15575
+ object.connection = "mysql";
15576
+ }
15219
15577
  return object;
15220
15578
  };
15221
15579
 
@@ -37904,6 +38262,9 @@ class CompilationSql {
37904
38262
  }
37905
38263
  return `"${database}"."${schema}"."${name}"`;
37906
38264
  }
38265
+ if (this.warehouse === "mysql") {
38266
+ return `\`${schema}\`.\`${name}\``;
38267
+ }
37907
38268
  if (!database) {
37908
38269
  return `\`${schema}.${name}\``;
37909
38270
  }
@@ -37920,6 +38281,9 @@ class CompilationSql {
37920
38281
  if (this.warehouse === "postgres" || this.warehouse === "supabase") {
37921
38282
  return `"${col.replace(/"/g, '""')}"`;
37922
38283
  }
38284
+ if (this.warehouse === "mysql") {
38285
+ return `\`${col.replace(/`/g, "``")}\``;
38286
+ }
37923
38287
  return col;
37924
38288
  };
37925
38289
  const commaSeparatedColumns = indexCols.map(quoteCol).join(", ");
@@ -38265,6 +38629,89 @@ when not matched then
38265
38629
  }
38266
38630
  }
38267
38631
 
38632
+ class MysqlExecutionSql {
38633
+ constructor(project, sqlanvilCoreVersion, uniqueIdGenerator = () => Math.random().toString(36).substring(2)) {
38634
+ this.project = project;
38635
+ this.sqlanvilCoreVersion = sqlanvilCoreVersion;
38636
+ this.uniqueIdGenerator = uniqueIdGenerator;
38637
+ this.CompilationSql = new CompilationSql(project, sqlanvilCoreVersion);
38638
+ }
38639
+ resolveTarget(target) {
38640
+ return this.CompilationSql.resolveTarget(target);
38641
+ }
38642
+ dropIfExists(target, type) {
38643
+ if (type === sqlanvil.TableMetadata.Type.VIEW) {
38644
+ return `drop view if exists ${this.resolveTarget(target)}`;
38645
+ }
38646
+ return `drop table if exists ${this.resolveTarget(target)}`;
38647
+ }
38648
+ publishTasks(table, runConfig, tableMetadata) {
38649
+ const tasks = new Tasks();
38650
+ const target = this.resolveTarget(table.target);
38651
+ if (table.enumType === sqlanvil.TableType.VIEW) {
38652
+ if (table.materialized) {
38653
+ throw new Error(`Materialized views are not supported on mysql (action ${target}). ` +
38654
+ `Use a table, or emulate refresh via operations.`);
38655
+ }
38656
+ tasks.add(Task.statement(`create or replace view ${target} as ${table.query}`));
38657
+ return tasks;
38658
+ }
38659
+ if (table.enumType === sqlanvil.TableType.INCREMENTAL) {
38660
+ const fresh = !this.shouldWriteIncrementally(table, runConfig, tableMetadata);
38661
+ if (fresh) {
38662
+ tasks.add(Task.statement(this.dropIfExists(table.target, sqlanvil.TableMetadata.Type.TABLE)));
38663
+ tasks.add(Task.statement(`create table ${target} as ${table.query}`));
38664
+ if (table.uniqueKey && table.uniqueKey.length > 0) {
38665
+ const idx = `uq_${table.target.schema}_${table.target.name}`.slice(0, 63);
38666
+ const cols = table.uniqueKey.map(k => `\`${k}\``).join(", ");
38667
+ tasks.add(Task.statement(`alter table ${target} add unique index \`${idx}\` (${cols})`));
38668
+ }
38669
+ }
38670
+ else {
38671
+ tasks.add(Task.statement(this.upsertInto(table, tableMetadata)));
38672
+ }
38673
+ return tasks;
38674
+ }
38675
+ tasks.add(Task.statement(this.dropIfExists(table.target, sqlanvil.TableMetadata.Type.TABLE)));
38676
+ tasks.add(Task.statement(`create table ${target} as ${table.query}`));
38677
+ return tasks;
38678
+ }
38679
+ assertTasks(assertion, projectConfig) {
38680
+ const tasks = new Tasks();
38681
+ const target = this.resolveTarget(assertion.target);
38682
+ tasks.add(Task.statement(this.dropIfExists(assertion.target, sqlanvil.TableMetadata.Type.VIEW)));
38683
+ tasks.add(Task.statement(`create or replace view ${target} as ${assertion.query}`));
38684
+ tasks.add(Task.assertion(`select sum(1) as row_count from ${target}`));
38685
+ return tasks;
38686
+ }
38687
+ shouldWriteIncrementally(table, runConfig, tableMetadata) {
38688
+ return (!runConfig.fullRefresh &&
38689
+ !!tableMetadata &&
38690
+ tableMetadata.type === sqlanvil.TableMetadata.Type.TABLE);
38691
+ }
38692
+ getIncrementalQuery(table) {
38693
+ return table.incrementalQuery || table.query;
38694
+ }
38695
+ upsertInto(table, tableMetadata) {
38696
+ const target = this.resolveTarget(table.target);
38697
+ const columns = ((tableMetadata === null || tableMetadata === void 0 ? void 0 : tableMetadata.fields) || []).map(f => f.name);
38698
+ const query = this.getIncrementalQuery(table);
38699
+ if (columns.length === 0) {
38700
+ return `insert into ${target} select * from (${query}) as insertions`;
38701
+ }
38702
+ const backticked = columns.map(c => `\`${c}\``);
38703
+ const uniqueKey = table.uniqueKey || [];
38704
+ const updates = uniqueKey.length > 0
38705
+ ? columns
38706
+ .filter(c => !uniqueKey.includes(c))
38707
+ .map(c => `\`${c}\` = values(\`${c}\`)`)
38708
+ .join(", ")
38709
+ : "";
38710
+ const tail = updates.length > 0 ? ` on duplicate key update ${updates}` : "";
38711
+ return `insert into ${target} (${backticked.join(", ")}) select ${backticked.join(", ")} from (${query}) as insertions${tail}`;
38712
+ }
38713
+ }
38714
+
38268
38715
  class PostgresExecutionSql {
38269
38716
  constructor(project, sqlanvilCoreVersion, uniqueIdGenerator = () => Math.random().toString(36).substring(2)) {
38270
38717
  this.project = project;
@@ -38424,9 +38871,16 @@ class PostgresExecutionSql {
38424
38871
  ? ` include (${index.include.map(c => `"${c}"`).join(", ")})`
38425
38872
  : "";
38426
38873
  const where = index.where ? ` where (${index.where})` : "";
38427
- return `create ${unique}index "${index.name}" on ${target} using ${method} (${columns})${include}${where}`;
38874
+ const indexName = index.name || this.defaultIndexName(table.target.name, index.columns, !!index.unique);
38875
+ return `create ${unique}index "${indexName}" on ${target} using ${method} (${columns})${include}${where}`;
38428
38876
  });
38429
38877
  }
38878
+ defaultIndexName(tableName, columns, unique) {
38879
+ const parts = [tableName, ...(columns || [])].filter(Boolean);
38880
+ const base = parts.join("_");
38881
+ const suffix = unique ? "_key" : "_idx";
38882
+ return `${base}${suffix}`.slice(0, 63);
38883
+ }
38430
38884
  indexMethodAsSql(method) {
38431
38885
  switch (method) {
38432
38886
  case sqlanvil.PostgresOptions.Index.Method.HASH:
@@ -38569,6 +39023,9 @@ class ExecutionSql {
38569
39023
  if (warehouse === "postgres" || warehouse === "supabase") {
38570
39024
  this.delegate = new PostgresExecutionSql(project, sqlanvilCoreVersion, uniqueIdGenerator);
38571
39025
  }
39026
+ else if (warehouse === "mysql") {
39027
+ this.delegate = new MysqlExecutionSql(project, sqlanvilCoreVersion, uniqueIdGenerator);
39028
+ }
38572
39029
  else {
38573
39030
  this.delegate = new BigQueryExecutionSql(project, sqlanvilCoreVersion, uniqueIdGenerator);
38574
39031
  }
@@ -38653,7 +39110,7 @@ function collectEvaluationQueries(queryOrAction, concatenate, queryModifier = (q
38653
39110
  .filter(validationQuery => !!validationQuery.query);
38654
39111
  }
38655
39112
 
38656
- const version = "1.4.0";
39113
+ const version = "1.5.0";
38657
39114
  const dataformVersion = "3.0.59";
38658
39115
 
38659
39116
  async function build(compiledGraph, runConfig, dbadapter) {
@@ -38914,6 +39371,13 @@ function read(credentialsPath, warehouse = "bigquery") {
38914
39371
  throw new Error(`Error reading credentials file: ${e.message}`);
38915
39372
  }
38916
39373
  const warehouseCredentials = __rest(credentialsAsJson, ["connections"]);
39374
+ if (warehouse.toLowerCase() === "mysql") {
39375
+ const credentials = verifyObjectMatchesProto(sqlanvil.MysqlConnection, warehouseCredentials);
39376
+ if (!credentials.host) {
39377
+ throw new Error(`Error reading credentials file: the host field is required`);
39378
+ }
39379
+ return credentials;
39380
+ }
38917
39381
  const isPostgres = warehouse.toLowerCase() === "postgres" || warehouse.toLowerCase() === "supabase";
38918
39382
  if (isPostgres) {
38919
39383
  const credentials = verifyObjectMatchesProto(sqlanvil.PostgresConnection, warehouseCredentials);
@@ -38988,6 +39452,17 @@ function postgresCredentialsTemplate(warehouse) {
38988
39452
  };
38989
39453
  return `${JSON.stringify(template, null, 2)}\n`;
38990
39454
  }
39455
+ function mysqlCredentialsTemplate() {
39456
+ const template = {
39457
+ host: "localhost",
39458
+ port: 3306,
39459
+ database: "sqlanvil",
39460
+ user: "root",
39461
+ password: "",
39462
+ sslMode: "disable"
39463
+ };
39464
+ return `${JSON.stringify(template, null, 2)}\n`;
39465
+ }
38991
39466
  async function init(projectDir, projectConfig) {
38992
39467
  const workflowSettingsYamlPath = path__namespace.join(projectDir, "workflow_settings.yaml");
38993
39468
  const packageJsonPath = path__namespace.join(projectDir, "package.json");
@@ -39039,7 +39514,7 @@ async function init(projectDir, projectConfig) {
39039
39514
  fs__namespace$1.writeFileSync(gitignorePath, gitIgnoreContents);
39040
39515
  filesWritten.push(gitignorePath);
39041
39516
  if (!isBigQuery) {
39042
- fs__namespace$1.writeFileSync(path__namespace.join(projectDir, CREDENTIALS_FILENAME), postgresCredentialsTemplate(warehouse));
39517
+ fs__namespace$1.writeFileSync(path__namespace.join(projectDir, CREDENTIALS_FILENAME), warehouse === "mysql" ? mysqlCredentialsTemplate() : postgresCredentialsTemplate(warehouse));
39043
39518
  filesWritten.push(path__namespace.join(projectDir, CREDENTIALS_FILENAME));
39044
39519
  }
39045
39520
  const definitionsDir = path__namespace.join(projectDir, "definitions");
@@ -40242,11 +40717,11 @@ function convertField(field) {
40242
40717
  });
40243
40718
  }
40244
40719
  else {
40245
- result.primitive = convertFieldType$1(field.type);
40720
+ result.primitive = convertFieldType$2(field.type);
40246
40721
  }
40247
40722
  return sqlanvil.Field.create(result);
40248
40723
  }
40249
- function convertFieldType$1(type) {
40724
+ function convertFieldType$2(type) {
40250
40725
  switch (String(type).toUpperCase()) {
40251
40726
  case "FLOAT":
40252
40727
  case "FLOAT64":
@@ -40319,6 +40794,270 @@ function createBigQueryError(jobMetadata) {
40319
40794
  return error;
40320
40795
  }
40321
40796
 
40797
+ class MySqlPoolExecutor {
40798
+ constructor(config, options) {
40799
+ this.pool = mysql__namespace.createPool(Object.assign(Object.assign({}, config), { connectionLimit: (options === null || options === void 0 ? void 0 : options.concurrencyLimit) || 10, waitForConnections: true, multipleStatements: false }));
40800
+ }
40801
+ async verifyConnection() {
40802
+ const conn = await this.pool.getConnection();
40803
+ try {
40804
+ await conn.query("select 1");
40805
+ }
40806
+ finally {
40807
+ conn.release();
40808
+ }
40809
+ }
40810
+ async withClientLock(callback) {
40811
+ const conn = await this.pool.getConnection();
40812
+ let released = false;
40813
+ const releaseOnce = () => {
40814
+ if (released) {
40815
+ return;
40816
+ }
40817
+ released = true;
40818
+ conn.release();
40819
+ };
40820
+ try {
40821
+ return await callback({
40822
+ execute: async (statement, options = { rowLimit: 1000 }) => {
40823
+ const [rows] = await conn.query(statement, options.params || []);
40824
+ const arr = Array.isArray(rows) ? rows : [];
40825
+ return options.rowLimit && arr.length > options.rowLimit
40826
+ ? arr.slice(0, options.rowLimit)
40827
+ : arr;
40828
+ }
40829
+ });
40830
+ }
40831
+ finally {
40832
+ releaseOnce();
40833
+ }
40834
+ }
40835
+ async close() {
40836
+ await this.pool.end();
40837
+ }
40838
+ }
40839
+ function convertFieldType$1(type) {
40840
+ switch (String(type).toUpperCase()) {
40841
+ case "FLOAT":
40842
+ case "DOUBLE":
40843
+ case "REAL":
40844
+ return sqlanvil.Field.Primitive.FLOAT;
40845
+ case "TINYINT":
40846
+ case "SMALLINT":
40847
+ case "MEDIUMINT":
40848
+ case "INT":
40849
+ case "INTEGER":
40850
+ case "BIGINT":
40851
+ case "YEAR":
40852
+ case "BIT":
40853
+ return sqlanvil.Field.Primitive.INTEGER;
40854
+ case "DECIMAL":
40855
+ case "DEC":
40856
+ case "NUMERIC":
40857
+ case "FIXED":
40858
+ return sqlanvil.Field.Primitive.NUMERIC;
40859
+ case "BOOL":
40860
+ case "BOOLEAN":
40861
+ return sqlanvil.Field.Primitive.BOOLEAN;
40862
+ case "CHAR":
40863
+ case "VARCHAR":
40864
+ case "TINYTEXT":
40865
+ case "TEXT":
40866
+ case "MEDIUMTEXT":
40867
+ case "LONGTEXT":
40868
+ case "ENUM":
40869
+ case "SET":
40870
+ case "JSON":
40871
+ case "TIME":
40872
+ return sqlanvil.Field.Primitive.STRING;
40873
+ case "DATE":
40874
+ return sqlanvil.Field.Primitive.DATE;
40875
+ case "DATETIME":
40876
+ case "TIMESTAMP":
40877
+ return sqlanvil.Field.Primitive.TIMESTAMP;
40878
+ default:
40879
+ return sqlanvil.Field.Primitive.UNKNOWN;
40880
+ }
40881
+ }
40882
+
40883
+ const INTERNAL_SCHEMAS$1 = new Set([
40884
+ "information_schema",
40885
+ "mysql",
40886
+ "performance_schema",
40887
+ "sys"
40888
+ ]);
40889
+ class MySqlDbAdapter {
40890
+ constructor(queryExecutor) {
40891
+ this.queryExecutor = queryExecutor;
40892
+ }
40893
+ static async create(credentials, options) {
40894
+ const sslMode = (credentials.sslMode || "").toLowerCase();
40895
+ const ssl = !(options === null || options === void 0 ? void 0 : options.disableSslForTestsOnly) && sslMode && sslMode !== "disable"
40896
+ ?
40897
+ { rejectUnauthorized: false }
40898
+ : undefined;
40899
+ const queryExecutor = new MySqlPoolExecutor({
40900
+ host: credentials.host,
40901
+ port: credentials.port || 3306,
40902
+ user: credentials.user,
40903
+ password: credentials.password,
40904
+ database: credentials.database || undefined,
40905
+ ssl
40906
+ }, options);
40907
+ try {
40908
+ await queryExecutor.verifyConnection();
40909
+ }
40910
+ catch (e) {
40911
+ await queryExecutor.close().catch(() => undefined);
40912
+ throw new ErrorWithCause(`Could not connect to MySQL at ${credentials.host}:${credentials.port || 3306} ` +
40913
+ `as "${credentials.user}": ${e.message}`, e);
40914
+ }
40915
+ return new MySqlDbAdapter(queryExecutor);
40916
+ }
40917
+ async execute(statement, options = { rowLimit: 1000, byteLimit: 1024 * 1024 }) {
40918
+ return await this.withClientLock(client => client.execute(statement, options));
40919
+ }
40920
+ async executeRaw(statement, options = { rowLimit: 1000 }) {
40921
+ const result = await this.execute(statement, options);
40922
+ return Object.assign(Object.assign({}, result), { schema: [] });
40923
+ }
40924
+ async withClientLock(callback) {
40925
+ return await this.queryExecutor.withClientLock(client => callback({
40926
+ execute: async (stmt, opts = { rowLimit: 1000, byteLimit: 1024 * 1024 }) => {
40927
+ try {
40928
+ const rows = await client.execute(stmt, { params: opts.params, rowLimit: opts.rowLimit });
40929
+ return { rows, metadata: {} };
40930
+ }
40931
+ catch (e) {
40932
+ if (opts.includeQueryInError) {
40933
+ throw new Error(`Error encountered while running "${stmt}": ${e.message}`);
40934
+ }
40935
+ throw new ErrorWithCause(`Error executing mysql query: ${e.message}`, e);
40936
+ }
40937
+ },
40938
+ executeRaw: async (stmt, opts = { rowLimit: 1000 }) => {
40939
+ const positional = opts.params ? Object.values(opts.params) : undefined;
40940
+ const rows = await client.execute(stmt, { params: positional, rowLimit: opts.rowLimit });
40941
+ return { rows, schema: [], metadata: {} };
40942
+ }
40943
+ }));
40944
+ }
40945
+ async evaluate(queryOrAction) {
40946
+ const validationQueries = collectEvaluationQueries(queryOrAction, false, (query) => !!query ? `explain ${query}` : "").map((validationQuery, index) => ({ index, validationQuery }));
40947
+ const validationQueriesWithoutWrappers = collectEvaluationQueries(queryOrAction, false);
40948
+ const queryEvaluations = new Array();
40949
+ for (const { index, validationQuery } of validationQueries) {
40950
+ let evaluationResponse = {
40951
+ status: sqlanvil.QueryEvaluation.QueryEvaluationStatus.SUCCESS
40952
+ };
40953
+ try {
40954
+ await this.execute(validationQuery.query);
40955
+ }
40956
+ catch (e) {
40957
+ evaluationResponse = {
40958
+ status: sqlanvil.QueryEvaluation.QueryEvaluationStatus.FAILURE,
40959
+ error: sqlanvil.QueryEvaluationError.create({
40960
+ message: (e === null || e === void 0 ? void 0 : e.message) ? String(e.message) : String(e)
40961
+ })
40962
+ };
40963
+ }
40964
+ queryEvaluations.push(sqlanvil.QueryEvaluation.create(Object.assign(Object.assign({}, evaluationResponse), { incremental: validationQuery.incremental, query: validationQueriesWithoutWrappers[index].query })));
40965
+ }
40966
+ return queryEvaluations;
40967
+ }
40968
+ async tables(_database, schema) {
40969
+ const params = [];
40970
+ let schemaClause = "";
40971
+ if (schema) {
40972
+ schemaClause = "and table_schema = ?";
40973
+ params.push(schema);
40974
+ }
40975
+ const queryResult = await this.execute(`select table_name, table_schema
40976
+ from information_schema.tables
40977
+ where table_schema not in ('information_schema', 'mysql', 'performance_schema', 'sys')
40978
+ ${schemaClause}`, { params, rowLimit: 10000, includeQueryInError: true });
40979
+ const targets = queryResult.rows.map(row => ({
40980
+ schema: row.table_schema,
40981
+ name: row.table_name
40982
+ }));
40983
+ return await Promise.all(targets.map(target => this.table(target)));
40984
+ }
40985
+ async search(searchText, options = { limit: 1000 }) {
40986
+ const results = await this.execute(`select tables.table_schema as table_schema, tables.table_name as table_name
40987
+ from information_schema.tables as tables
40988
+ left join information_schema.columns columns
40989
+ on tables.table_schema = columns.table_schema
40990
+ and tables.table_name = columns.table_name
40991
+ where tables.table_schema like ?
40992
+ or tables.table_name like ?
40993
+ or columns.column_name like ?
40994
+ group by 1, 2`, {
40995
+ params: [`%${searchText}%`, `%${searchText}%`, `%${searchText}%`],
40996
+ rowLimit: options.limit
40997
+ });
40998
+ return await Promise.all(results.rows.map(row => this.table({
40999
+ schema: row.table_schema,
41000
+ name: row.table_name
41001
+ })));
41002
+ }
41003
+ async table(target) {
41004
+ var _a;
41005
+ const params = [target.schema, target.name];
41006
+ const [tableResults, columnResults] = await Promise.all([
41007
+ this.execute(`select table_type from information_schema.tables
41008
+ where table_schema = ? and table_name = ?`, { params, includeQueryInError: true }),
41009
+ this.execute(`select column_name, data_type, ordinal_position
41010
+ from information_schema.columns
41011
+ where table_schema = ? and table_name = ?
41012
+ order by ordinal_position`, { params, includeQueryInError: true })
41013
+ ]);
41014
+ if (tableResults.rows.length === 0) {
41015
+ return null;
41016
+ }
41017
+ const tableType = String((_a = tableResults.rows[0].table_type) !== null && _a !== void 0 ? _a : tableResults.rows[0].TABLE_TYPE).toUpperCase();
41018
+ return sqlanvil.TableMetadata.create({
41019
+ target,
41020
+ type: tableType === "VIEW" ? sqlanvil.TableMetadata.Type.VIEW : sqlanvil.TableMetadata.Type.TABLE,
41021
+ fields: columnResults.rows.map(row => {
41022
+ var _a, _b;
41023
+ return sqlanvil.Field.create({
41024
+ name: ((_a = row.column_name) !== null && _a !== void 0 ? _a : row.COLUMN_NAME),
41025
+ primitive: convertFieldType$1(((_b = row.data_type) !== null && _b !== void 0 ? _b : row.DATA_TYPE))
41026
+ });
41027
+ })
41028
+ });
41029
+ }
41030
+ async deleteTable(target) {
41031
+ const metadata = await this.table(target);
41032
+ if (!metadata) {
41033
+ return;
41034
+ }
41035
+ const kind = metadata.type === sqlanvil.TableMetadata.Type.VIEW ? "view" : "table";
41036
+ await this.execute(`drop ${kind} if exists \`${target.schema}\`.\`${target.name}\``, {
41037
+ includeQueryInError: true
41038
+ });
41039
+ }
41040
+ async schemas(_database) {
41041
+ const result = await this.execute(`select schema_name from information_schema.schemata`, {
41042
+ includeQueryInError: true
41043
+ });
41044
+ return result.rows
41045
+ .map(row => { var _a; return ((_a = row.schema_name) !== null && _a !== void 0 ? _a : row.SCHEMA_NAME); })
41046
+ .filter(name => !INTERNAL_SCHEMAS$1.has(name));
41047
+ }
41048
+ async createSchema(_database, schema) {
41049
+ await this.execute(`create database if not exists \`${schema}\``, {
41050
+ includeQueryInError: true
41051
+ });
41052
+ }
41053
+ async setMetadata(_action) {
41054
+ return;
41055
+ }
41056
+ async close() {
41057
+ await this.queryExecutor.close();
41058
+ }
41059
+ }
41060
+
40322
41061
  const maybeInitializePg = (() => {
40323
41062
  let initialized = false;
40324
41063
  return () => {
@@ -40347,15 +41086,23 @@ class PgPoolExecutor {
40347
41086
  }
40348
41087
  async withClientLock(callback) {
40349
41088
  const client = await this.pool.connect();
41089
+ let released = false;
41090
+ const releaseOnce = (err) => {
41091
+ if (released) {
41092
+ return;
41093
+ }
41094
+ released = true;
41095
+ try {
41096
+ client.release(err);
41097
+ }
41098
+ catch (e) {
41099
+ console.error("Error thrown when releasing pg.Client", e.message, e.stack);
41100
+ }
41101
+ };
40350
41102
  try {
40351
41103
  client.on("error", err => {
40352
41104
  console.error("pg.Client client error", err.message, err.stack);
40353
- try {
40354
- client.release(err);
40355
- }
40356
- catch (e) {
40357
- console.error("Error thrown when releasing errored pg.Client", e.message, e.stack);
40358
- }
41105
+ releaseOnce(err);
40359
41106
  });
40360
41107
  return await callback({
40361
41108
  execute: async (statement, options = { rowLimit: 1000, byteLimit: 1024 * 1024 }) => {
@@ -40380,12 +41127,7 @@ class PgPoolExecutor {
40380
41127
  }
40381
41128
  });
40382
41129
  query.on("error", err => {
40383
- try {
40384
- client.release(err);
40385
- }
40386
- catch (e) {
40387
- console.error("Error thrown when releasing errored pg.Query", e.message, e.stack);
40388
- }
41130
+ releaseOnce(err);
40389
41131
  reject(err);
40390
41132
  });
40391
41133
  query.on("end", () => {
@@ -40396,12 +41138,7 @@ class PgPoolExecutor {
40396
41138
  });
40397
41139
  }
40398
41140
  finally {
40399
- try {
40400
- client.release();
40401
- }
40402
- catch (e) {
40403
- console.error("Error thrown when releasing ended pg.Client", e.message, e.stack);
40404
- }
41141
+ releaseOnce();
40405
41142
  }
40406
41143
  }
40407
41144
  async close() {
@@ -42100,7 +42837,7 @@ const icebergOption = option("iceberg", {
42100
42837
  const warehouseOption = option("warehouse", {
42101
42838
  describe: "Target warehouse for the new project.",
42102
42839
  type: "string",
42103
- choices: ["bigquery", "postgres", "supabase"],
42840
+ choices: ["bigquery", "postgres", "supabase", "mysql"],
42104
42841
  default: "supabase"
42105
42842
  });
42106
42843
  const testConnectionOptionName = "test-connection";
@@ -42377,6 +43114,9 @@ function runCli() {
42377
43114
  else if (warehouse.toLowerCase() === "postgres") {
42378
43115
  dbadapter = await PostgresDbAdapter.create(readCredentials);
42379
43116
  }
43117
+ else if (warehouse.toLowerCase() === "mysql") {
43118
+ dbadapter = await MySqlDbAdapter.create(readCredentials);
43119
+ }
42380
43120
  else {
42381
43121
  dbadapter = new BigQueryDbAdapter(readCredentials);
42382
43122
  }
@@ -42450,6 +43190,9 @@ function runCli() {
42450
43190
  else if (warehouse.toLowerCase() === "postgres") {
42451
43191
  dbadapter = await PostgresDbAdapter.create(readCredentials);
42452
43192
  }
43193
+ else if (warehouse.toLowerCase() === "mysql") {
43194
+ dbadapter = await MySqlDbAdapter.create(readCredentials);
43195
+ }
42453
43196
  else {
42454
43197
  dbadapter = new BigQueryDbAdapter(readCredentials);
42455
43198
  }