forge-sql-orm 2.0.9 → 2.0.11
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 +67 -42
- package/dist/ForgeSQLORM.js +162 -16
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +165 -19
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +32 -0
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +8 -6
- 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/lib/drizzle/extensions/selectAliased.d.ts +9 -0
- package/dist/lib/drizzle/extensions/selectAliased.d.ts.map +1 -0
- package/dist/utils/sqlUtils.d.ts +8 -4
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts +23 -0
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts +20 -4
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/fetchSchemaWebTrigger.d.ts +28 -0
- package/dist/webtriggers/fetchSchemaWebTrigger.d.ts.map +1 -0
- package/dist/webtriggers/index.d.ts +1 -0
- package/dist/webtriggers/index.d.ts.map +1 -1
- package/dist-cli/cli.js +5 -0
- package/dist-cli/cli.js.map +1 -1
- package/dist-cli/cli.mjs +8 -3
- package/dist-cli/cli.mjs.map +1 -1
- package/package.json +10 -10
- package/src/core/ForgeSQLCrudOperations.ts +0 -425
- package/src/core/ForgeSQLORM.ts +0 -228
- package/src/core/ForgeSQLQueryBuilder.ts +0 -319
- package/src/core/ForgeSQLSelectOperations.ts +0 -93
- package/src/core/SystemTables.ts +0 -7
- package/src/index.ts +0 -10
- package/src/utils/forgeDriver.ts +0 -39
- package/src/utils/sqlUtils.ts +0 -306
- package/src/webtriggers/applyMigrationsWebTrigger.ts +0 -26
- package/src/webtriggers/dropMigrationWebTrigger.ts +0 -35
- package/src/webtriggers/index.ts +0 -25
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
- ✅ **Automatic entity generation** from MySQL/tidb databases
|
|
12
12
|
- ✅ **Automatic migration generation** from MySQL/tidb databases
|
|
13
13
|
- ✅ **Drop Migrations** Generate a migration to drop all tables and clear migrations history for subsequent schema recreation
|
|
14
|
-
- ✅ **
|
|
14
|
+
- ✅ **Schema Fetching** Development-only web trigger to retrieve current database schema and generate SQL statements for schema recreation
|
|
15
|
+
- ✅ **Ready-to-use Migration Triggers** Built-in web triggers for applying migrations, dropping tables (development-only), and fetching schema (development-only) with proper error handling and security controls
|
|
15
16
|
- ✅ **Optimistic Locking** Ensures data consistency by preventing conflicts when multiple users update the same record
|
|
16
17
|
- ✅ **Type Safety** Full TypeScript support with proper type inference
|
|
17
18
|
|
|
@@ -19,11 +20,11 @@
|
|
|
19
20
|
|
|
20
21
|
### 1. Direct Drizzle Usage
|
|
21
22
|
```typescript
|
|
22
|
-
import { drizzle } from "drizzle-orm/mysql-
|
|
23
|
+
import { drizzle } from "drizzle-orm/mysql-proxy";
|
|
23
24
|
import { forgeDriver } from "forge-sql-orm";
|
|
24
25
|
const db = drizzle(forgeDriver);
|
|
25
26
|
```
|
|
26
|
-
Best for: Simple CRUD operations without optimistic locking. Note that you need to manually
|
|
27
|
+
Best for: Simple CRUD operations without optimistic locking. Note that you need to manually patch drizzle `patchDbWithSelectAliased` for select fields to prevent field name collisions in Atlassian Forge SQL.
|
|
27
28
|
|
|
28
29
|
### 2. Full Forge-SQL-ORM Usage
|
|
29
30
|
```typescript
|
|
@@ -53,14 +54,14 @@ await forgeSQL
|
|
|
53
54
|
|
|
54
55
|
### Using Direct Drizzle
|
|
55
56
|
```typescript
|
|
56
|
-
import { drizzle } from "drizzle-orm/mysql-
|
|
57
|
-
import { forgeDriver,
|
|
57
|
+
import { drizzle } from "drizzle-orm/mysql-proxy";
|
|
58
|
+
import { forgeDriver, patchDbWithSelectAliased } from "forge-sql-orm";
|
|
58
59
|
|
|
59
|
-
const db = drizzle(forgeDriver);
|
|
60
|
+
const db = patchDbWithSelectAliased(drizzle(forgeDriver));
|
|
60
61
|
|
|
61
62
|
// Manual field name collision prevention
|
|
62
63
|
await db
|
|
63
|
-
.
|
|
64
|
+
.selectAliased({user: users, order: orders})
|
|
64
65
|
.from(orders)
|
|
65
66
|
.innerJoin(users, eq(orders.userId, users.id));
|
|
66
67
|
```
|
|
@@ -71,6 +72,7 @@ await db
|
|
|
71
72
|
- The solution automatically creates unique aliases for each field by prefixing them with the table name
|
|
72
73
|
- This ensures that fields with the same name from different tables remain distinct in the query results
|
|
73
74
|
|
|
75
|
+
|
|
74
76
|
## Installation
|
|
75
77
|
|
|
76
78
|
Forge-SQL-ORM is designed to work with @forge/sql and requires some additional setup to ensure compatibility within Atlassian Forge.
|
|
@@ -94,10 +96,10 @@ If you prefer to use Drizzle ORM directly without the additional features of For
|
|
|
94
96
|
|
|
95
97
|
```typescript
|
|
96
98
|
import { drizzle } from "drizzle-orm/mysql-proxy";
|
|
97
|
-
import { forgeDriver } from "forge-sql-orm";
|
|
99
|
+
import { forgeDriver, patchDbWithSelectAliased } from "forge-sql-orm";
|
|
98
100
|
|
|
99
|
-
// Initialize drizzle with the custom driver
|
|
100
|
-
const db = drizzle(forgeDriver);
|
|
101
|
+
// Initialize drizzle with the custom driver and patch it for aliased selects
|
|
102
|
+
const db = patchDbWithSelectAliased(drizzle(forgeDriver));
|
|
101
103
|
|
|
102
104
|
// Use drizzle directly
|
|
103
105
|
const users = await db.select().from(users);
|
|
@@ -377,7 +379,6 @@ const result = await db
|
|
|
377
379
|
|
|
378
380
|
### Complex Queries
|
|
379
381
|
```js
|
|
380
|
-
|
|
381
382
|
// Using joins with automatic field name collision prevention
|
|
382
383
|
// With forgeSQL
|
|
383
384
|
const orderWithUser = await forgeSQL
|
|
@@ -386,9 +387,9 @@ const orderWithUser = await forgeSQL
|
|
|
386
387
|
.innerJoin(users, eq(orders.userId, users.id));
|
|
387
388
|
|
|
388
389
|
// OR with direct drizzle
|
|
389
|
-
const db = drizzle(forgeDriver);
|
|
390
|
+
const db = patchDbWithSelectAliased(drizzle(forgeDriver));
|
|
390
391
|
const orderWithUser = await db
|
|
391
|
-
.
|
|
392
|
+
.selectAliased({user: users, order: orders})
|
|
392
393
|
.from(orders)
|
|
393
394
|
.innerJoin(users, eq(orders.userId, users.id));
|
|
394
395
|
// Returns: {
|
|
@@ -398,33 +399,11 @@ const orderWithUser = await db
|
|
|
398
399
|
// order_product: "Product 1"
|
|
399
400
|
// }
|
|
400
401
|
|
|
401
|
-
// Using distinct
|
|
402
|
-
const
|
|
403
|
-
.
|
|
404
|
-
.from(
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
// Finding duplicates
|
|
408
|
-
// With forgeSQL
|
|
409
|
-
const duplicates = await forgeSQL
|
|
410
|
-
.getDrizzleQueryBuilder()
|
|
411
|
-
.select({
|
|
412
|
-
name: Users.name,
|
|
413
|
-
count: sql<number>`COUNT(*) as \`count\``
|
|
414
|
-
}).from(Users)
|
|
415
|
-
.groupBy(Users.name)
|
|
416
|
-
.having(sql`COUNT(*) > 1`);
|
|
417
|
-
|
|
418
|
-
// OR with direct drizzle
|
|
419
|
-
const db = drizzle(forgeDriver);
|
|
420
|
-
const duplicates = await db
|
|
421
|
-
.select({
|
|
422
|
-
name: Users.name,
|
|
423
|
-
count: sql<number>`COUNT(*) as \`count\``
|
|
424
|
-
}).from(Users)
|
|
425
|
-
.groupBy(Users.name)
|
|
426
|
-
.having(sql`COUNT(*) > 1`);
|
|
427
|
-
// Returns: { name: "John Doe", count: 2 }
|
|
402
|
+
// Using distinct with aliases
|
|
403
|
+
const uniqueUsers = await db
|
|
404
|
+
.selectAliasedDistinct({user: users})
|
|
405
|
+
.from(users);
|
|
406
|
+
// Returns unique users with aliased fields
|
|
428
407
|
|
|
429
408
|
// Using executeQueryOnlyOne for unique results
|
|
430
409
|
const userStats = await forgeSQL
|
|
@@ -575,7 +554,7 @@ Commands:
|
|
|
575
554
|
|
|
576
555
|
## Web Triggers for Migrations
|
|
577
556
|
|
|
578
|
-
Forge-SQL-ORM provides
|
|
557
|
+
Forge-SQL-ORM provides web triggers for managing database migrations in Atlassian Forge:
|
|
579
558
|
|
|
580
559
|
### 1. Apply Migrations Trigger
|
|
581
560
|
|
|
@@ -647,10 +626,57 @@ Configure in `manifest.yml`:
|
|
|
647
626
|
handler: index.dropMigrations
|
|
648
627
|
```
|
|
649
628
|
|
|
629
|
+
### 3. Fetch Schema Trigger
|
|
630
|
+
|
|
631
|
+
⚠️ **DEVELOPMENT ONLY**: This trigger is designed for development environments only and should not be used in production.
|
|
632
|
+
|
|
633
|
+
This trigger retrieves the current database schema from Atlassian Forge SQL and generates SQL statements that can be used to recreate the database structure. It's useful for:
|
|
634
|
+
- Development environment setup
|
|
635
|
+
- Schema documentation
|
|
636
|
+
- Database structure verification
|
|
637
|
+
- Creating backup scripts
|
|
638
|
+
|
|
639
|
+
**Security Considerations**:
|
|
640
|
+
- This trigger exposes your database structure
|
|
641
|
+
- It temporarily disables foreign key checks
|
|
642
|
+
- It may expose sensitive table names and structures
|
|
643
|
+
- Should only be used in development environments
|
|
644
|
+
|
|
645
|
+
```typescript
|
|
646
|
+
// Example usage in your Forge app
|
|
647
|
+
import { fetchSchemaWebTrigger } from "forge-sql-orm";
|
|
648
|
+
|
|
649
|
+
export const fetchSchema = async () => {
|
|
650
|
+
return fetchSchemaWebTrigger();
|
|
651
|
+
};
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Configure in `manifest.yml`:
|
|
655
|
+
```yaml
|
|
656
|
+
webtrigger:
|
|
657
|
+
- key: fetch-schema
|
|
658
|
+
function: fetchSchema
|
|
659
|
+
sql:
|
|
660
|
+
- key: main
|
|
661
|
+
engine: mysql
|
|
662
|
+
function:
|
|
663
|
+
- key: fetchSchema
|
|
664
|
+
handler: index.fetchSchema
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
The response will contain SQL statements like:
|
|
668
|
+
```sql
|
|
669
|
+
SET foreign_key_checks = 0;
|
|
670
|
+
CREATE TABLE IF NOT EXISTS users (...);
|
|
671
|
+
CREATE TABLE IF NOT EXISTS orders (...);
|
|
672
|
+
SET foreign_key_checks = 1;
|
|
673
|
+
```
|
|
674
|
+
|
|
650
675
|
### Important Notes
|
|
651
676
|
|
|
652
677
|
**Security Considerations**:
|
|
653
678
|
- The drop migrations trigger should be restricted to development environments
|
|
679
|
+
- The fetch schema trigger should only be used in development
|
|
654
680
|
- Consider implementing additional authentication for these endpoints
|
|
655
681
|
|
|
656
682
|
**Best Practices**:
|
|
@@ -659,7 +685,6 @@ Configure in `manifest.yml`:
|
|
|
659
685
|
- Use these triggers as part of your deployment pipeline
|
|
660
686
|
- Monitor the execution logs in the Forge Developer Console
|
|
661
687
|
|
|
662
|
-
|
|
663
688
|
## License
|
|
664
689
|
This project is licensed under the **MIT License**.
|
|
665
690
|
Feel free to use it for commercial and personal projects.
|
package/dist/ForgeSQLORM.js
CHANGED
|
@@ -131,32 +131,36 @@ function generateDropTableStatements(tables) {
|
|
|
131
131
|
dropStatements.push(`DELETE FROM __migrations;`);
|
|
132
132
|
return dropStatements;
|
|
133
133
|
}
|
|
134
|
-
function mapSelectTableToAlias(table2) {
|
|
134
|
+
function mapSelectTableToAlias(table2, aliasMap) {
|
|
135
135
|
const { columns, tableName } = getTableMetadata(table2);
|
|
136
136
|
const selectionsTableFields = {};
|
|
137
137
|
Object.keys(columns).forEach((name) => {
|
|
138
138
|
const column = columns[name];
|
|
139
|
-
const
|
|
139
|
+
const uniqName = `a_${tableName}_${column.name}`;
|
|
140
|
+
const fieldAlias = drizzleOrm.sql.raw(uniqName);
|
|
140
141
|
selectionsTableFields[name] = drizzleOrm.sql`${column} as \`${fieldAlias}\``;
|
|
142
|
+
aliasMap[uniqName] = column;
|
|
141
143
|
});
|
|
142
144
|
return selectionsTableFields;
|
|
143
145
|
}
|
|
144
146
|
function isDrizzleColumn(column) {
|
|
145
147
|
return column && typeof column === "object" && "table" in column;
|
|
146
148
|
}
|
|
147
|
-
function mapSelectAllFieldsToAlias(selections, name, fields) {
|
|
149
|
+
function mapSelectAllFieldsToAlias(selections, name, fields, aliasMap) {
|
|
148
150
|
if (drizzleOrm.isTable(fields)) {
|
|
149
|
-
selections[name] = mapSelectTableToAlias(fields);
|
|
151
|
+
selections[name] = mapSelectTableToAlias(fields, aliasMap);
|
|
150
152
|
} else if (isDrizzleColumn(fields)) {
|
|
151
153
|
const column = fields;
|
|
152
|
-
|
|
154
|
+
const uniqName = `a_${table.getTableName(column.table)}_${column.name}`;
|
|
155
|
+
let aliasName = drizzleOrm.sql.raw(uniqName);
|
|
153
156
|
selections[name] = drizzleOrm.sql`${column} as \`${aliasName}\``;
|
|
157
|
+
aliasMap[uniqName] = column;
|
|
154
158
|
} else if (sql.isSQLWrapper(fields)) {
|
|
155
159
|
selections[name] = fields;
|
|
156
160
|
} else {
|
|
157
161
|
const innerSelections = {};
|
|
158
162
|
Object.entries(fields).forEach(([iname, ifields]) => {
|
|
159
|
-
mapSelectAllFieldsToAlias(innerSelections, iname, ifields);
|
|
163
|
+
mapSelectAllFieldsToAlias(innerSelections, iname, ifields, aliasMap);
|
|
160
164
|
});
|
|
161
165
|
selections[name] = innerSelections;
|
|
162
166
|
}
|
|
@@ -166,11 +170,65 @@ function mapSelectFieldsWithAlias(fields) {
|
|
|
166
170
|
if (!fields) {
|
|
167
171
|
throw new Error("fields is empty");
|
|
168
172
|
}
|
|
173
|
+
const aliasMap = {};
|
|
169
174
|
const selections = {};
|
|
170
175
|
Object.entries(fields).forEach(([name, fields2]) => {
|
|
171
|
-
mapSelectAllFieldsToAlias(selections, name, fields2);
|
|
176
|
+
mapSelectAllFieldsToAlias(selections, name, fields2, aliasMap);
|
|
177
|
+
});
|
|
178
|
+
return { selections, aliasMap };
|
|
179
|
+
}
|
|
180
|
+
function getAliasFromDrizzleAlias(value) {
|
|
181
|
+
const isSQL = value !== null && typeof value === "object" && sql.isSQLWrapper(value) && "queryChunks" in value;
|
|
182
|
+
if (isSQL) {
|
|
183
|
+
const sql2 = value;
|
|
184
|
+
const queryChunks = sql2.queryChunks;
|
|
185
|
+
if (queryChunks.length > 3) {
|
|
186
|
+
const aliasNameChunk = queryChunks[queryChunks.length - 2];
|
|
187
|
+
if (sql.isSQLWrapper(aliasNameChunk) && "queryChunks" in aliasNameChunk) {
|
|
188
|
+
const aliasNameChunkSql = aliasNameChunk;
|
|
189
|
+
if (aliasNameChunkSql && aliasNameChunkSql.queryChunks.length === 1) {
|
|
190
|
+
const queryChunksStringChunc = aliasNameChunkSql.queryChunks[0];
|
|
191
|
+
if (queryChunksStringChunc && "value" in queryChunksStringChunc) {
|
|
192
|
+
const values = queryChunksStringChunc.value;
|
|
193
|
+
if (values && values.length === 1) {
|
|
194
|
+
return values[0];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
function transformValue(value, alias, aliasMap) {
|
|
204
|
+
const column = aliasMap[alias];
|
|
205
|
+
if (!column) return value;
|
|
206
|
+
let customColumn = column;
|
|
207
|
+
const fromDriver = customColumn?.mapFrom;
|
|
208
|
+
if (fromDriver && value !== null && value !== void 0) {
|
|
209
|
+
return fromDriver(value);
|
|
210
|
+
}
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
function transformObject(obj, selections, aliasMap) {
|
|
214
|
+
const result = {};
|
|
215
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
216
|
+
const selection = selections[key];
|
|
217
|
+
const alias = getAliasFromDrizzleAlias(selection);
|
|
218
|
+
if (alias && aliasMap[alias]) {
|
|
219
|
+
result[key] = transformValue(value, alias, aliasMap);
|
|
220
|
+
} else if (selection && typeof selection === "object" && !sql.isSQLWrapper(selection)) {
|
|
221
|
+
result[key] = transformObject(value, selection, aliasMap);
|
|
222
|
+
} else {
|
|
223
|
+
result[key] = value;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
function applyFromDriverTransform(rows, selections, aliasMap) {
|
|
229
|
+
return rows.map((row) => {
|
|
230
|
+
return transformObject(row, selections, aliasMap);
|
|
172
231
|
});
|
|
173
|
-
return selections;
|
|
174
232
|
}
|
|
175
233
|
class ForgeSQLCrudOperations {
|
|
176
234
|
forgeOperations;
|
|
@@ -549,6 +607,52 @@ const forgeDriver = async (query, params, method) => {
|
|
|
549
607
|
throw error;
|
|
550
608
|
}
|
|
551
609
|
};
|
|
610
|
+
function createAliasedSelectBuilder(db, fields, selectFn) {
|
|
611
|
+
const { selections, aliasMap } = mapSelectFieldsWithAlias(fields);
|
|
612
|
+
const builder = selectFn(selections);
|
|
613
|
+
const wrapBuilder = (rawBuilder) => {
|
|
614
|
+
return new Proxy(rawBuilder, {
|
|
615
|
+
get(target, prop, receiver) {
|
|
616
|
+
if (prop === "execute") {
|
|
617
|
+
return async (...args) => {
|
|
618
|
+
const rows = await target.execute(...args);
|
|
619
|
+
return applyFromDriverTransform(rows, selections, aliasMap);
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
if (prop === "then") {
|
|
623
|
+
return (onfulfilled, onrejected) => target.execute().then(
|
|
624
|
+
(rows) => {
|
|
625
|
+
const transformed = applyFromDriverTransform(rows, selections, aliasMap);
|
|
626
|
+
return onfulfilled?.(transformed);
|
|
627
|
+
},
|
|
628
|
+
onrejected
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
const value = Reflect.get(target, prop, receiver);
|
|
632
|
+
if (typeof value === "function") {
|
|
633
|
+
return (...args) => {
|
|
634
|
+
const result = value.apply(target, args);
|
|
635
|
+
if (typeof result === "object" && result !== null && "execute" in result) {
|
|
636
|
+
return wrapBuilder(result);
|
|
637
|
+
}
|
|
638
|
+
return result;
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
return value;
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
};
|
|
645
|
+
return wrapBuilder(builder);
|
|
646
|
+
}
|
|
647
|
+
function patchDbWithSelectAliased(db) {
|
|
648
|
+
db.selectAliased = function(fields) {
|
|
649
|
+
return createAliasedSelectBuilder(db, fields, (selections) => db.select(selections));
|
|
650
|
+
};
|
|
651
|
+
db.selectAliasedDistinct = function(fields) {
|
|
652
|
+
return createAliasedSelectBuilder(db, fields, (selections) => db.selectDistinct(selections));
|
|
653
|
+
};
|
|
654
|
+
return db;
|
|
655
|
+
}
|
|
552
656
|
class ForgeSQLORMImpl {
|
|
553
657
|
static instance = null;
|
|
554
658
|
drizzle;
|
|
@@ -567,7 +671,7 @@ class ForgeSQLORMImpl {
|
|
|
567
671
|
if (newOptions.logRawSqlQuery) {
|
|
568
672
|
console.debug("Initializing ForgeSQLORM...");
|
|
569
673
|
}
|
|
570
|
-
this.drizzle = mysqlProxy.drizzle(forgeDriver, { logger: newOptions.logRawSqlQuery });
|
|
674
|
+
this.drizzle = patchDbWithSelectAliased(mysqlProxy.drizzle(forgeDriver, { logger: newOptions.logRawSqlQuery }));
|
|
571
675
|
this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);
|
|
572
676
|
this.fetchOperations = new ForgeSQLSelectOperations(newOptions);
|
|
573
677
|
} catch (error) {
|
|
@@ -632,7 +736,7 @@ class ForgeSQLORMImpl {
|
|
|
632
736
|
if (!fields) {
|
|
633
737
|
throw new Error("fields is empty");
|
|
634
738
|
}
|
|
635
|
-
return this.drizzle.
|
|
739
|
+
return this.drizzle.selectAliased(fields);
|
|
636
740
|
}
|
|
637
741
|
/**
|
|
638
742
|
* Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
|
|
@@ -654,7 +758,7 @@ class ForgeSQLORMImpl {
|
|
|
654
758
|
if (!fields) {
|
|
655
759
|
throw new Error("fields is empty");
|
|
656
760
|
}
|
|
657
|
-
return this.drizzle.
|
|
761
|
+
return this.drizzle.selectAliasedDistinct(fields);
|
|
658
762
|
}
|
|
659
763
|
}
|
|
660
764
|
class ForgeSQLORM {
|
|
@@ -679,7 +783,7 @@ class ForgeSQLORM {
|
|
|
679
783
|
* ```
|
|
680
784
|
*/
|
|
681
785
|
select(fields) {
|
|
682
|
-
return this.ormInstance.
|
|
786
|
+
return this.ormInstance.select(fields);
|
|
683
787
|
}
|
|
684
788
|
/**
|
|
685
789
|
* Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
|
|
@@ -698,7 +802,7 @@ class ForgeSQLORM {
|
|
|
698
802
|
* ```
|
|
699
803
|
*/
|
|
700
804
|
selectDistinct(fields) {
|
|
701
|
-
return this.ormInstance.
|
|
805
|
+
return this.ormInstance.selectDistinct(fields);
|
|
702
806
|
}
|
|
703
807
|
/**
|
|
704
808
|
* Proxies the `crud` method from `ForgeSQLORMImpl`.
|
|
@@ -794,8 +898,8 @@ const applySchemaMigrations = async (migration) => {
|
|
|
794
898
|
console.log("Provisioning the database");
|
|
795
899
|
await sql$1.sql._provision();
|
|
796
900
|
console.info("Running schema migrations");
|
|
797
|
-
const
|
|
798
|
-
const successfulMigrations = await
|
|
901
|
+
const migrations2 = await migration(sql$1.migrationRunner);
|
|
902
|
+
const successfulMigrations = await migrations2.run();
|
|
799
903
|
console.info("Migrations applied:", successfulMigrations);
|
|
800
904
|
const migrationHistory = (await sql$1.migrationRunner.list()).map((y) => `${y.id}, ${y.name}, ${y.migratedAt.toUTCString()}`).join("\n");
|
|
801
905
|
console.info("Migrations history:\nid, name, migrated_at\n", migrationHistory);
|
|
@@ -806,6 +910,46 @@ const applySchemaMigrations = async (migration) => {
|
|
|
806
910
|
body: "Migrations successfully executed"
|
|
807
911
|
};
|
|
808
912
|
};
|
|
913
|
+
const migrations = mysqlCore.mysqlTable("__migrations", {
|
|
914
|
+
id: mysqlCore.bigint("id", { mode: "number" }).primaryKey().autoincrement(),
|
|
915
|
+
name: mysqlCore.varchar("name", { length: 255 }).notNull(),
|
|
916
|
+
migratedAt: mysqlCore.timestamp("migratedAt").defaultNow().notNull()
|
|
917
|
+
});
|
|
918
|
+
const forgeSystemTables = [migrations];
|
|
919
|
+
async function fetchSchemaWebTrigger() {
|
|
920
|
+
try {
|
|
921
|
+
const tables = await getTables();
|
|
922
|
+
const createTableStatements = await generateCreateTableStatements(tables);
|
|
923
|
+
const sqlStatements = wrapWithForeignKeyChecks(createTableStatements);
|
|
924
|
+
return getHttpResponse(200, sqlStatements.join(";\n"));
|
|
925
|
+
} catch (error) {
|
|
926
|
+
console.error(JSON.stringify(error));
|
|
927
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
928
|
+
return getHttpResponse(500, errorMessage);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
async function getTables() {
|
|
932
|
+
const tables = await sql$1.sql.executeDDL("SHOW TABLES");
|
|
933
|
+
return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
|
|
934
|
+
}
|
|
935
|
+
async function generateCreateTableStatements(tables) {
|
|
936
|
+
const statements = [];
|
|
937
|
+
for (const table2 of tables) {
|
|
938
|
+
const createTableResult = await sql$1.sql.executeDDL(`SHOW CREATE TABLE ${table2}`);
|
|
939
|
+
const createTableStatements = createTableResult.rows.filter((row) => !isSystemTable(row.Table)).map((row) => formatCreateTableStatement(row["Create Table"]));
|
|
940
|
+
statements.push(...createTableStatements);
|
|
941
|
+
}
|
|
942
|
+
return statements;
|
|
943
|
+
}
|
|
944
|
+
function isSystemTable(tableName) {
|
|
945
|
+
return forgeSystemTables.some((st) => table.getTableName(st) === tableName);
|
|
946
|
+
}
|
|
947
|
+
function formatCreateTableStatement(statement) {
|
|
948
|
+
return statement.replace(/"/g, "").replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
|
|
949
|
+
}
|
|
950
|
+
function wrapWithForeignKeyChecks(statements) {
|
|
951
|
+
return ["SET foreign_key_checks = 0", ...statements, "SET foreign_key_checks = 1"];
|
|
952
|
+
}
|
|
809
953
|
const getHttpResponse = (statusCode, body) => {
|
|
810
954
|
let statusText = "";
|
|
811
955
|
if (statusCode === 200) {
|
|
@@ -822,10 +966,12 @@ const getHttpResponse = (statusCode, body) => {
|
|
|
822
966
|
};
|
|
823
967
|
exports.ForgeSQLCrudOperations = ForgeSQLCrudOperations;
|
|
824
968
|
exports.ForgeSQLSelectOperations = ForgeSQLSelectOperations;
|
|
969
|
+
exports.applyFromDriverTransform = applyFromDriverTransform;
|
|
825
970
|
exports.applySchemaMigrations = applySchemaMigrations;
|
|
826
971
|
exports.default = ForgeSQLORM;
|
|
827
972
|
exports.dropSchemaMigrations = dropSchemaMigrations;
|
|
828
973
|
exports.extractAlias = extractAlias;
|
|
974
|
+
exports.fetchSchemaWebTrigger = fetchSchemaWebTrigger;
|
|
829
975
|
exports.forgeDateString = forgeDateString;
|
|
830
976
|
exports.forgeDateTimeString = forgeDateTimeString;
|
|
831
977
|
exports.forgeDriver = forgeDriver;
|
|
@@ -837,6 +983,6 @@ exports.getPrimaryKeys = getPrimaryKeys;
|
|
|
837
983
|
exports.getTableMetadata = getTableMetadata;
|
|
838
984
|
exports.mapSelectAllFieldsToAlias = mapSelectAllFieldsToAlias;
|
|
839
985
|
exports.mapSelectFieldsWithAlias = mapSelectFieldsWithAlias;
|
|
840
|
-
exports.mapSelectTableToAlias = mapSelectTableToAlias;
|
|
841
986
|
exports.parseDateTime = parseDateTime;
|
|
987
|
+
exports.patchDbWithSelectAliased = patchDbWithSelectAliased;
|
|
842
988
|
//# sourceMappingURL=ForgeSQLORM.js.map
|