forge-sql-orm 2.0.0 → 2.0.2
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 +189 -43
- package/dist/ForgeSQLORM.js +47 -118
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +48 -119
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +1 -2
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +4 -12
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/ForgeSQLSelectOperations.d.ts +0 -38
- package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/forgeDriver.d.ts +3 -0
- package/dist/utils/forgeDriver.d.ts.map +1 -0
- package/dist-cli/cli.js +3 -3
- package/dist-cli/cli.js.map +1 -1
- package/dist-cli/cli.mjs +3 -3
- package/dist-cli/cli.mjs.map +1 -1
- package/package.json +4 -1
- package/src/core/ForgeSQLCrudOperations.ts +11 -19
- package/src/core/ForgeSQLORM.ts +7 -8
- package/src/core/ForgeSQLQueryBuilder.ts +4 -15
- package/src/core/ForgeSQLSelectOperations.ts +1 -132
- package/src/index.ts +1 -0
- package/src/utils/forgeDriver.ts +37 -0
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
**Forge-SQL-ORM** is an ORM designed for working with [@forge/sql](https://developer.atlassian.com/platform/forge/storage-reference/sql-tutorial/) in **Atlassian Forge**. It is built on top of [Drizzle ORM](https://orm.drizzle.team) and provides advanced capabilities for working with relational databases inside Forge.
|
|
6
6
|
|
|
7
7
|
## Key Features
|
|
8
|
+
- ✅ **Custom Drizzle Driver** for direct integration with @forge/sql
|
|
8
9
|
- ✅ **Supports complex SQL queries** with joins and filtering using Drizzle ORM
|
|
9
10
|
- ✅ **Batch insert support** with duplicate key handling
|
|
10
11
|
- ✅ **Schema migration support**, allowing automatic schema evolution
|
|
@@ -14,6 +15,23 @@
|
|
|
14
15
|
- ✅ **Optimistic Locking** Ensures data consistency by preventing conflicts when multiple users update the same record
|
|
15
16
|
- ✅ **Type Safety** Full TypeScript support with proper type inference
|
|
16
17
|
|
|
18
|
+
## Usage Approaches
|
|
19
|
+
|
|
20
|
+
### 1. Direct Drizzle Usage
|
|
21
|
+
```typescript
|
|
22
|
+
import { drizzle } from "drizzle-orm/mysql-core";
|
|
23
|
+
import { forgeDriver } from "forge-sql-orm";
|
|
24
|
+
const db = drizzle(forgeDriver);
|
|
25
|
+
```
|
|
26
|
+
Best for: Simple CRUD operations without optimistic locking
|
|
27
|
+
|
|
28
|
+
### 2. Full Forge-SQL-ORM Usage
|
|
29
|
+
```typescript
|
|
30
|
+
import ForgeSQL from "forge-sql-orm";
|
|
31
|
+
const forgeSQL = new ForgeSQL();
|
|
32
|
+
```
|
|
33
|
+
Best for: Advanced features like optimistic locking and automatic versioning
|
|
34
|
+
|
|
17
35
|
## Installation
|
|
18
36
|
|
|
19
37
|
Forge-SQL-ORM is designed to work with @forge/sql and requires some additional setup to ensure compatibility within Atlassian Forge.
|
|
@@ -22,8 +40,7 @@ Forge-SQL-ORM is designed to work with @forge/sql and requires some additional s
|
|
|
22
40
|
|
|
23
41
|
```sh
|
|
24
42
|
npm install forge-sql-orm -S
|
|
25
|
-
npm install @forge/sql -S
|
|
26
|
-
npm install drizzle-orm mysql2
|
|
43
|
+
npm install @forge/sql drizzle-orm -S
|
|
27
44
|
npm install mysql2 @types/mysql2 -D
|
|
28
45
|
```
|
|
29
46
|
|
|
@@ -33,6 +50,38 @@ This will:
|
|
|
33
50
|
- Install Drizzle ORM and its MySQL driver
|
|
34
51
|
- Install TypeScript types for MySQL
|
|
35
52
|
|
|
53
|
+
## Direct Drizzle Usage with Custom Driver
|
|
54
|
+
|
|
55
|
+
If you prefer to use Drizzle ORM directly without the additional features of Forge-SQL-ORM (like optimistic locking), you can use the custom driver:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { drizzle } from "drizzle-orm/mysql-core";
|
|
59
|
+
import { forgeDriver } from "forge-sql-orm";
|
|
60
|
+
|
|
61
|
+
// Initialize drizzle with the custom driver
|
|
62
|
+
const db = drizzle(forgeDriver);
|
|
63
|
+
|
|
64
|
+
// Use drizzle directly
|
|
65
|
+
const users = await db.select().from(users);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Drizzle Usage with forge-sql-orm
|
|
69
|
+
|
|
70
|
+
If you prefer to use Drizzle ORM with the additional features of Forge-SQL-ORM (like optimistic locking), you can use the custom driver:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import ForgeSQL from "forge-sql-orm";
|
|
74
|
+
const forgeSQL = new ForgeSQL();
|
|
75
|
+
forgeSQL.crud().insert(...);
|
|
76
|
+
forgeSQL.crud().updateById(...);
|
|
77
|
+
const db = forgeSQL.getDrizzleQueryBuilder();
|
|
78
|
+
|
|
79
|
+
// Use drizzle
|
|
80
|
+
const users = await db.select().from(users);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This approach gives you direct access to all Drizzle ORM features while still using the @forge/sql backend.
|
|
84
|
+
|
|
36
85
|
## Step-by-Step Migration Workflow
|
|
37
86
|
|
|
38
87
|
1. **Generate initial schema from an existing database**
|
|
@@ -155,6 +204,68 @@ export default (migrationRunner: MigrationRunner): MigrationRunner => {
|
|
|
155
204
|
|
|
156
205
|
---
|
|
157
206
|
|
|
207
|
+
## Date and Time Types
|
|
208
|
+
|
|
209
|
+
When working with date and time fields in your models, you should use the custom types provided by Forge-SQL-ORM to ensure proper handling of date/time values. This is necessary because Forge SQL has specific format requirements for date/time values:
|
|
210
|
+
|
|
211
|
+
| Date type | Required Format | Example |
|
|
212
|
+
|-----------|----------------|---------|
|
|
213
|
+
| DATE | YYYY-MM-DD | 2024-09-19 |
|
|
214
|
+
| TIME | HH:MM:SS[.fraction] | 06:40:34 |
|
|
215
|
+
| TIMESTAMP | YYYY-MM-DD HH:MM:SS[.fraction] | 2024-09-19 06:40:34.999999 |
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// ❌ Don't use standard Drizzle date/time types
|
|
219
|
+
export const testEntityTimeStampVersion = mysqlTable('test_entity', {
|
|
220
|
+
id: int('id').primaryKey().autoincrement(),
|
|
221
|
+
time_stamp: timestamp('times_tamp').notNull(),
|
|
222
|
+
date_time: datetime('date_time').notNull(),
|
|
223
|
+
time: time('time').notNull(),
|
|
224
|
+
date: date('date').notNull(),
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// ✅ Use Forge-SQL-ORM custom types instead
|
|
228
|
+
import { forgeDateTimeString, forgeDateString, forgeTimestampString, forgeTimeString } from 'forge-sql-orm'
|
|
229
|
+
|
|
230
|
+
export const testEntityTimeStampVersion = mysqlTable('test_entity', {
|
|
231
|
+
id: int('id').primaryKey().autoincrement(),
|
|
232
|
+
time_stamp: forgeTimestampString('times_tamp').notNull(),
|
|
233
|
+
date_time: forgeDateTimeString('date_time').notNull(),
|
|
234
|
+
time: forgeTimeString('time').notNull(),
|
|
235
|
+
date: forgeDateString('date').notNull(),
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Why Custom Types?
|
|
240
|
+
|
|
241
|
+
The custom types in Forge-SQL-ORM handle the conversion between JavaScript Date objects and Forge SQL's required string formats automatically. Without these custom types, you would need to manually format dates like this:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
// Without custom types, you'd need to do this manually:
|
|
245
|
+
const date = moment().format("YYYY-MM-DD");
|
|
246
|
+
const time = moment().format("HH:mm:ss.SSS");
|
|
247
|
+
const timestamp = moment().format("YYYY-MM-DDTHH:mm:ss.SSS");
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Our custom types provide:
|
|
251
|
+
- Automatic conversion between JavaScript Date objects and Forge SQL's required string formats
|
|
252
|
+
- Consistent date/time handling across your application
|
|
253
|
+
- Type safety for date/time fields
|
|
254
|
+
- Proper handling of timezone conversions
|
|
255
|
+
- Support for all Forge SQL date/time types (datetime, timestamp, date, time)
|
|
256
|
+
|
|
257
|
+
### Available Custom Types
|
|
258
|
+
|
|
259
|
+
- `forgeDateTimeString` - For datetime fields (YYYY-MM-DD HH:MM:SS[.fraction])
|
|
260
|
+
- `forgeTimestampString` - For timestamp fields (YYYY-MM-DD HH:MM:SS[.fraction])
|
|
261
|
+
- `forgeDateString` - For date fields (YYYY-MM-DD)
|
|
262
|
+
- `forgeTimeString` - For time fields (HH:MM:SS[.fraction])
|
|
263
|
+
|
|
264
|
+
Each type ensures that the data is properly formatted according to Forge SQL's requirements while providing a clean, type-safe interface for your application code.
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
158
269
|
# Connection to ORM
|
|
159
270
|
|
|
160
271
|
```js
|
|
@@ -162,20 +273,35 @@ import ForgeSQL from "forge-sql-orm";
|
|
|
162
273
|
|
|
163
274
|
const forgeSQL = new ForgeSQL();
|
|
164
275
|
```
|
|
276
|
+
or
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { drizzle } from "drizzle-orm/mysql-core";
|
|
280
|
+
import { forgeDriver } from "forge-sql-orm";
|
|
281
|
+
|
|
282
|
+
// Initialize drizzle with the custom driver
|
|
283
|
+
const db = drizzle(forgeDriver);
|
|
284
|
+
|
|
285
|
+
// Use drizzle directly
|
|
286
|
+
const users = await db.select().from(users);
|
|
287
|
+
```
|
|
165
288
|
|
|
166
289
|
## Fetch Data
|
|
167
290
|
|
|
168
291
|
### Basic Fetch Operations
|
|
169
292
|
|
|
170
293
|
```js
|
|
171
|
-
// Using
|
|
294
|
+
// Using forgeSQL.getDrizzleQueryBuilder()
|
|
172
295
|
const user = await forgeSQL
|
|
173
|
-
.
|
|
174
|
-
.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
296
|
+
.getDrizzleQueryBuilder()
|
|
297
|
+
.select("*").from(Users)
|
|
298
|
+
.where(eq(Users.id, 1));
|
|
299
|
+
|
|
300
|
+
// OR using direct drizzle with custom driver
|
|
301
|
+
const db = drizzle(forgeDriver);
|
|
302
|
+
const user = await db
|
|
303
|
+
.select("*").from(Users)
|
|
304
|
+
.where(eq(Users.id, 1));
|
|
179
305
|
// Returns: { id: 1, name: "John Doe" }
|
|
180
306
|
|
|
181
307
|
// Using executeQueryOnlyOne for single result with error handling
|
|
@@ -191,34 +317,47 @@ const user = await forgeSQL
|
|
|
191
317
|
// Throws error if multiple records found
|
|
192
318
|
// Returns undefined if no records found
|
|
193
319
|
|
|
194
|
-
// Using
|
|
320
|
+
// Using with aliases
|
|
321
|
+
// With forgeSQL
|
|
195
322
|
const usersAlias = alias(Users, "u");
|
|
196
323
|
const result = await forgeSQL
|
|
197
|
-
.
|
|
198
|
-
.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
324
|
+
.getDrizzleQueryBuilder()
|
|
325
|
+
.select({
|
|
326
|
+
userId: rawSql`${usersAlias.id} as \`userId\``,
|
|
327
|
+
userName: rawSql`${usersAlias.name} as \`userName\``
|
|
328
|
+
}).from(usersAlias);
|
|
329
|
+
|
|
330
|
+
// OR with direct drizzle
|
|
331
|
+
const db = drizzle(forgeDriver);
|
|
332
|
+
const result = await db
|
|
333
|
+
.select({
|
|
334
|
+
userId: rawSql`${usersAlias.id} as \`userId\``,
|
|
335
|
+
userName: rawSql`${usersAlias.name} as \`userName\``
|
|
336
|
+
}).from(usersAlias);
|
|
206
337
|
// Returns: { userId: 1, userName: "John Doe" }
|
|
207
338
|
|
|
208
|
-
// Using
|
|
339
|
+
// Using joins
|
|
340
|
+
// With forgeSQL
|
|
209
341
|
const orderWithUser = await forgeSQL
|
|
210
|
-
.
|
|
211
|
-
.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
342
|
+
.getDrizzleQueryBuilder()
|
|
343
|
+
.select({
|
|
344
|
+
orderId: rawSql`${Orders.id} as \`orderId\``,
|
|
345
|
+
product: Orders.product,
|
|
346
|
+
userName: rawSql`${Users.name} as \`userName\``
|
|
347
|
+
}).from(Orders)
|
|
348
|
+
.innerJoin(Users, eq(Orders.userId, Users.id))
|
|
349
|
+
.where(eq(Orders.id, 1));
|
|
350
|
+
|
|
351
|
+
// OR with direct drizzle
|
|
352
|
+
const db = drizzle(forgeDriver);
|
|
353
|
+
const orderWithUser = await db
|
|
354
|
+
.select({
|
|
355
|
+
orderId: rawSql`${Orders.id} as \`orderId\``,
|
|
356
|
+
product: Orders.product,
|
|
357
|
+
userName: rawSql`${Users.name} as \`userName\``
|
|
358
|
+
}).from(Orders)
|
|
359
|
+
.innerJoin(Users, eq(Orders.userId, Users.id))
|
|
360
|
+
.where(eq(Orders.id, 1));
|
|
222
361
|
// Returns: { orderId: 1, product: "Product 1", userName: "John Doe" }
|
|
223
362
|
```
|
|
224
363
|
|
|
@@ -226,18 +365,25 @@ const orderWithUser = await forgeSQL
|
|
|
226
365
|
|
|
227
366
|
```js
|
|
228
367
|
// Finding duplicates
|
|
368
|
+
// With forgeSQL
|
|
229
369
|
const duplicates = await forgeSQL
|
|
230
|
-
.
|
|
231
|
-
.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
370
|
+
.getDrizzleQueryBuilder()
|
|
371
|
+
.select({
|
|
372
|
+
name: Users.name,
|
|
373
|
+
count: rawSql`COUNT(*) as \`count\``
|
|
374
|
+
}).from(Users)
|
|
375
|
+
.groupBy(Users.name)
|
|
376
|
+
.having(rawSql`COUNT(*) > 1`);
|
|
377
|
+
|
|
378
|
+
// OR with direct drizzle
|
|
379
|
+
const db = drizzle(forgeDriver);
|
|
380
|
+
const duplicates = await db
|
|
381
|
+
.select({
|
|
382
|
+
name: Users.name,
|
|
383
|
+
count: rawSql`COUNT(*) as \`count\``
|
|
384
|
+
}).from(Users)
|
|
385
|
+
.groupBy(Users.name)
|
|
386
|
+
.having(rawSql`COUNT(*) > 1`);
|
|
241
387
|
// Returns: { name: "John Doe", count: 2 }
|
|
242
388
|
|
|
243
389
|
// Using executeQueryOnlyOne for unique results
|
package/dist/ForgeSQLORM.js
CHANGED
|
@@ -124,8 +124,8 @@ class ForgeSQLCrudOperations {
|
|
|
124
124
|
if (this.options?.logRawSqlQuery) {
|
|
125
125
|
console.debug("INSERT SQL:", query.sql);
|
|
126
126
|
}
|
|
127
|
-
const result = await
|
|
128
|
-
return result.insertId;
|
|
127
|
+
const result = await finalQuery;
|
|
128
|
+
return result[0].insertId;
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
131
|
* Deletes a record by its primary key with optional version check.
|
|
@@ -161,8 +161,8 @@ class ForgeSQLCrudOperations {
|
|
|
161
161
|
if (this.options?.logRawSqlQuery) {
|
|
162
162
|
console.debug("DELETE SQL:", queryBuilder.toSQL().sql);
|
|
163
163
|
}
|
|
164
|
-
const result = await
|
|
165
|
-
return result.affectedRows;
|
|
164
|
+
const result = await queryBuilder;
|
|
165
|
+
return result[0].affectedRows;
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
168
168
|
* Updates a record by its primary key with optimistic locking support.
|
|
@@ -211,13 +211,13 @@ class ForgeSQLCrudOperations {
|
|
|
211
211
|
if (this.options?.logRawSqlQuery) {
|
|
212
212
|
console.debug("UPDATE SQL:", queryBuilder.toSQL().sql);
|
|
213
213
|
}
|
|
214
|
-
const result = await
|
|
215
|
-
if (versionMetadata && result.affectedRows === 0) {
|
|
214
|
+
const result = await queryBuilder;
|
|
215
|
+
if (versionMetadata && result[0].affectedRows === 0) {
|
|
216
216
|
throw new Error(
|
|
217
217
|
`Optimistic locking failed: record with primary key ${entity[primaryKeyName]} has been modified`
|
|
218
218
|
);
|
|
219
219
|
}
|
|
220
|
-
return result.affectedRows;
|
|
220
|
+
return result[0].affectedRows;
|
|
221
221
|
}
|
|
222
222
|
/**
|
|
223
223
|
* Updates specified fields of records based on provided conditions.
|
|
@@ -239,8 +239,8 @@ class ForgeSQLCrudOperations {
|
|
|
239
239
|
if (this.options?.logRawSqlQuery) {
|
|
240
240
|
console.debug("UPDATE SQL:", queryBuilder.toSQL().sql);
|
|
241
241
|
}
|
|
242
|
-
const result = await
|
|
243
|
-
return result.affectedRows;
|
|
242
|
+
const result = await queryBuilder;
|
|
243
|
+
return result[0].affectedRows;
|
|
244
244
|
}
|
|
245
245
|
// Helper methods
|
|
246
246
|
/**
|
|
@@ -387,105 +387,6 @@ class ForgeSQLSelectOperations {
|
|
|
387
387
|
constructor(options) {
|
|
388
388
|
this.options = options;
|
|
389
389
|
}
|
|
390
|
-
/**
|
|
391
|
-
* Executes a Drizzle query and returns the results.
|
|
392
|
-
* Maps the raw database results to the appropriate entity types.
|
|
393
|
-
*
|
|
394
|
-
* @template T - The type of the query builder
|
|
395
|
-
* @param {T} query - The Drizzle query to execute
|
|
396
|
-
* @returns {Promise<Awaited<T>>} The query results mapped to entity types
|
|
397
|
-
*/
|
|
398
|
-
async executeQuery(query) {
|
|
399
|
-
const queryType = query;
|
|
400
|
-
const querySql = queryType.toSQL();
|
|
401
|
-
const datas = await this.executeRawSQL(querySql.sql, querySql.params);
|
|
402
|
-
if (!datas.length) return [];
|
|
403
|
-
return datas.map((r) => {
|
|
404
|
-
const rawModel = r;
|
|
405
|
-
const newModel = {};
|
|
406
|
-
const columns = queryType.config.fields;
|
|
407
|
-
Object.entries(columns).forEach(([name, column]) => {
|
|
408
|
-
const { realColumn, aliasName } = this.extractColumnInfo(column);
|
|
409
|
-
const value = rawModel[aliasName];
|
|
410
|
-
if (value === null || value === void 0) {
|
|
411
|
-
newModel[name] = value;
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
newModel[name] = this.parseColumnValue(realColumn, value);
|
|
415
|
-
});
|
|
416
|
-
return newModel;
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Extracts column information and alias name from a column definition.
|
|
421
|
-
* @param {any} column - The column definition from Drizzle
|
|
422
|
-
* @returns {Object} Object containing the real column and its alias name
|
|
423
|
-
*/
|
|
424
|
-
extractColumnInfo(column) {
|
|
425
|
-
if (column instanceof drizzleOrm.SQL) {
|
|
426
|
-
const realColumnSql = column;
|
|
427
|
-
const realColumn = realColumnSql.queryChunks.find(
|
|
428
|
-
(q) => q instanceof drizzleOrm.Column
|
|
429
|
-
);
|
|
430
|
-
let stringChunk = this.findAliasChunk(realColumnSql);
|
|
431
|
-
let withoutAlias = false;
|
|
432
|
-
if (!realColumn && (!stringChunk || !stringChunk.value || !stringChunk.value?.length)) {
|
|
433
|
-
stringChunk = realColumnSql.queryChunks.filter((q) => q instanceof drizzleOrm.StringChunk).find((q) => q.value[0]);
|
|
434
|
-
withoutAlias = true;
|
|
435
|
-
}
|
|
436
|
-
const aliasName = this.resolveAliasName(stringChunk, realColumn, withoutAlias);
|
|
437
|
-
return { realColumn, aliasName };
|
|
438
|
-
}
|
|
439
|
-
return { realColumn: column, aliasName: column.name };
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Finds the alias chunk in SQL query chunks.
|
|
443
|
-
* @param {SQL} realColumnSql - The SQL query chunks
|
|
444
|
-
* @returns {StringChunk | undefined} The string chunk containing the alias or undefined
|
|
445
|
-
*/
|
|
446
|
-
findAliasChunk(realColumnSql) {
|
|
447
|
-
return realColumnSql.queryChunks.filter((q) => q instanceof drizzleOrm.StringChunk).find(
|
|
448
|
-
(q) => q.value.find((f) => f.toLowerCase().includes("as"))
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Resolves the alias name from the string chunk or column.
|
|
453
|
-
* @param {StringChunk | undefined} stringChunk - The string chunk containing the alias
|
|
454
|
-
* @param {Column | undefined} realColumn - The real column definition
|
|
455
|
-
* @param {boolean} withoutAlias - Whether the column has no alias
|
|
456
|
-
* @returns {string} The resolved alias name
|
|
457
|
-
*/
|
|
458
|
-
resolveAliasName(stringChunk, realColumn, withoutAlias) {
|
|
459
|
-
if (stringChunk) {
|
|
460
|
-
if (withoutAlias) {
|
|
461
|
-
return stringChunk.value[0];
|
|
462
|
-
}
|
|
463
|
-
const asClause = stringChunk.value.find((f) => f.toLowerCase().includes("as"));
|
|
464
|
-
return asClause ? extractAlias(asClause.trim()) : realColumn?.name || "";
|
|
465
|
-
}
|
|
466
|
-
return realColumn?.name || "";
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Parses a column value based on its SQL type.
|
|
470
|
-
* Handles datetime, date, and time types with appropriate formatting.
|
|
471
|
-
*
|
|
472
|
-
* @param {Column} column - The column definition
|
|
473
|
-
* @param {unknown} value - The raw value to parse
|
|
474
|
-
* @returns {unknown} The parsed value
|
|
475
|
-
*/
|
|
476
|
-
parseColumnValue(column, value) {
|
|
477
|
-
if (!column) return value;
|
|
478
|
-
switch (column.getSQLType()) {
|
|
479
|
-
case "datetime":
|
|
480
|
-
return parseDateTime(value, "YYYY-MM-DDTHH:mm:ss.SSS");
|
|
481
|
-
case "date":
|
|
482
|
-
return parseDateTime(value, "YYYY-MM-DD");
|
|
483
|
-
case "time":
|
|
484
|
-
return parseDateTime(value, "HH:mm:ss.SSS");
|
|
485
|
-
default:
|
|
486
|
-
return value;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
390
|
/**
|
|
490
391
|
* Executes a Drizzle query and returns a single result.
|
|
491
392
|
* Throws an error if more than one record is returned.
|
|
@@ -496,7 +397,7 @@ class ForgeSQLSelectOperations {
|
|
|
496
397
|
* @throws {Error} If more than one record is returned
|
|
497
398
|
*/
|
|
498
399
|
async executeQueryOnlyOne(query) {
|
|
499
|
-
const results = await
|
|
400
|
+
const results = await query;
|
|
500
401
|
const datas = results;
|
|
501
402
|
if (!datas.length) {
|
|
502
403
|
return void 0;
|
|
@@ -544,6 +445,33 @@ class ForgeSQLSelectOperations {
|
|
|
544
445
|
return updateQueryResponseResults.rows;
|
|
545
446
|
}
|
|
546
447
|
}
|
|
448
|
+
const forgeDriver = {
|
|
449
|
+
query: async (query, params) => {
|
|
450
|
+
try {
|
|
451
|
+
const sqlStatement = await sql.sql.prepare(query.sql);
|
|
452
|
+
if (params) {
|
|
453
|
+
await sqlStatement.bindParams(...params);
|
|
454
|
+
}
|
|
455
|
+
const result = await sqlStatement.execute();
|
|
456
|
+
let rows;
|
|
457
|
+
if (Array.isArray(result.rows)) {
|
|
458
|
+
rows = [
|
|
459
|
+
result.rows.map((r) => Object.values(r))
|
|
460
|
+
];
|
|
461
|
+
} else {
|
|
462
|
+
rows = [
|
|
463
|
+
result.rows
|
|
464
|
+
];
|
|
465
|
+
}
|
|
466
|
+
return rows;
|
|
467
|
+
} catch (error) {
|
|
468
|
+
console.error("SQL Error:", JSON.stringify(error));
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
transaction: async (transactionFn) => {
|
|
473
|
+
}
|
|
474
|
+
};
|
|
547
475
|
class ForgeSQLORMImpl {
|
|
548
476
|
static instance = null;
|
|
549
477
|
drizzle;
|
|
@@ -562,7 +490,7 @@ class ForgeSQLORMImpl {
|
|
|
562
490
|
if (newOptions.logRawSqlQuery) {
|
|
563
491
|
console.debug("Initializing ForgeSQLORM...");
|
|
564
492
|
}
|
|
565
|
-
this.drizzle = mysql2.drizzle(
|
|
493
|
+
this.drizzle = mysql2.drizzle(forgeDriver);
|
|
566
494
|
this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);
|
|
567
495
|
this.fetchOperations = new ForgeSQLSelectOperations(newOptions);
|
|
568
496
|
} catch (error) {
|
|
@@ -640,7 +568,7 @@ class ForgeSQLORM {
|
|
|
640
568
|
return this.ormInstance.getDrizzleQueryBuilder();
|
|
641
569
|
}
|
|
642
570
|
}
|
|
643
|
-
const
|
|
571
|
+
const forgeDateTimeString = mysqlCore.customType({
|
|
644
572
|
dataType() {
|
|
645
573
|
return "datetime";
|
|
646
574
|
},
|
|
@@ -652,7 +580,7 @@ const mySqlDateTimeString = mysqlCore.customType({
|
|
|
652
580
|
return parseDateTime(value, format);
|
|
653
581
|
}
|
|
654
582
|
});
|
|
655
|
-
const
|
|
583
|
+
const forgeTimestampString = mysqlCore.customType({
|
|
656
584
|
dataType() {
|
|
657
585
|
return "timestamp";
|
|
658
586
|
},
|
|
@@ -664,7 +592,7 @@ const mySqlTimestampString = mysqlCore.customType({
|
|
|
664
592
|
return parseDateTime(value, format);
|
|
665
593
|
}
|
|
666
594
|
});
|
|
667
|
-
const
|
|
595
|
+
const forgeDateString = mysqlCore.customType({
|
|
668
596
|
dataType() {
|
|
669
597
|
return "date";
|
|
670
598
|
},
|
|
@@ -676,7 +604,7 @@ const mySqlDateString = mysqlCore.customType({
|
|
|
676
604
|
return parseDateTime(value, format);
|
|
677
605
|
}
|
|
678
606
|
});
|
|
679
|
-
const
|
|
607
|
+
const forgeTimeString = mysqlCore.customType({
|
|
680
608
|
dataType() {
|
|
681
609
|
return "time";
|
|
682
610
|
},
|
|
@@ -691,11 +619,12 @@ exports.ForgeSQLCrudOperations = ForgeSQLCrudOperations;
|
|
|
691
619
|
exports.ForgeSQLSelectOperations = ForgeSQLSelectOperations;
|
|
692
620
|
exports.default = ForgeSQLORM;
|
|
693
621
|
exports.extractAlias = extractAlias;
|
|
622
|
+
exports.forgeDateString = forgeDateString;
|
|
623
|
+
exports.forgeDateTimeString = forgeDateTimeString;
|
|
624
|
+
exports.forgeDriver = forgeDriver;
|
|
625
|
+
exports.forgeTimeString = forgeTimeString;
|
|
626
|
+
exports.forgeTimestampString = forgeTimestampString;
|
|
694
627
|
exports.getPrimaryKeys = getPrimaryKeys;
|
|
695
628
|
exports.getTableMetadata = getTableMetadata;
|
|
696
|
-
exports.mySqlDateString = mySqlDateString;
|
|
697
|
-
exports.mySqlDateTimeString = mySqlDateTimeString;
|
|
698
|
-
exports.mySqlTimeString = mySqlTimeString;
|
|
699
|
-
exports.mySqlTimestampString = mySqlTimestampString;
|
|
700
629
|
exports.parseDateTime = parseDateTime;
|
|
701
630
|
//# sourceMappingURL=ForgeSQLORM.js.map
|