forge-sql-orm 2.0.18 → 2.0.19

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 (33) hide show
  1. package/README.md +95 -4
  2. package/dist/ForgeSQLORM.js +314 -49
  3. package/dist/ForgeSQLORM.js.map +1 -1
  4. package/dist/ForgeSQLORM.mjs +314 -49
  5. package/dist/ForgeSQLORM.mjs.map +1 -1
  6. package/dist/core/ForgeSQLAnalyseOperations.d.ts +250 -0
  7. package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -0
  8. package/dist/core/ForgeSQLORM.d.ts +12 -2
  9. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  10. package/dist/core/ForgeSQLQueryBuilder.d.ts +105 -9
  11. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  12. package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
  13. package/dist/core/SystemTables.d.ts +167 -0
  14. package/dist/core/SystemTables.d.ts.map +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/utils/sqlUtils.d.ts +2 -2
  18. package/dist/utils/sqlUtils.d.ts.map +1 -1
  19. package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
  20. package/dist/webtriggers/dropMigrationWebTrigger.d.ts +2 -4
  21. package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
  22. package/package.json +4 -12
  23. package/src/core/ForgeSQLAnalyseOperations.ts +461 -0
  24. package/src/core/ForgeSQLORM.ts +43 -7
  25. package/src/core/ForgeSQLQueryBuilder.ts +121 -18
  26. package/src/core/ForgeSQLSelectOperations.ts +4 -6
  27. package/src/core/SystemTables.ts +175 -0
  28. package/src/index.ts +1 -0
  29. package/src/utils/forgeDriverProxy.ts +1 -1
  30. package/src/utils/sqlUtils.ts +10 -16
  31. package/src/webtriggers/applyMigrationsWebTrigger.ts +32 -16
  32. package/src/webtriggers/dropMigrationWebTrigger.ts +5 -6
  33. package/src/webtriggers/fetchSchemaWebTrigger.ts +2 -10
