forge-sql-orm 2.0.0 → 2.0.1
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 +39 -110
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +40 -111
- 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 +0 -8
- 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.map +1 -1
- 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 +0 -11
- package/src/core/ForgeSQLSelectOperations.ts +1 -132
- package/src/index.ts +1 -0
- package/src/utils/forgeDriver.ts +37 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { sql, UpdateQueryResponse } from "@forge/sql";
|
|
2
|
-
import { extractAlias, parseDateTime } from "../utils/sqlUtils";
|
|
3
2
|
import { ForgeSqlOrmOptions, SchemaSqlForgeSql } from "./ForgeSQLQueryBuilder";
|
|
4
|
-
import { AnyMySqlSelect } from "drizzle-orm/mysql-core";
|
|
5
3
|
import {
|
|
6
4
|
AnyMySqlSelectQueryBuilder,
|
|
7
5
|
MySqlSelectDynamic,
|
|
8
6
|
} from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
9
|
-
import { Column, SQL, SQLChunk, StringChunk } from "drizzle-orm";
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* Class implementing SQL select operations for ForgeSQL ORM.
|
|
@@ -23,134 +20,6 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
|
23
20
|
this.options = options;
|
|
24
21
|
}
|
|
25
22
|
|
|
26
|
-
/**
|
|
27
|
-
* Executes a Drizzle query and returns the results.
|
|
28
|
-
* Maps the raw database results to the appropriate entity types.
|
|
29
|
-
*
|
|
30
|
-
* @template T - The type of the query builder
|
|
31
|
-
* @param {T} query - The Drizzle query to execute
|
|
32
|
-
* @returns {Promise<Awaited<T>>} The query results mapped to entity types
|
|
33
|
-
*/
|
|
34
|
-
async executeQuery<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(
|
|
35
|
-
query: T,
|
|
36
|
-
): Promise<Awaited<T>> {
|
|
37
|
-
const queryType = <AnyMySqlSelect>query;
|
|
38
|
-
const querySql = queryType.toSQL();
|
|
39
|
-
const datas = await this.executeRawSQL<unknown>(querySql.sql, querySql.params);
|
|
40
|
-
|
|
41
|
-
if (!datas.length) return [] as Awaited<T>;
|
|
42
|
-
|
|
43
|
-
return datas.map((r) => {
|
|
44
|
-
const rawModel = r as Record<string, unknown>;
|
|
45
|
-
const newModel: any = {};
|
|
46
|
-
|
|
47
|
-
// @ts-ignore - Drizzle internal property
|
|
48
|
-
const columns = queryType.config.fields;
|
|
49
|
-
|
|
50
|
-
Object.entries(columns).forEach(([name, column]: [string, any]) => {
|
|
51
|
-
const { realColumn, aliasName } = this.extractColumnInfo(column);
|
|
52
|
-
const value = rawModel[aliasName];
|
|
53
|
-
|
|
54
|
-
if (value === null || value === undefined) {
|
|
55
|
-
newModel[name] = value;
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
newModel[name] = this.parseColumnValue(realColumn, value);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
return newModel;
|
|
63
|
-
}) as Awaited<T>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Extracts column information and alias name from a column definition.
|
|
68
|
-
* @param {any} column - The column definition from Drizzle
|
|
69
|
-
* @returns {Object} Object containing the real column and its alias name
|
|
70
|
-
*/
|
|
71
|
-
private extractColumnInfo(column: any): { realColumn: Column; aliasName: string } {
|
|
72
|
-
if (column instanceof SQL) {
|
|
73
|
-
const realColumnSql = <SQL>column;
|
|
74
|
-
const realColumn = realColumnSql.queryChunks.find(
|
|
75
|
-
(q: SQLChunk) => q instanceof Column,
|
|
76
|
-
) as Column;
|
|
77
|
-
|
|
78
|
-
let stringChunk = this.findAliasChunk(realColumnSql);
|
|
79
|
-
let withoutAlias = false;
|
|
80
|
-
|
|
81
|
-
if (!realColumn && (!stringChunk || !stringChunk.value || !stringChunk.value?.length)) {
|
|
82
|
-
stringChunk = realColumnSql.queryChunks
|
|
83
|
-
.filter((q: SQLChunk) => q instanceof StringChunk)
|
|
84
|
-
.find((q: SQLChunk) => (q as StringChunk).value[0]) as StringChunk;
|
|
85
|
-
withoutAlias = true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const aliasName = this.resolveAliasName(stringChunk, realColumn, withoutAlias);
|
|
89
|
-
|
|
90
|
-
return { realColumn, aliasName };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return { realColumn: column, aliasName: column.name };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Finds the alias chunk in SQL query chunks.
|
|
98
|
-
* @param {SQL} realColumnSql - The SQL query chunks
|
|
99
|
-
* @returns {StringChunk | undefined} The string chunk containing the alias or undefined
|
|
100
|
-
*/
|
|
101
|
-
private findAliasChunk(realColumnSql: SQL): StringChunk | undefined {
|
|
102
|
-
return realColumnSql.queryChunks
|
|
103
|
-
.filter((q: SQLChunk) => q instanceof StringChunk)
|
|
104
|
-
.find((q: SQLChunk) =>
|
|
105
|
-
(q as StringChunk).value.find((f) => f.toLowerCase().includes("as")),
|
|
106
|
-
) as StringChunk;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Resolves the alias name from the string chunk or column.
|
|
111
|
-
* @param {StringChunk | undefined} stringChunk - The string chunk containing the alias
|
|
112
|
-
* @param {Column | undefined} realColumn - The real column definition
|
|
113
|
-
* @param {boolean} withoutAlias - Whether the column has no alias
|
|
114
|
-
* @returns {string} The resolved alias name
|
|
115
|
-
*/
|
|
116
|
-
private resolveAliasName(
|
|
117
|
-
stringChunk: StringChunk | undefined,
|
|
118
|
-
realColumn: Column | undefined,
|
|
119
|
-
withoutAlias: boolean,
|
|
120
|
-
): string {
|
|
121
|
-
if (stringChunk) {
|
|
122
|
-
if (withoutAlias) {
|
|
123
|
-
return stringChunk.value[0];
|
|
124
|
-
}
|
|
125
|
-
const asClause = stringChunk.value.find((f) => f.toLowerCase().includes("as"));
|
|
126
|
-
return asClause ? extractAlias(asClause.trim()) : realColumn?.name || "";
|
|
127
|
-
}
|
|
128
|
-
return realColumn?.name || "";
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Parses a column value based on its SQL type.
|
|
133
|
-
* Handles datetime, date, and time types with appropriate formatting.
|
|
134
|
-
*
|
|
135
|
-
* @param {Column} column - The column definition
|
|
136
|
-
* @param {unknown} value - The raw value to parse
|
|
137
|
-
* @returns {unknown} The parsed value
|
|
138
|
-
*/
|
|
139
|
-
private parseColumnValue(column: Column, value: unknown): unknown {
|
|
140
|
-
if (!column) return value;
|
|
141
|
-
|
|
142
|
-
switch (column.getSQLType()) {
|
|
143
|
-
case "datetime":
|
|
144
|
-
return parseDateTime(value as string, "YYYY-MM-DDTHH:mm:ss.SSS");
|
|
145
|
-
case "date":
|
|
146
|
-
return parseDateTime(value as string, "YYYY-MM-DD");
|
|
147
|
-
case "time":
|
|
148
|
-
return parseDateTime(value as string, "HH:mm:ss.SSS");
|
|
149
|
-
default:
|
|
150
|
-
return value;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
23
|
/**
|
|
155
24
|
* Executes a Drizzle query and returns a single result.
|
|
156
25
|
* Throws an error if more than one record is returned.
|
|
@@ -165,7 +34,7 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
|
165
34
|
): Promise<
|
|
166
35
|
Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined
|
|
167
36
|
> {
|
|
168
|
-
const results: Awaited<T> = await
|
|
37
|
+
const results: Awaited<T> = await query;
|
|
169
38
|
const datas = results as unknown[];
|
|
170
39
|
if (!datas.length) {
|
|
171
40
|
return undefined;
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sql } from "@forge/sql";
|
|
2
|
+
import {AnyMySql2Connection} from "drizzle-orm/mysql2/driver";
|
|
3
|
+
|
|
4
|
+
interface ForgeSQLResult {
|
|
5
|
+
rows: Record<string, unknown>[] | Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const forgeDriver = {
|
|
9
|
+
query: async (query: { sql: string }, params?: unknown[]) => {
|
|
10
|
+
try {
|
|
11
|
+
const sqlStatement = await sql.prepare<unknown>(query.sql);
|
|
12
|
+
if (params) {
|
|
13
|
+
await sqlStatement.bindParams(...params);
|
|
14
|
+
}
|
|
15
|
+
const result = await sqlStatement.execute() as ForgeSQLResult;
|
|
16
|
+
|
|
17
|
+
let rows;
|
|
18
|
+
if (Array.isArray(result.rows)) {
|
|
19
|
+
rows = [
|
|
20
|
+
result.rows.map(r => Object.values(r as Record<string, unknown>))
|
|
21
|
+
];
|
|
22
|
+
} else {
|
|
23
|
+
rows = [
|
|
24
|
+
result.rows as Record<string, unknown>
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return rows;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error("SQL Error:", JSON.stringify(error));
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
transaction: async (transactionFn: (tx: any) => Promise<void>) => {
|
|
35
|
+
// Implementation will be added later
|
|
36
|
+
},
|
|
37
|
+
} as unknown as AnyMySql2Connection;
|