forge-sql-orm 2.0.18 → 2.0.20

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 +315 -49
  3. package/dist/ForgeSQLORM.js.map +1 -1
  4. package/dist/ForgeSQLORM.mjs +315 -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 +11 -19
  23. package/src/core/ForgeSQLAnalyseOperations.ts +462 -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,240 @@ 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
+ // CLUSTER_SLOW_QUERY STATISTICS
922
+ async analyzeSlowQueries() {
923
+ const results = await this.forgeOperations.fetch().executeRawSQL(`
924
+ SELECT *
925
+ FROM information_schema.slow_query
926
+ ORDER BY time DESC
927
+ `);
928
+ return results.map((row) => this.normalizeSlowQuery(row));
929
+ }
930
+ /**
931
+ * Converts a cluster statement row to camelCase format.
932
+ * @param {Record<string, any>} input - The input row data
933
+ * @returns {ClusterStatementRowCamelCase} The converted row data
934
+ */
935
+ mapToCamelCaseClusterStatement(input) {
936
+ if (!input) {
937
+ return {};
938
+ }
939
+ const result = {};
940
+ result.parsedPlan = this.decodedPlan(input["PLAN"] ?? "");
941
+ for (const key in input) {
942
+ const camelKey = key.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
943
+ result[camelKey] = input[key];
944
+ }
945
+ return result;
946
+ }
947
+ /**
948
+ * Analyzes query history for specific tables using raw table names.
949
+ * @param {string[]} tables - The table names to analyze
950
+ * @param {Date} [fromDate] - The start date for the analysis
951
+ * @param {Date} [toDate] - The end date for the analysis
952
+ * @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history
953
+ */
954
+ async analyzeQueriesHistoryRaw(tables, fromDate, toDate) {
955
+ const results = await this.forgeOperations.fetch().executeRawSQL(
956
+ this.buildClusterStatementQuery(tables ?? [], fromDate, toDate)
957
+ );
958
+ return results.map((r) => this.mapToCamelCaseClusterStatement(r));
959
+ }
960
+ /**
961
+ * Analyzes query history for specific tables using Drizzle table objects.
962
+ * @param {AnyMySqlTable[]} tables - The Drizzle table objects to analyze
963
+ * @param {Date} [fromDate] - The start date for the analysis
964
+ * @param {Date} [toDate] - The end date for the analysis
965
+ * @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history
966
+ */
967
+ async analyzeQueriesHistory(tables, fromDate, toDate) {
968
+ const tableNames = tables?.map((table) => getTableName(table)) ?? [];
969
+ return this.analyzeQueriesHistoryRaw(tableNames, fromDate, toDate);
970
+ }
971
+ }
749
972
  class ForgeSQLORMImpl {
750
973
  static instance = null;
751
974
  drizzle;
752
975
  crudOperations;
753
976
  fetchOperations;
977
+ analyzeOperations;
754
978
  /**
755
979
  * Private constructor to enforce singleton behavior.
756
980
  * @param options - Options for configuring ForgeSQL ORM behavior.
@@ -770,20 +994,26 @@ class ForgeSQLORMImpl {
770
994
  );
771
995
  this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);
772
996
  this.fetchOperations = new ForgeSQLSelectOperations(newOptions);
997
+ this.analyzeOperations = new ForgeSQLAnalyseOperation(this);
773
998
  } catch (error) {
774
999
  console.error("ForgeSQLORM initialization failed:", error);
775
1000
  throw error;
776
1001
  }
777
1002
  }
1003
+ /**
1004
+ * Create the modify operations instance.
1005
+ * @returns modify operations.
1006
+ */
1007
+ modify() {
1008
+ return this.crudOperations;
1009
+ }
778
1010
  /**
779
1011
  * Returns the singleton instance of ForgeSQLORMImpl.
780
1012
  * @param options - Options for configuring ForgeSQL ORM behavior.
781
1013
  * @returns The singleton instance of ForgeSQLORMImpl.
782
1014
  */
783
1015
  static getInstance(options) {
784
- if (!ForgeSQLORMImpl.instance) {
785
- ForgeSQLORMImpl.instance = new ForgeSQLORMImpl(options);
786
- }
1016
+ ForgeSQLORMImpl.instance ??= new ForgeSQLORMImpl(options);
787
1017
  return ForgeSQLORMImpl.instance;
788
1018
  }
789
1019
  /**
@@ -791,7 +1021,7 @@ class ForgeSQLORMImpl {
791
1021
  * @returns CRUD operations.
792
1022
  */
793
1023
  crud() {
794
- return this.crudOperations;
1024
+ return this.modify();
795
1025
  }
796
1026
  /**
797
1027
  * Retrieves the fetch operations instance.
@@ -800,6 +1030,9 @@ class ForgeSQLORMImpl {
800
1030
  fetch() {
801
1031
  return this.fetchOperations;
802
1032
  }
1033
+ analyze() {
1034
+ return this.analyzeOperations;
1035
+ }
803
1036
  /**
804
1037
  * Returns a Drizzle query builder instance.
805
1038
  *
@@ -887,7 +1120,7 @@ class ForgeSQLORM {
887
1120
  *
888
1121
  * @template TSelection - The type of the selected fields
889
1122
  * @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
1123
+ * @returns {MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>} A distinct select query builder with unique field aliases
891
1124
  * @throws {Error} If fields parameter is empty
892
1125
  * @example
893
1126
  * ```typescript
@@ -905,7 +1138,14 @@ class ForgeSQLORM {
905
1138
  * @returns CRUD operations.
906
1139
  */
907
1140
  crud() {
908
- return this.ormInstance.crud();
1141
+ return this.ormInstance.modify();
1142
+ }
1143
+ /**
1144
+ * Proxies the `modify` method from `ForgeSQLORMImpl`.
1145
+ * @returns Modify operations.
1146
+ */
1147
+ modify() {
1148
+ return this.ormInstance.modify();
909
1149
  }
910
1150
  /**
911
1151
  * Proxies the `fetch` method from `ForgeSQLORMImpl`.
@@ -914,6 +1154,13 @@ class ForgeSQLORM {
914
1154
  fetch() {
915
1155
  return this.ormInstance.fetch();
916
1156
  }
1157
+ /**
1158
+ * Provides query analysis capabilities including EXPLAIN ANALYZE and slow query analysis.
1159
+ * @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance
1160
+ */
1161
+ analyze() {
1162
+ return this.ormInstance.analyze();
1163
+ }
917
1164
  /**
918
1165
  * Returns a Drizzle query builder instance.
919
1166
  *
@@ -974,8 +1221,19 @@ const forgeTimeString = customType({
974
1221
  return parseDateTime(value, "HH:mm:ss.SSS");
975
1222
  }
976
1223
  });
977
- async function dropSchemaMigrations(tables) {
1224
+ const migrations = mysqlTable("__migrations", {
1225
+ id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
1226
+ name: varchar("name", { length: 255 }).notNull(),
1227
+ migratedAt: timestamp("migratedAt").defaultNow().notNull()
1228
+ });
1229
+ async function getTables() {
1230
+ const tables = await sql$1.executeDDL("SHOW TABLES");
1231
+ return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
1232
+ }
1233
+ const forgeSystemTables = [migrations];
1234
+ async function dropSchemaMigrations() {
978
1235
  try {
1236
+ const tables = await getTables();
979
1237
  const dropStatements = generateDropTableStatements(tables);
980
1238
  for (const statement of dropStatements) {
981
1239
  console.warn(statement);
@@ -986,32 +1244,41 @@ async function dropSchemaMigrations(tables) {
986
1244
  "⚠️ All data in these tables has been permanently deleted. This operation cannot be undone."
987
1245
  );
988
1246
  } catch (error) {
1247
+ console.error(error);
989
1248
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
990
1249
  return getHttpResponse(500, errorMessage);
991
1250
  }
992
1251
  }
993
1252
  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
- };
1253
+ try {
1254
+ if (typeof migration !== "function") {
1255
+ throw new Error("migration is not a function");
1256
+ }
1257
+ console.log("Provisioning the database");
1258
+ await sql$1._provision();
1259
+ console.info("Running schema migrations");
1260
+ const migrations2 = await migration(migrationRunner);
1261
+ const successfulMigrations = await migrations2.run();
1262
+ console.info("Migrations applied:", successfulMigrations);
1263
+ const migrationList = await migrationRunner.list();
1264
+ const migrationHistory = Array.isArray(migrationList) && migrationList.length > 0 ? migrationList.map((y) => `${y.id}, ${y.name}, ${y.migratedAt.toUTCString()}`).join("\n") : "No migrations found";
1265
+ console.info("Migrations history:\nid, name, migrated_at\n", migrationHistory);
1266
+ return {
1267
+ headers: { "Content-Type": ["application/json"] },
1268
+ statusCode: 200,
1269
+ statusText: "OK",
1270
+ body: "Migrations successfully executed"
1271
+ };
1272
+ } catch (error) {
1273
+ console.error("Error during migration:", error);
1274
+ return {
1275
+ headers: { "Content-Type": ["application/json"] },
1276
+ statusCode: 500,
1277
+ statusText: "Internal Server Error",
1278
+ body: error instanceof Error ? error.message : "Unknown error during migration"
1279
+ };
1280
+ }
1008
1281
  };
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
1282
  async function fetchSchemaWebTrigger() {
1016
1283
  try {
1017
1284
  const tables = await getTables();
@@ -1024,14 +1291,10 @@ async function fetchSchemaWebTrigger() {
1024
1291
  return getHttpResponse(500, errorMessage);
1025
1292
  }
1026
1293
  }
1027
- async function getTables() {
1028
- const tables = await sql$1.executeDDL("SHOW TABLES");
1029
- return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
1030
- }
1031
1294
  async function generateCreateTableStatements(tables) {
1032
1295
  const statements = [];
1033
1296
  for (const table of tables) {
1034
- const createTableResult = await sql$1.executeDDL(`SHOW CREATE TABLE ${table}`);
1297
+ const createTableResult = await sql$1.executeDDL(`SHOW CREATE TABLE "${table}"`);
1035
1298
  const createTableStatements = createTableResult.rows.filter((row) => !isSystemTable(row.Table)).map((row) => formatCreateTableStatement(row["Create Table"]));
1036
1299
  statements.push(...createTableStatements);
1037
1300
  }
@@ -1071,14 +1334,17 @@ export {
1071
1334
  forgeDateString,
1072
1335
  forgeDateTimeString,
1073
1336
  forgeDriver,
1337
+ forgeSystemTables,
1074
1338
  forgeTimeString,
1075
1339
  forgeTimestampString,
1076
1340
  generateDropTableStatements,
1077
1341
  getHttpResponse,
1078
1342
  getPrimaryKeys,
1079
1343
  getTableMetadata,
1344
+ getTables,
1080
1345
  mapSelectAllFieldsToAlias,
1081
1346
  mapSelectFieldsWithAlias,
1347
+ migrations,
1082
1348
  parseDateTime,
1083
1349
  patchDbWithSelectAliased
1084
1350
  };