@@ -62,7 +62,7 @@ function processForeignKeys(table, foreignKeysSymbol, extraSymbol) {
62
62
  const configBuilderData = extraConfigBuilder(table);
63
63
  if (configBuilderData) {
64
64
  const configBuilders = Array.isArray(configBuilderData) ? configBuilderData : Object.values(configBuilderData).map(
65
- (item) => item.value || item
65
+ (item) => item.value ?? item
66
66
  );
67
67
  configBuilders.forEach((builder) => {
68
68
  if (!builder?.constructor) return;
@@ -97,7 +97,7 @@ function getTableMetadata(table) {
97
97
  const configBuilderData = extraConfigBuilder(table);
98
98
  if (configBuilderData) {
99
99
  const configBuilders = Array.isArray(configBuilderData) ? configBuilderData : Object.values(configBuilderData).map(
100
- (item) => item.value || item
100
+ (item) => item.value ?? item
101
101
  );
102
102
  configBuilders.forEach((builder) => {
103
103
  if (!builder?.constructor) return;
@@ -127,13 +127,9 @@ function getTableMetadata(table) {
127
127
  }
128
128
  function generateDropTableStatements(tables) {
129
129
  const dropStatements = [];
130
- tables.forEach((table) => {
131
- const tableMetadata = getTableMetadata(table);
132
- if (tableMetadata.tableName) {
133
- dropStatements.push(`DROP TABLE IF EXISTS \`${tableMetadata.tableName}\`;`);
134
- }
130
+ tables.forEach((tableName) => {
131
+ dropStatements.push(`DROP TABLE IF EXISTS \`${tableName}\`;`);
135
132
  });
136
- dropStatements.push(`DELETE FROM __migrations;`);
137
133
  return dropStatements;
138
134
  }
139
135
  function mapSelectTableToAlias(table, uniqPrefix, aliasMap) {
@@ -191,9 +187,9 @@ function getAliasFromDrizzleAlias(value) {
191
187
  const aliasNameChunk = queryChunks[queryChunks.length - 2];
192
188
  if (isSQLWrapper(aliasNameChunk) && "queryChunks" in aliasNameChunk) {
193
189
  const aliasNameChunkSql = aliasNameChunk;
194
- if (aliasNameChunkSql && aliasNameChunkSql.queryChunks.length === 1) {
190
+ if (aliasNameChunkSql.queryChunks?.length === 1 && aliasNameChunkSql.queryChunks[0]) {
195
191
  const queryChunksStringChunc = aliasNameChunkSql.queryChunks[0];
196
- if (queryChunksStringChunc && "value" in queryChunksStringChunc) {
192
+ if ("value" in queryChunksStringChunc) {
197
193
  const values = queryChunksStringChunc.value;
198
194
  if (values && values.length === 1) {
199
195
  return values[0];
@@ -245,7 +241,7 @@ function applyFromDriverTransform(rows, selections, aliasMap) {
245
241
  });
246
242
  }
247
243
  function processNullBranches(obj) {
248
- if (obj === null || typeof obj !== "object" || obj === void 0) {
244
+ if (obj === null || typeof obj !== "object") {
249
245
  return obj;
250
246
  }
251
247
  if (obj.constructor && obj.constructor.name !== "Object") {
@@ -258,7 +254,7 @@ function processNullBranches(obj) {
258
254
  result[key] = null;
259
255
  continue;
260
256
  }
261
- if (typeof value === "object" && value !== null && value !== void 0) {
257
+ if (typeof value === "object") {
262
258
  const processed = processNullBranches(value);
263
259
  result[key] = processed;
264
260
  if (processed !== null) {
@@ -608,9 +604,8 @@ class ForgeSQLSelectOperations {
608
604
  */
609
605
  async executeRawSQL(query, params) {
610
606
  if (this.options.logRawSqlQuery) {
611
- console.debug(
612
- `Executing with SQL ${query}` + params ? `, with params: ${JSON.stringify(params)}` : ""
613
- );
607
+ const paramsStr = params ? `, with params: ${JSON.stringify(params)}` : "";
608
+ console.debug(`Executing with SQL ${query}${paramsStr}`);
614
609
  }
615
610
  const sqlStatement = sql$1.prepare(query);
616
611
  if (params) {
@@ -632,7 +627,7 @@ class ForgeSQLSelectOperations {
632
627
  }
633
628
  if (this.options.logRawSqlQuery) {
634
629
  console.debug(
635
- `Executing Update with SQL ${query}` + params ? `, with params: ${JSON.stringify(params)}` : ""
630
+ `Executing Update with SQL ${query}` + (params ? `, with params: ${JSON.stringify(params)}` : "")
636
631
  );
637
632
  }
638
633
  const updateQueryResponseResults = await sqlStatement.execute();
@@ -697,7 +692,7 @@ function injectSqlHints(query, hints) {
697
692
  function createForgeDriverProxy(options, logRawSqlQuery) {
698
693
  return async (query, params, method) => {
699
694
  const modifiedQuery = injectSqlHints(query, options);
700
- if (options && logRawSqlQuery) {
695
+ if (options && logRawSqlQuery && modifiedQuery !== query) {
701
696
  console.warn("modified query: " + modifiedQuery);
702
697
  }
703
698
  return forgeDriver(modifiedQuery, params, method);
@@ -746,11 +741,239 @@ function patchDbWithSelectAliased(db) {
746
741
  };
747
742
  return db;
748
743
  }
744
+ class ForgeSQLAnalyseOperation {
745
+ forgeOperations;
746
+ /**
747
+ * Creates a new instance of ForgeSQLAnalizeOperation.
748
+ * @param {ForgeSqlOperation} forgeOperations - The ForgeSQL operations instance
749
+ */
750
+ constructor(forgeOperations) {
751
+ this.forgeOperations = forgeOperations;
752
+ this.mapToCamelCaseClusterStatement = this.mapToCamelCaseClusterStatement.bind(this);
753
+ }
754
+ /**
755
+ * Executes EXPLAIN on a raw SQL query.
756
+ * @param {string} query - The SQL query to analyze
757
+ * @param {unknown[]} bindParams - The query parameters
758
+ * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
759
+ */
760
+ async explainRaw(query, bindParams) {
761
+ const results = await this.forgeOperations.fetch().executeRawSQL(`EXPLAIN ${query}`, bindParams);
762
+ return results.map((row) => ({
763
+ id: row.id,
764
+ estRows: row.estRows,
765
+ actRows: row.actRows,
766
+ task: row.task,
767
+ accessObject: row["access object"],
768
+ executionInfo: row["execution info"],
769
+ operatorInfo: row["operator info"],
770
+ memory: row.memory,
771
+ disk: row.disk
772
+ }));
773
+ }
774
+ /**
775
+ * Executes EXPLAIN on a Drizzle query.
776
+ * @param {{ toSQL: () => Query }} query - The Drizzle query to analyze
777
+ * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
778
+ */
779
+ async explain(query) {
780
+ const { sql: sql2, params } = query.toSQL();
781
+ return this.explainRaw(sql2, params);
782
+ }
783
+ /**
784
+ * Executes EXPLAIN ANALYZE on a raw SQL query.
785
+ * @param {string} query - The SQL query to analyze
786
+ * @param {unknown[]} bindParams - The query parameters
787
+ * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
788
+ */
789
+ async explainAnalyzeRaw(query, bindParams) {
790
+ const results = await this.forgeOperations.fetch().executeRawSQL(`EXPLAIN ANALYZE ${query}`, bindParams);
791
+ return results.map((row) => ({
792
+ id: row.id,
793
+ estRows: row.estRows,
794
+ actRows: row.actRows,
795
+ task: row.task,
796
+ accessObject: row["access object"],
797
+ executionInfo: row["execution info"],
798
+ operatorInfo: row["operator info"],
799
+ memory: row.memory,
800
+ disk: row.disk
801
+ }));
802
+ }
803
+ /**
804
+ * Executes EXPLAIN ANALYZE on a Drizzle query.
805
+ * @param {{ toSQL: () => Query }} query - The Drizzle query to analyze
806
+ * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
807
+ */
808
+ async explainAnalyze(query) {
809
+ const { sql: sql2, params } = query.toSQL();
810
+ return this.explainAnalyzeRaw(sql2, params);
811
+ }
812
+ /**
813
+ * Decodes a query execution plan from its string representation.
814
+ * @param {string} input - The raw execution plan string
815
+ * @returns {ExplainAnalyzeRow[]} The decoded execution plan rows
816
+ */
817
+ decodedPlan(input) {
818
+ if (!input) {
819
+ return [];
820
+ }
821
+ const lines = input.trim().split("\n");
822
+ if (lines.length < 2) return [];
823
+ const headersRaw = lines[0].split(" ").map((h) => h.trim()).filter(Boolean);
824
+ const headers = headersRaw.map((h) => {
825
+ return h.replace(/\s+/g, " ").replace(/[-\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^./, (s) => s.toLowerCase());
826
+ });
827
+ return lines.slice(1).map((line) => {
828
+ const values = line.split(" ").map((s) => s.trim()).filter(Boolean);
829
+ const row = {};
830
+ headers.forEach((key, i) => {
831
+ row[key] = values[i] ?? "";
832
+ });
833
+ return row;
834
+ });
835
+ }
836
+ /**
837
+ * Normalizes a raw slow query row into a more structured format.
838
+ * @param {SlowQueryRaw} row - The raw slow query data
839
+ * @returns {SlowQueryNormalized} The normalized slow query data
840
+ */
841
+ normalizeSlowQuery(row) {
842
+ return {
843
+ time: row.Time,
844
+ txnStartTs: row.Txn_start_ts,
845
+ user: row.User,
846
+ host: row.Host,
847
+ connId: row.Conn_ID,
848
+ db: row.DB,
849
+ query: row.Query,
850
+ digest: row.Digest,
851
+ queryTime: row.Query_time,
852
+ compileTime: row.Compile_time,
853
+ optimizeTime: row.Optimize_time,
854
+ processTime: row.Process_time,
855
+ waitTime: row.Wait_time,
856
+ parseTime: row.Parse_time,
857
+ rewriteTime: row.Rewrite_time,
858
+ copTime: row.Cop_time,
859
+ copProcAvg: row.Cop_proc_avg,
860
+ copProcMax: row.Cop_proc_max,
861
+ copProcP90: row.Cop_proc_p90,
862
+ copProcAddr: row.Cop_proc_addr,
863
+ copWaitAvg: row.Cop_wait_avg,
864
+ copWaitMax: row.Cop_wait_max,
865
+ copWaitP90: row.Cop_wait_p90,
866
+ copWaitAddr: row.Cop_wait_addr,
867
+ memMax: row.Mem_max,
868
+ diskMax: row.Disk_max,
869
+ totalKeys: row.Total_keys,
870
+ processKeys: row.Process_keys,
871
+ requestCount: row.Request_count,
872
+ kvTotal: row.KV_total,
873
+ pdTotal: row.PD_total,
874
+ resultRows: row.Result_rows,
875
+ rocksdbBlockCacheHitCount: row.Rocksdb_block_cache_hit_count,
876
+ rocksdbBlockReadCount: row.Rocksdb_block_read_count,
877
+ rocksdbBlockReadByte: row.Rocksdb_block_read_byte,
878
+ plan: row.Plan,
879
+ binaryPlan: row.Binary_plan,
880
+ planDigest: row.Plan_digest,
881
+ parsedPlan: this.decodedPlan(row.Plan)
882
+ };
883
+ }
884
+ /**
885
+ * Builds a SQL query for retrieving cluster statement history.
886
+ * @param {string[]} tables - The tables to analyze
887
+ * @param {Date} [from] - The start date for the analysis
888
+ * @param {Date} [to] - The end date for the analysis
889
+ * @returns {string} The SQL query for cluster statement history
890
+ */
891
+ buildClusterStatementQuery(tables, from, to) {
892
+ const formatDateTime = (date) => moment(date).format("YYYY-MM-DDTHH:mm:ss.SSS");
893
+ const tableConditions = tables.map((table) => `TABLE_NAMES LIKE CONCAT(SCHEMA_NAME, '.', '%', '${table}', '%')`).join(" OR ");
894
+ const timeConditions = [];
895
+ if (from) {
896
+ timeConditions.push(`SUMMARY_BEGIN_TIME >= '${formatDateTime(from)}'`);
897
+ }
898
+ if (to) {
899
+ timeConditions.push(`SUMMARY_END_TIME <= '${formatDateTime(to)}'`);
900
+ }
901
+ let whereClauses;
902
+ if (tableConditions?.length) {
903
+ whereClauses = [tableConditions ? `(${tableConditions})` : "", ...timeConditions];
904
+ } else {
905
+ whereClauses = timeConditions;
906
+ }
907
+ return `
908
+ SELECT *
909
+ FROM (
910
+ SELECT * FROM INFORMATION_SCHEMA.CLUSTER_STATEMENTS_SUMMARY
911
+ UNION ALL
912
+ SELECT * FROM INFORMATION_SCHEMA.CLUSTER_STATEMENTS_SUMMARY_HISTORY
913
+ ) AS combined
914
+ ${whereClauses?.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : ""}
915
+ `;
916
+ }
917
+ /**
918
+ * Retrieves and analyzes slow queries from the database.
919
+ * @returns {Promise<SlowQueryNormalized[]>} The normalized slow query data
920
+ */
921
+ async analyzeSlowQueries() {
922
+ const results = await this.forgeOperations.fetch().executeRawSQL(`
923
+ SELECT *
924
+ FROM information_schema.slow_query
925
+ ORDER BY time DESC
926
+ `);
927
+ return results.map((row) => this.normalizeSlowQuery(row));
928
+ }
929
+ /**
930
+ * Converts a cluster statement row to camelCase format.
931
+ * @param {Record<string, any>} input - The input row data
932
+ * @returns {ClusterStatementRowCamelCase} The converted row data
933
+ */
934
+ mapToCamelCaseClusterStatement(input) {
935
+ if (!input) {
936
+ return {};
937
+ }
938
+ const result = {};
939
+ result.parsedPlan = this.decodedPlan(input["PLAN"] ?? "");
940
+ for (const key in input) {
941
+ const camelKey = key.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
942
+ result[camelKey] = input[key];
943
+ }
944
+ return result;
945
+ }
946
+ /**
947
+ * Analyzes query history for specific tables using raw table names.
948
+ * @param {string[]} tables - The table names to analyze
949
+ * @param {Date} [fromDate] - The start date for the analysis
950
+ * @param {Date} [toDate] - The end date for the analysis
951
+ * @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history
952
+ */
953
+ async analyzeQueriesHistoryRaw(tables, fromDate, toDate) {
954
+ const results = await this.forgeOperations.fetch().executeRawSQL(
955
+ this.buildClusterStatementQuery(tables ?? [], fromDate, toDate)
956
+ );
957
+ return results.map((r) => this.mapToCamelCaseClusterStatement(r));
958
+ }
959
+ /**
960
+ * Analyzes query history for specific tables using Drizzle table objects.
961
+ * @param {AnyMySqlTable[]} tables - The Drizzle table objects to analyze
962
+ * @param {Date} [fromDate] - The start date for the analysis
963
+ * @param {Date} [toDate] - The end date for the analysis
964
+ * @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history
965
+ */
966
+ async analyzeQueriesHistory(tables, fromDate, toDate) {
967
+ const tableNames = tables?.map((table) => getTableName(table)) ?? [];
968
+ return this.analyzeQueriesHistoryRaw(tableNames, fromDate, toDate);
969
+ }
970
+ }
749
971
  class ForgeSQLORMImpl {
750
972
  static instance = null;
751
973
  drizzle;
752
974
  crudOperations;
753
975
  fetchOperations;
976
+ analyzeOperations;
754
977
  /**
755
978
  * Private constructor to enforce singleton behavior.
756
979
  * @param options - Options for configuring ForgeSQL ORM behavior.
@@ -770,20 +993,26 @@ class ForgeSQLORMImpl {
770
993
  );
771
994
  this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);
772
995
  this.fetchOperations = new ForgeSQLSelectOperations(newOptions);
996
+ this.analyzeOperations = new ForgeSQLAnalyseOperation(this);
773
997
  } catch (error) {
774
998
  console.error("ForgeSQLORM initialization failed:", error);
775
999
  throw error;
776
1000
  }
777
1001
  }
1002
+ /**
1003
+ * Create the modify operations instance.
1004
+ * @returns modify operations.
1005
+ */
1006
+ modify() {
1007
+ return this.crudOperations;
1008
+ }
778
1009
  /**
779
1010
  * Returns the singleton instance of ForgeSQLORMImpl.
780
1011
  * @param options - Options for configuring ForgeSQL ORM behavior.
781
1012
  * @returns The singleton instance of ForgeSQLORMImpl.
782
1013
  */
783
1014
  static getInstance(options) {
784
- if (!ForgeSQLORMImpl.instance) {
785
- ForgeSQLORMImpl.instance = new ForgeSQLORMImpl(options);
786
- }
1015
+ ForgeSQLORMImpl.instance ??= new ForgeSQLORMImpl(options);
787
1016
  return ForgeSQLORMImpl.instance;
788
1017
  }
789
1018
  /**
@@ -791,7 +1020,7 @@ class ForgeSQLORMImpl {
791
1020
  * @returns CRUD operations.
792
1021
  */
793
1022
  crud() {
794
- return this.crudOperations;
1023
+ return this.modify();
795
1024
  }
796
1025
  /**
797
1026
  * Retrieves the fetch operations instance.
@@ -800,6 +1029,9 @@ class ForgeSQLORMImpl {
800
1029
  fetch() {
801
1030
  return this.fetchOperations;
802
1031
  }
1032
+ analyze() {
1033
+ return this.analyzeOperations;
1034
+ }
803
1035
  /**
804
1036
  * Returns a Drizzle query builder instance.
805
1037
  *
@@ -887,7 +1119,7 @@ class ForgeSQLORM {
887
1119
  *
888
1120
  * @template TSelection - The type of the selected fields
889
1121
  * @param {TSelection} fields - Object containing the fields to select, with table schemas as values
890
- * @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A distinct select query builder with unique field aliases
1122
+ * @returns {MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>} A distinct select query builder with unique field aliases
891
1123
  * @throws {Error} If fields parameter is empty
892
1124
  * @example
893
1125
  * ```typescript
@@ -905,7 +1137,14 @@ class ForgeSQLORM {
905
1137
  * @returns CRUD operations.
906
1138
  */
907
1139
  crud() {
908
- return this.ormInstance.crud();
1140
+ return this.ormInstance.modify();
1141
+ }
1142
+ /**
1143
+ * Proxies the `modify` method from `ForgeSQLORMImpl`.
1144
+ * @returns Modify operations.
1145
+ */
1146
+ modify() {
1147
+ return this.ormInstance.modify();
909
1148
  }
910
1149
  /**
911
1150
  * Proxies the `fetch` method from `ForgeSQLORMImpl`.
@@ -914,6 +1153,13 @@ class ForgeSQLORM {
914
1153
  fetch() {
915
1154
  return this.ormInstance.fetch();
916
1155
  }
1156
+ /**
1157
+ * Provides query analysis capabilities including EXPLAIN ANALYZE and slow query analysis.
1158
+ * @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance
1159
+ */
1160
+ analyze() {
1161
+ return this.ormInstance.analyze();
1162
+ }
917
1163
  /**
918
1164
  * Returns a Drizzle query builder instance.
919
1165
  *
@@ -974,8 +1220,19 @@ const forgeTimeString = customType({
974
1220
  return parseDateTime(value, "HH:mm:ss.SSS");
975
1221
  }
976
1222
  });
977
- async function dropSchemaMigrations(tables) {
1223
+ const migrations = mysqlTable("__migrations", {
1224
+ id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
1225
+ name: varchar("name", { length: 255 }).notNull(),
1226
+ migratedAt: timestamp("migratedAt").defaultNow().notNull()
1227
+ });
1228
+ async function getTables() {
1229
+ const tables = await sql$1.executeDDL("SHOW TABLES");
1230
+ return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
1231
+ }
1232
+ const forgeSystemTables = [migrations];
1233
+ async function dropSchemaMigrations() {
978
1234
  try {
1235
+ const tables = await getTables();
979
1236
  const dropStatements = generateDropTableStatements(tables);
980
1237
  for (const statement of dropStatements) {
981
1238
  console.warn(statement);
@@ -986,32 +1243,41 @@ async function dropSchemaMigrations(tables) {
986
1243
  "⚠️ All data in these tables has been permanently deleted. This operation cannot be undone."
987
1244
  );
988
1245
  } catch (error) {
1246
+ console.error(error);
989
1247
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
990
1248
  return getHttpResponse(500, errorMessage);
991
1249
  }
992
1250
  }
993
1251
  const applySchemaMigrations = async (migration) => {
994
- console.log("Provisioning the database");
995
- await sql$1._provision();
996
- console.info("Running schema migrations");
997
- const migrations2 = await migration(migrationRunner);
998
- const successfulMigrations = await migrations2.run();
999
- console.info("Migrations applied:", successfulMigrations);
1000
- const migrationHistory = (await migrationRunner.list()).map((y) => `${y.id}, ${y.name}, ${y.migratedAt.toUTCString()}`).join("\n");
1001
- console.info("Migrations history:\nid, name, migrated_at\n", migrationHistory);
1002
- return {
1003
- headers: { "Content-Type": ["application/json"] },
1004
- statusCode: 200,
1005
- statusText: "OK",
1006
- body: "Migrations successfully executed"
1007
- };
1252
+ try {
1253
+ if (typeof migration !== "function") {
1254
+ throw new Error("migration is not a function");
1255
+ }
1256
+ console.log("Provisioning the database");
1257
+ await sql$1._provision();
1258
+ console.info("Running schema migrations");
1259
+ const migrations2 = await migration(migrationRunner);
1260
+ const successfulMigrations = await migrations2.run();
1261
+ console.info("Migrations applied:", successfulMigrations);
1262
+ const migrationList = await migrationRunner.list();
1263
+ const migrationHistory = Array.isArray(migrationList) && migrationList.length > 0 ? migrationList.map((y) => `${y.id}, ${y.name}, ${y.migratedAt.toUTCString()}`).join("\n") : "No migrations found";
1264
+ console.info("Migrations history:\nid, name, migrated_at\n", migrationHistory);
1265
+ return {
1266
+ headers: { "Content-Type": ["application/json"] },
1267
+ statusCode: 200,
1268
+ statusText: "OK",
1269
+ body: "Migrations successfully executed"
1270
+ };
1271
+ } catch (error) {
1272
+ console.error("Error during migration:", error);
1273
+ return {
1274
+ headers: { "Content-Type": ["application/json"] },
1275
+ statusCode: 500,
1276
+ statusText: "Internal Server Error",
1277
+ body: error instanceof Error ? error.message : "Unknown error during migration"
1278
+ };
1279
+ }
1008
1280
  };
1009
- const migrations = mysqlTable("__migrations", {
1010
- id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
1011
- name: varchar("name", { length: 255 }).notNull(),
1012
- migratedAt: timestamp("migratedAt").defaultNow().notNull()
1013
- });
1014
- const forgeSystemTables = [migrations];
1015
1281
  async function fetchSchemaWebTrigger() {
1016
1282
  try {
1017
1283
  const tables = await getTables();
@@ -1024,14 +1290,10 @@ async function fetchSchemaWebTrigger() {
1024
1290
  return getHttpResponse(500, errorMessage);
1025
1291
  }
1026
1292
  }
1027
- async function getTables() {
1028
- const tables = await sql$1.executeDDL("SHOW TABLES");
1029
- return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
1030
- }
1031
1293
  async function generateCreateTableStatements(tables) {
1032
1294
  const statements = [];
1033
1295
  for (const table of tables) {
1034
- const createTableResult = await sql$1.executeDDL(`SHOW CREATE TABLE ${table}`);
1296
+ const createTableResult = await sql$1.executeDDL(`SHOW CREATE TABLE "${table}"`);
1035
1297
  const createTableStatements = createTableResult.rows.filter((row) => !isSystemTable(row.Table)).map((row) => formatCreateTableStatement(row["Create Table"]));
1036
1298
  statements.push(...createTableStatements);
1037
1299
  }
@@ -1071,14 +1333,17 @@ export {
1071
1333
  forgeDateString,
1072
1334
  forgeDateTimeString,
1073
1335
  forgeDriver,
1336
+ forgeSystemTables,
1074
1337
  forgeTimeString,
1075
1338
  forgeTimestampString,
1076
1339
  generateDropTableStatements,
1077
1340
  getHttpResponse,
1078
1341
  getPrimaryKeys,
1079
1342
  getTableMetadata,
1343
+ getTables,
1080
1344
  mapSelectAllFieldsToAlias,
1081
1345
  mapSelectFieldsWithAlias,
1346
+ migrations,
1082
1347
  parseDateTime,
1083
1348
  patchDbWithSelectAliased
1084
1349
  };