forge-sql-orm 2.0.17 → 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.
- package/README.md +95 -4
- package/dist/ForgeSQLORM.js +382 -60
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +382 -60
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLAnalyseOperations.d.ts +250 -0
- package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -0
- package/dist/core/ForgeSQLCrudOperations.d.ts +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +12 -2
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +112 -21
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +167 -0
- package/dist/core/SystemTables.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/forgeDriverProxy.d.ts +11 -0
- package/dist/utils/forgeDriverProxy.d.ts.map +1 -0
- package/dist/utils/sqlHints.d.ts +21 -0
- package/dist/utils/sqlHints.d.ts.map +1 -0
- package/dist/utils/sqlUtils.d.ts +2 -8
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts +2 -4
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
- package/package.json +4 -12
- package/src/core/ForgeSQLAnalyseOperations.ts +461 -0
- package/src/core/ForgeSQLCrudOperations.ts +15 -8
- package/src/core/ForgeSQLORM.ts +46 -9
- package/src/core/ForgeSQLQueryBuilder.ts +129 -32
- package/src/core/ForgeSQLSelectOperations.ts +4 -6
- package/src/core/SystemTables.ts +175 -0
- package/src/index.ts +1 -0
- package/src/utils/forgeDriverProxy.ts +27 -0
- package/src/utils/sqlHints.ts +63 -0
- package/src/utils/sqlUtils.ts +36 -32
- package/src/webtriggers/applyMigrationsWebTrigger.ts +32 -16
- package/src/webtriggers/dropMigrationWebTrigger.ts +5 -6
- package/src/webtriggers/fetchSchemaWebTrigger.ts +2 -10
package/src/utils/sqlUtils.ts
CHANGED
|
@@ -47,23 +47,24 @@ interface ConfigBuilderData {
|
|
|
47
47
|
* @returns Date object
|
|
48
48
|
*/
|
|
49
49
|
export const parseDateTime = (value: string, format: string): Date => {
|
|
50
|
+
let result: Date;
|
|
50
51
|
const m = moment(value, format, true);
|
|
51
52
|
if (!m.isValid()) {
|
|
52
|
-
|
|
53
|
+
const momentDate = moment(value);
|
|
54
|
+
if (momentDate.isValid()) {
|
|
55
|
+
result = momentDate.toDate();
|
|
56
|
+
} else {
|
|
57
|
+
result = new Date(value);
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
result = m.toDate();
|
|
61
|
+
}
|
|
62
|
+
if (isNaN(result.getTime())) {
|
|
63
|
+
result = new Date(value);
|
|
53
64
|
}
|
|
54
|
-
return
|
|
65
|
+
return result;
|
|
55
66
|
};
|
|
56
67
|
|
|
57
|
-
/**
|
|
58
|
-
* Extracts the alias from a SQL query
|
|
59
|
-
* @param query - The SQL query to extract the alias from
|
|
60
|
-
* @returns The extracted alias or the original query if no alias found
|
|
61
|
-
*/
|
|
62
|
-
export function extractAlias(query: string): string {
|
|
63
|
-
const match = query.match(/\bas\s+(['"`]?)([\w*]+)\1$/i);
|
|
64
|
-
return match ? match[2] : query;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
68
|
/**
|
|
68
69
|
* Gets primary keys from the schema.
|
|
69
70
|
* @template T - The type of the table schema
|
|
@@ -144,7 +145,7 @@ function processForeignKeys(
|
|
|
144
145
|
const configBuilders = Array.isArray(configBuilderData)
|
|
145
146
|
? configBuilderData
|
|
146
147
|
: Object.values(configBuilderData).map(
|
|
147
|
-
(item) => (item as ConfigBuilderData).value
|
|
148
|
+
(item) => (item as ConfigBuilderData).value ?? item,
|
|
148
149
|
);
|
|
149
150
|
|
|
150
151
|
configBuilders.forEach((builder) => {
|
|
@@ -198,7 +199,7 @@ export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
|
|
|
198
199
|
const configBuilders = Array.isArray(configBuilderData)
|
|
199
200
|
? configBuilderData
|
|
200
201
|
: Object.values(configBuilderData).map(
|
|
201
|
-
(item) => (item as ConfigBuilderData).value
|
|
202
|
+
(item) => (item as ConfigBuilderData).value ?? item,
|
|
202
203
|
);
|
|
203
204
|
|
|
204
205
|
// Process each builder
|
|
@@ -239,28 +240,26 @@ export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
|
|
|
239
240
|
|
|
240
241
|
/**
|
|
241
242
|
* Generates SQL statements to drop tables
|
|
242
|
-
* @param tables - Array of table
|
|
243
|
+
* @param tables - Array of table names
|
|
243
244
|
* @returns Array of SQL statements for dropping tables
|
|
244
245
|
*/
|
|
245
|
-
export function generateDropTableStatements(tables:
|
|
246
|
+
export function generateDropTableStatements(tables: string[]): string[] {
|
|
246
247
|
const dropStatements: string[] = [];
|
|
247
248
|
|
|
248
|
-
tables.forEach((
|
|
249
|
-
|
|
250
|
-
if (tableMetadata.tableName) {
|
|
251
|
-
dropStatements.push(`DROP TABLE IF EXISTS \`${tableMetadata.tableName}\`;`);
|
|
252
|
-
}
|
|
249
|
+
tables.forEach((tableName) => {
|
|
250
|
+
dropStatements.push(`DROP TABLE IF EXISTS \`${tableName}\`;`);
|
|
253
251
|
});
|
|
254
252
|
|
|
255
|
-
// Add statement to clear migrations table
|
|
256
|
-
dropStatements.push(`DELETE FROM __migrations;`);
|
|
257
|
-
|
|
258
253
|
return dropStatements;
|
|
259
254
|
}
|
|
260
255
|
|
|
261
256
|
type AliasColumnMap = Record<string, AnyColumn>;
|
|
262
257
|
|
|
263
|
-
function mapSelectTableToAlias(
|
|
258
|
+
function mapSelectTableToAlias(
|
|
259
|
+
table: MySqlTable,
|
|
260
|
+
uniqPrefix: string,
|
|
261
|
+
aliasMap: AliasColumnMap,
|
|
262
|
+
): any {
|
|
264
263
|
const { columns, tableName } = getTableMetadata(table);
|
|
265
264
|
const selectionsTableFields: Record<string, unknown> = {};
|
|
266
265
|
Object.keys(columns).forEach((name) => {
|
|
@@ -280,7 +279,7 @@ function isDrizzleColumn(column: any): boolean {
|
|
|
280
279
|
export function mapSelectAllFieldsToAlias(
|
|
281
280
|
selections: any,
|
|
282
281
|
name: string,
|
|
283
|
-
uniqName:string,
|
|
282
|
+
uniqName: string,
|
|
284
283
|
fields: any,
|
|
285
284
|
aliasMap: AliasColumnMap,
|
|
286
285
|
): any {
|
|
@@ -312,7 +311,7 @@ export function mapSelectFieldsWithAlias<TSelection extends SelectedFields>(
|
|
|
312
311
|
const aliasMap: AliasColumnMap = {};
|
|
313
312
|
const selections: any = {};
|
|
314
313
|
Object.entries(fields).forEach(([name, fields]) => {
|
|
315
|
-
mapSelectAllFieldsToAlias(selections, name,name, fields, aliasMap);
|
|
314
|
+
mapSelectAllFieldsToAlias(selections, name, name, fields, aliasMap);
|
|
316
315
|
});
|
|
317
316
|
return { selections, aliasMap };
|
|
318
317
|
}
|
|
@@ -327,9 +326,9 @@ function getAliasFromDrizzleAlias(value: unknown): string | undefined {
|
|
|
327
326
|
const aliasNameChunk = queryChunks[queryChunks.length - 2];
|
|
328
327
|
if (isSQLWrapper(aliasNameChunk) && "queryChunks" in aliasNameChunk) {
|
|
329
328
|
const aliasNameChunkSql = aliasNameChunk as SQL;
|
|
330
|
-
if (aliasNameChunkSql
|
|
329
|
+
if (aliasNameChunkSql.queryChunks?.length === 1 && aliasNameChunkSql.queryChunks[0]) {
|
|
331
330
|
const queryChunksStringChunc = aliasNameChunkSql.queryChunks[0];
|
|
332
|
-
if (
|
|
331
|
+
if ("value" in queryChunksStringChunc) {
|
|
333
332
|
const values = (queryChunksStringChunc as StringChunk).value;
|
|
334
333
|
if (values && values.length === 1) {
|
|
335
334
|
return values[0];
|
|
@@ -402,7 +401,12 @@ export function applyFromDriverTransform<T, TSelection>(
|
|
|
402
401
|
}
|
|
403
402
|
|
|
404
403
|
function processNullBranches(obj: Record<string, unknown>): Record<string, unknown> | null {
|
|
405
|
-
if (obj === null || typeof obj !==
|
|
404
|
+
if (obj === null || typeof obj !== "object") {
|
|
405
|
+
return obj;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Skip built-in objects like Date, Array, etc.
|
|
409
|
+
if (obj.constructor && obj.constructor.name !== "Object") {
|
|
406
410
|
return obj;
|
|
407
411
|
}
|
|
408
412
|
|
|
@@ -410,12 +414,12 @@ function processNullBranches(obj: Record<string, unknown>): Record<string, unkno
|
|
|
410
414
|
let allNull = true;
|
|
411
415
|
|
|
412
416
|
for (const [key, value] of Object.entries(obj)) {
|
|
413
|
-
if (value === null || value===undefined) {
|
|
417
|
+
if (value === null || value === undefined) {
|
|
414
418
|
result[key] = null;
|
|
415
419
|
continue;
|
|
416
420
|
}
|
|
417
421
|
|
|
418
|
-
if (typeof value ===
|
|
422
|
+
if (typeof value === "object") {
|
|
419
423
|
const processed = processNullBranches(value as Record<string, unknown>);
|
|
420
424
|
result[key] = processed;
|
|
421
425
|
if (processed !== null) {
|
|
@@ -27,23 +27,39 @@ import { MigrationRunner } from "@forge/sql/out/migration";
|
|
|
27
27
|
export const applySchemaMigrations = async (
|
|
28
28
|
migration: (migrationRunner: MigrationRunner) => Promise<MigrationRunner>,
|
|
29
29
|
) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const successfulMigrations = await migrations.run();
|
|
35
|
-
console.info("Migrations applied:", successfulMigrations);
|
|
30
|
+
try {
|
|
31
|
+
if (typeof migration !== "function") {
|
|
32
|
+
throw new Error("migration is not a function");
|
|
33
|
+
}
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.
|
|
35
|
+
console.log("Provisioning the database");
|
|
36
|
+
await sql._provision();
|
|
37
|
+
console.info("Running schema migrations");
|
|
38
|
+
const migrations = await migration(migrationRunner);
|
|
39
|
+
const successfulMigrations = await migrations.run();
|
|
40
|
+
console.info("Migrations applied:", successfulMigrations);
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
const migrationList = await migrationRunner.list();
|
|
43
|
+
const migrationHistory =
|
|
44
|
+
Array.isArray(migrationList) && migrationList.length > 0
|
|
45
|
+
? migrationList.map((y) => `${y.id}, ${y.name}, ${y.migratedAt.toUTCString()}`).join("\n")
|
|
46
|
+
: "No migrations found";
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
console.info("Migrations history:\nid, name, migrated_at\n", migrationHistory);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
headers: { "Content-Type": ["application/json"] },
|
|
52
|
+
statusCode: 200,
|
|
53
|
+
statusText: "OK",
|
|
54
|
+
body: "Migrations successfully executed",
|
|
55
|
+
};
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error("Error during migration:", error);
|
|
58
|
+
return {
|
|
59
|
+
headers: { "Content-Type": ["application/json"] },
|
|
60
|
+
statusCode: 500,
|
|
61
|
+
statusText: "Internal Server Error",
|
|
62
|
+
body: error instanceof Error ? error.message : "Unknown error during migration",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
49
65
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { sql } from "@forge/sql";
|
|
2
|
-
import { AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
3
2
|
import { generateDropTableStatements as generateStatements } from "../utils/sqlUtils";
|
|
4
3
|
import { getHttpResponse, TriggerResponse } from "./index";
|
|
4
|
+
import { getTables } from "../core/SystemTables";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* ⚠️ DEVELOPMENT ONLY WEB TRIGGER ⚠️
|
|
@@ -15,7 +15,6 @@ import { getHttpResponse, TriggerResponse } from "./index";
|
|
|
15
15
|
* - It may affect application functionality
|
|
16
16
|
* - It could lead to data loss and system instability
|
|
17
17
|
*
|
|
18
|
-
* @param tables - Array of table schemas to drop
|
|
19
18
|
* @returns {Promise<TriggerResponse<string>>} A response containing:
|
|
20
19
|
* - On success: 200 status with warning message about permanent deletion
|
|
21
20
|
* - On failure: 500 status with error message
|
|
@@ -23,14 +22,13 @@ import { getHttpResponse, TriggerResponse } from "./index";
|
|
|
23
22
|
* @example
|
|
24
23
|
* ```typescript
|
|
25
24
|
* // Example usage in development only
|
|
26
|
-
* await dropSchemaMigrations(
|
|
25
|
+
* await dropSchemaMigrations();
|
|
27
26
|
* // ⚠️ Warning: This will permanently delete all data in users and orders tables
|
|
28
27
|
* ```
|
|
29
28
|
*/
|
|
30
|
-
export async function dropSchemaMigrations(
|
|
31
|
-
tables: AnyMySqlTable[],
|
|
32
|
-
): Promise<TriggerResponse<string>> {
|
|
29
|
+
export async function dropSchemaMigrations(): Promise<TriggerResponse<string>> {
|
|
33
30
|
try {
|
|
31
|
+
const tables = await getTables();
|
|
34
32
|
// Generate drop statements
|
|
35
33
|
const dropStatements = generateStatements(tables);
|
|
36
34
|
|
|
@@ -45,6 +43,7 @@ export async function dropSchemaMigrations(
|
|
|
45
43
|
"⚠️ All data in these tables has been permanently deleted. This operation cannot be undone.",
|
|
46
44
|
);
|
|
47
45
|
} catch (error: unknown) {
|
|
46
|
+
console.error(error);
|
|
48
47
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
49
48
|
return getHttpResponse<string>(500, errorMessage);
|
|
50
49
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sql } from "@forge/sql";
|
|
2
2
|
import { getHttpResponse, TriggerResponse } from "./index";
|
|
3
|
-
import { forgeSystemTables } from "../core/SystemTables";
|
|
3
|
+
import { forgeSystemTables, getTables } from "../core/SystemTables";
|
|
4
4
|
import { getTableName } from "drizzle-orm/table";
|
|
5
5
|
|
|
6
6
|
interface CreateTableRow {
|
|
@@ -47,14 +47,6 @@ export async function fetchSchemaWebTrigger(): Promise<TriggerResponse<string>>
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
* Retrieves all tables from the database
|
|
52
|
-
*/
|
|
53
|
-
async function getTables(): Promise<string[]> {
|
|
54
|
-
const tables = await sql.executeDDL<string>("SHOW TABLES");
|
|
55
|
-
return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
50
|
/**
|
|
59
51
|
* Generates CREATE TABLE statements for each table
|
|
60
52
|
*/
|
|
@@ -62,7 +54,7 @@ async function generateCreateTableStatements(tables: string[]): Promise<string[]
|
|
|
62
54
|
const statements: string[] = [];
|
|
63
55
|
|
|
64
56
|
for (const table of tables) {
|
|
65
|
-
const createTableResult = await sql.executeDDL<CreateTableRow>(`SHOW CREATE TABLE ${table}`);
|
|
57
|
+
const createTableResult = await sql.executeDDL<CreateTableRow>(`SHOW CREATE TABLE "${table}"`);
|
|
66
58
|
|
|
67
59
|
const createTableStatements = createTableResult.rows
|
|
68
60
|
.filter((row) => !isSystemTable(row.Table))
|