forge-sql-orm 1.0.30 → 1.1.31
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 +242 -661
- package/dist/ForgeSQLORM.js +541 -568
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +539 -555
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts +101 -130
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +11 -10
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +271 -113
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/ForgeSQLSelectOperations.d.ts +65 -22
- package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +59 -0
- package/dist/core/SystemTables.d.ts.map +1 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/sqlUtils.d.ts +53 -6
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist-cli/cli.js +561 -360
- package/dist-cli/cli.js.map +1 -1
- package/dist-cli/cli.mjs +561 -360
- package/dist-cli/cli.mjs.map +1 -1
- package/package.json +26 -26
- package/src/core/ForgeSQLCrudOperations.ts +360 -473
- package/src/core/ForgeSQLORM.ts +40 -78
- package/src/core/ForgeSQLQueryBuilder.ts +250 -133
- package/src/core/ForgeSQLSelectOperations.ts +182 -72
- package/src/core/SystemTables.ts +7 -0
- package/src/index.ts +1 -2
- package/src/utils/sqlUtils.ts +155 -23
- package/dist/core/ComplexQuerySchemaBuilder.d.ts +0 -38
- package/dist/core/ComplexQuerySchemaBuilder.d.ts.map +0 -1
- package/dist/knex/index.d.ts +0 -4
- package/dist/knex/index.d.ts.map +0 -1
- package/src/core/ComplexQuerySchemaBuilder.ts +0 -63
- package/src/knex/index.ts +0 -4
|
@@ -1,103 +1,213 @@
|
|
|
1
1
|
import { sql, UpdateQueryResponse } from "@forge/sql";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { extractAlias, parseDateTime } from "../utils/sqlUtils";
|
|
3
|
+
import { ForgeSqlOrmOptions, SchemaSqlForgeSql } from "./ForgeSQLQueryBuilder";
|
|
4
|
+
import { AnyMySqlSelect } from "drizzle-orm/mysql-core";
|
|
5
|
+
import {
|
|
6
|
+
AnyMySqlSelectQueryBuilder,
|
|
7
|
+
MySqlSelectDynamic,
|
|
8
|
+
} from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
9
|
+
import { Column, SQL, SQLChunk, StringChunk } from "drizzle-orm";
|
|
8
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Class implementing SQL select operations for ForgeSQL ORM.
|
|
13
|
+
* Provides methods for executing queries and mapping results to entity types.
|
|
14
|
+
*/
|
|
9
15
|
export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
10
|
-
|
|
16
|
+
private readonly options: ForgeSqlOrmOptions;
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new instance of ForgeSQLSelectOperations.
|
|
20
|
+
* @param {ForgeSqlOrmOptions} options - Configuration options for the ORM
|
|
21
|
+
*/
|
|
22
|
+
constructor(options: ForgeSqlOrmOptions) {
|
|
23
|
+
this.options = options;
|
|
24
|
+
}
|
|
25
|
+
|
|
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 };
|
|
14
91
|
}
|
|
15
92
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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 || "";
|
|
24
127
|
}
|
|
128
|
+
return realColumn?.name || "";
|
|
129
|
+
}
|
|
25
130
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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;
|
|
35
151
|
}
|
|
152
|
+
}
|
|
36
153
|
|
|
37
154
|
/**
|
|
38
|
-
* Executes a
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @
|
|
155
|
+
* Executes a Drizzle query and returns a single result.
|
|
156
|
+
* Throws an error if more than one record is returned.
|
|
157
|
+
*
|
|
158
|
+
* @template T - The type of the query builder
|
|
159
|
+
* @param {T} query - The Drizzle query to execute
|
|
160
|
+
* @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} A single result object or undefined
|
|
161
|
+
* @throws {Error} If more than one record is returned
|
|
42
162
|
*/
|
|
43
|
-
async
|
|
44
|
-
|
|
45
|
-
|
|
163
|
+
async executeQueryOnlyOne<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(
|
|
164
|
+
query: T,
|
|
165
|
+
): Promise<
|
|
166
|
+
Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined
|
|
167
|
+
> {
|
|
168
|
+
const results: Awaited<T> = await this.executeQuery<T>(query);
|
|
169
|
+
const datas = results as unknown[];
|
|
170
|
+
if (!datas.length) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
if (datas.length > 1) {
|
|
174
|
+
throw new Error(`Expected 1 record but returned ${datas.length}`);
|
|
175
|
+
}
|
|
46
176
|
|
|
47
|
-
return datas
|
|
48
|
-
const rawModel = r as Record<string, unknown>;
|
|
49
|
-
const newModel = Object.create(schema.meta.prototype) as T;
|
|
50
|
-
|
|
51
|
-
schema.meta.props
|
|
52
|
-
.filter((p) => p.kind === "scalar")
|
|
53
|
-
.forEach((p) => {
|
|
54
|
-
const fieldName = p.name;
|
|
55
|
-
const fieldNames = p.fieldNames;
|
|
56
|
-
const rawFieldName = fieldNames && Array.isArray(fieldNames) ? fieldNames[0] : p.name;
|
|
57
|
-
switch (p.type) {
|
|
58
|
-
case "datetime":
|
|
59
|
-
newModel[fieldName] = parseDateTime(
|
|
60
|
-
rawModel[rawFieldName] as string,
|
|
61
|
-
"YYYY-MM-DDTHH:mm:ss.SSS",
|
|
62
|
-
) as unknown as T[EntityKey<T>];
|
|
63
|
-
break;
|
|
64
|
-
case "date":
|
|
65
|
-
newModel[fieldName] = parseDateTime(rawModel[rawFieldName] as string, "YYYY-MM-DD") as unknown as T[EntityKey<T>];
|
|
66
|
-
break;
|
|
67
|
-
case "time":
|
|
68
|
-
newModel[fieldName] = parseDateTime(rawModel[rawFieldName] as string, "HH:mm:ss.SSS") as unknown as T[EntityKey<T>];
|
|
69
|
-
break;
|
|
70
|
-
default:
|
|
71
|
-
newModel[fieldName] = rawModel[rawFieldName] as unknown as T[EntityKey<T>];
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
return newModel as T;
|
|
75
|
-
});
|
|
177
|
+
return datas[0] as Awaited<T> extends Array<any> ? Awaited<T>[number] : Awaited<T>;
|
|
76
178
|
}
|
|
77
179
|
|
|
78
180
|
/**
|
|
79
181
|
* Executes a raw SQL query and returns the results.
|
|
80
|
-
*
|
|
81
|
-
*
|
|
182
|
+
* Logs the query if logging is enabled.
|
|
183
|
+
*
|
|
184
|
+
* @template T - The type of the result objects
|
|
185
|
+
* @param {string} query - The raw SQL query to execute
|
|
186
|
+
* @param {SqlParameters[]} [params] - Optional SQL parameters
|
|
187
|
+
* @returns {Promise<T[]>} A list of results as objects
|
|
82
188
|
*/
|
|
83
|
-
async executeRawSQL<T extends object | unknown>(query: string): Promise<T[]> {
|
|
189
|
+
async executeRawSQL<T extends object | unknown>(query: string, params?: unknown[]): Promise<T[]> {
|
|
84
190
|
if (this.options.logRawSqlQuery) {
|
|
85
191
|
console.debug("Executing raw SQL: " + query);
|
|
86
192
|
}
|
|
87
|
-
const sqlStatement =
|
|
88
|
-
|
|
193
|
+
const sqlStatement = sql.prepare<T>(query);
|
|
194
|
+
if (params) {
|
|
195
|
+
sqlStatement.bindParams(...params);
|
|
196
|
+
}
|
|
197
|
+
const result = await sqlStatement.execute();
|
|
198
|
+
return result.rows as T[];
|
|
89
199
|
}
|
|
90
200
|
|
|
91
201
|
/**
|
|
92
202
|
* Executes a raw SQL update query.
|
|
93
|
-
* @param query - The raw SQL update query
|
|
94
|
-
* @param params -
|
|
95
|
-
* @returns The update response containing affected rows
|
|
203
|
+
* @param {string} query - The raw SQL update query
|
|
204
|
+
* @param {SqlParameters[]} [params] - Optional SQL parameters
|
|
205
|
+
* @returns {Promise<UpdateQueryResponse>} The update response containing affected rows
|
|
96
206
|
*/
|
|
97
|
-
async executeRawUpdateSQL(query: string, params?:
|
|
207
|
+
async executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse> {
|
|
98
208
|
const sqlStatement = sql.prepare<UpdateQueryResponse>(query);
|
|
99
209
|
if (params) {
|
|
100
|
-
sqlStatement.bindParams(params);
|
|
210
|
+
sqlStatement.bindParams(...params);
|
|
101
211
|
}
|
|
102
212
|
const updateQueryResponseResults = await sqlStatement.execute();
|
|
103
213
|
return updateQueryResponseResults.rows;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core/index";
|
|
2
|
+
|
|
3
|
+
export const migrations = mysqlTable("__migrations", {
|
|
4
|
+
id: int("id").primaryKey().autoincrement(),
|
|
5
|
+
name: varchar("name", { length: 255 }).notNull(),
|
|
6
|
+
created_at: timestamp("created_at").defaultNow().notNull(),
|
|
7
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,6 @@ import ForgeSQLORM from "./core/ForgeSQLORM";
|
|
|
3
3
|
export * from "./core/ForgeSQLQueryBuilder";
|
|
4
4
|
export * from "./core/ForgeSQLCrudOperations";
|
|
5
5
|
export * from "./core/ForgeSQLSelectOperations";
|
|
6
|
-
export * from "
|
|
7
|
-
export * from "@mikro-orm/entity-generator";
|
|
6
|
+
export * from "./utils/sqlUtils";
|
|
8
7
|
|
|
9
8
|
export default ForgeSQLORM;
|
package/src/utils/sqlUtils.ts
CHANGED
|
@@ -1,30 +1,40 @@
|
|
|
1
1
|
import moment from "moment";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { AnyColumn } from "drizzle-orm";
|
|
3
|
+
import { AnyMySqlTable } from "drizzle-orm/mysql-core/index";
|
|
4
|
+
import { PrimaryKeyBuilder } from "drizzle-orm/mysql-core/primary-keys";
|
|
5
|
+
import { AnyIndexBuilder, IndexBuilder } from "drizzle-orm/mysql-core/indexes";
|
|
6
|
+
import { CheckBuilder } from "drizzle-orm/mysql-core/checks";
|
|
7
|
+
import { ForeignKeyBuilder } from "drizzle-orm/mysql-core/foreign-keys";
|
|
8
|
+
import { UniqueConstraintBuilder } from "drizzle-orm/mysql-core/unique-constraint";
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Interface representing table metadata information
|
|
12
|
+
*/
|
|
13
|
+
export interface MetadataInfo {
|
|
14
|
+
/** The name of the table */
|
|
15
|
+
tableName: string;
|
|
16
|
+
/** Record of column names and their corresponding column definitions */
|
|
17
|
+
columns: Record<string, AnyColumn>;
|
|
18
|
+
/** Array of index builders */
|
|
19
|
+
indexes: AnyIndexBuilder[];
|
|
20
|
+
/** Array of check constraint builders */
|
|
21
|
+
checks: CheckBuilder[];
|
|
22
|
+
/** Array of foreign key builders */
|
|
23
|
+
foreignKeys: ForeignKeyBuilder[];
|
|
24
|
+
/** Array of primary key builders */
|
|
25
|
+
primaryKeys: PrimaryKeyBuilder[];
|
|
26
|
+
/** Array of unique constraint builders */
|
|
27
|
+
uniqueConstraints: UniqueConstraintBuilder[];
|
|
28
|
+
/** Array of all extra builders */
|
|
29
|
+
extras: any[];
|
|
7
30
|
}
|
|
8
31
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
case "string":
|
|
16
|
-
return <U>wrapIfNeeded(`${value.value}`,wrapValue);
|
|
17
|
-
case "datetime":
|
|
18
|
-
return <U>wrapIfNeeded(`${moment(value.value as Date).format("YYYY-MM-DDTHH:mm:ss.SSS")}`,wrapValue);
|
|
19
|
-
case "date":
|
|
20
|
-
return <U>wrapIfNeeded(`${moment(value.value as Date).format("YYYY-MM-DD")}`, wrapValue);
|
|
21
|
-
case "time":
|
|
22
|
-
return <U>wrapIfNeeded(`${moment(value.value as Date).format("HH:mm:ss.SSS")}`,wrapValue);
|
|
23
|
-
default:
|
|
24
|
-
return value.value;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Parses a date string into a Date object using the specified format
|
|
34
|
+
* @param value - The date string to parse
|
|
35
|
+
* @param format - The format to use for parsing
|
|
36
|
+
* @returns Date object
|
|
37
|
+
*/
|
|
28
38
|
export const parseDateTime = (value: string, format: string): Date => {
|
|
29
39
|
const m = moment(value, format, true);
|
|
30
40
|
if (!m.isValid()) {
|
|
@@ -32,3 +42,125 @@ export const parseDateTime = (value: string, format: string): Date => {
|
|
|
32
42
|
}
|
|
33
43
|
return m.toDate();
|
|
34
44
|
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Extracts the alias from a SQL query
|
|
48
|
+
* @param query - The SQL query to extract the alias from
|
|
49
|
+
* @returns The extracted alias or the original query if no alias found
|
|
50
|
+
*/
|
|
51
|
+
export function extractAlias(query: string): string {
|
|
52
|
+
const match = query.match(/\bas\s+(['"`]?)([\w*]+)\1$/i);
|
|
53
|
+
return match ? match[2] : query;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Gets primary keys from the schema.
|
|
58
|
+
* @template T - The type of the table schema
|
|
59
|
+
* @param {T} table - The table schema
|
|
60
|
+
* @returns {[string, AnyColumn][] | undefined} Array of primary key name and column pairs or undefined if no primary keys found
|
|
61
|
+
*/
|
|
62
|
+
export function getPrimaryKeys<T extends AnyMySqlTable>(
|
|
63
|
+
table: T,
|
|
64
|
+
): [string, AnyColumn][] | undefined {
|
|
65
|
+
const { columns, primaryKeys } = getTableMetadata(table);
|
|
66
|
+
|
|
67
|
+
// First try to find primary keys in columns
|
|
68
|
+
const columnPrimaryKeys = Object.entries(columns).filter(([, column]) => column.primary) as [
|
|
69
|
+
string,
|
|
70
|
+
AnyColumn,
|
|
71
|
+
][];
|
|
72
|
+
|
|
73
|
+
if (columnPrimaryKeys.length > 0) {
|
|
74
|
+
return columnPrimaryKeys;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// If no primary keys found in columns, check primary key builders
|
|
78
|
+
if (Array.isArray(primaryKeys) && primaryKeys.length > 0) {
|
|
79
|
+
// Collect all primary key columns from all primary key builders
|
|
80
|
+
const primaryKeyColumns = new Set<[string, AnyColumn]>();
|
|
81
|
+
|
|
82
|
+
primaryKeys.forEach((primaryKeyBuilder) => {
|
|
83
|
+
// Get primary key columns from each builder
|
|
84
|
+
Object.entries(columns)
|
|
85
|
+
.filter(([, column]) => {
|
|
86
|
+
// @ts-ignore - PrimaryKeyBuilder has internal columns property
|
|
87
|
+
return primaryKeyBuilder.columns.includes(column);
|
|
88
|
+
})
|
|
89
|
+
.forEach(([name, column]) => {
|
|
90
|
+
primaryKeyColumns.add([name, column]);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const result = Array.from(primaryKeyColumns);
|
|
95
|
+
return result.length > 0 ? result : undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Extracts table metadata from the schema.
|
|
103
|
+
* @param {AnyMySqlTable} table - The table schema
|
|
104
|
+
* @returns {MetadataInfo} Object containing table metadata
|
|
105
|
+
*/
|
|
106
|
+
export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
|
|
107
|
+
const symbols = Object.getOwnPropertySymbols(table);
|
|
108
|
+
const nameSymbol = symbols.find((s) => s.toString().includes("Name"));
|
|
109
|
+
const columnsSymbol = symbols.find((s) => s.toString().includes("Columns"));
|
|
110
|
+
const extraSymbol = symbols.find((s) => s.toString().includes("ExtraConfigBuilder"));
|
|
111
|
+
const foreignKeysSymbol = symbols.find((s) => s.toString().includes("MySqlInlineForeignKeys)"));
|
|
112
|
+
|
|
113
|
+
// Initialize builders arrays
|
|
114
|
+
const builders = {
|
|
115
|
+
indexes: [] as AnyIndexBuilder[],
|
|
116
|
+
checks: [] as CheckBuilder[],
|
|
117
|
+
foreignKeys: [] as ForeignKeyBuilder[],
|
|
118
|
+
primaryKeys: [] as PrimaryKeyBuilder[],
|
|
119
|
+
uniqueConstraints: [] as UniqueConstraintBuilder[],
|
|
120
|
+
extras: [] as any[],
|
|
121
|
+
};
|
|
122
|
+
if (foreignKeysSymbol) {
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
const foreignKeys: any[] = table[foreignKeysSymbol];
|
|
125
|
+
if (foreignKeys) {
|
|
126
|
+
for (const foreignKey of foreignKeys) {
|
|
127
|
+
builders.foreignKeys.push(foreignKey);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Process extra configuration if available
|
|
133
|
+
if (extraSymbol) {
|
|
134
|
+
// @ts-ignore
|
|
135
|
+
const extraConfigBuilder = table[extraSymbol];
|
|
136
|
+
if (extraConfigBuilder && typeof extraConfigBuilder === "function") {
|
|
137
|
+
const configBuilders = extraConfigBuilder(table);
|
|
138
|
+
let configBuildersArray: any[] = [];
|
|
139
|
+
if (!Array.isArray(configBuilders)) {
|
|
140
|
+
configBuildersArray = Object.values(configBuilders);
|
|
141
|
+
} else {
|
|
142
|
+
configBuildersArray = configBuilders as any[];
|
|
143
|
+
}
|
|
144
|
+
configBuildersArray.forEach((builder) => {
|
|
145
|
+
if (builder instanceof IndexBuilder) {
|
|
146
|
+
builders.indexes.push(builder);
|
|
147
|
+
} else if (builder instanceof CheckBuilder) {
|
|
148
|
+
builders.checks.push(builder);
|
|
149
|
+
} else if (builder instanceof ForeignKeyBuilder) {
|
|
150
|
+
builders.foreignKeys.push(builder);
|
|
151
|
+
} else if (builder instanceof PrimaryKeyBuilder) {
|
|
152
|
+
builders.primaryKeys.push(builder);
|
|
153
|
+
} else if (builder instanceof UniqueConstraintBuilder) {
|
|
154
|
+
builders.uniqueConstraints.push(builder);
|
|
155
|
+
}
|
|
156
|
+
builders.extras.push(builder);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
tableName: nameSymbol ? (table as any)[nameSymbol] : "",
|
|
163
|
+
columns: columnsSymbol ? ((table as any)[columnsSymbol] as Record<string, AnyColumn>) : {},
|
|
164
|
+
...builders,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { EntitySchema, EntityProperty } from "..";
|
|
2
|
-
import { ComplexQuerySchemaBuilder } from "./ForgeSQLQueryBuilder";
|
|
3
|
-
export declare class DynamicEntity {
|
|
4
|
-
[key: string]: unknown;
|
|
5
|
-
/**
|
|
6
|
-
* Retrieves a schema field by its original entity property.
|
|
7
|
-
* @param field - The entity property to search for.
|
|
8
|
-
* @returns The corresponding schema field or undefined if not found.
|
|
9
|
-
*/
|
|
10
|
-
getSchemaBySchemaField<TYPE>(field: EntityProperty): TYPE | undefined;
|
|
11
|
-
/**
|
|
12
|
-
* Retrieves a schema field by its alias.
|
|
13
|
-
* @param alias - The alias of the field.
|
|
14
|
-
* @returns The corresponding schema field or undefined if not found.
|
|
15
|
-
*/
|
|
16
|
-
getSchemaByAliasField<TYPE>(alias: string): TYPE | undefined;
|
|
17
|
-
}
|
|
18
|
-
export declare class EntitySchemaBuilder<T> implements ComplexQuerySchemaBuilder<T> {
|
|
19
|
-
private entityClass;
|
|
20
|
-
private properties;
|
|
21
|
-
constructor(entityClass: new () => T);
|
|
22
|
-
/**
|
|
23
|
-
* Adds a field to the schema definition.
|
|
24
|
-
* @param field - The entity property to add.
|
|
25
|
-
* @param alias - (Optional) Custom alias for the field name.
|
|
26
|
-
* @returns The current instance of EntitySchemaBuilder for method chaining.
|
|
27
|
-
*/
|
|
28
|
-
addField<K>(field: Partial<EntityProperty<K>>, alias?: string): this;
|
|
29
|
-
/**
|
|
30
|
-
* Creates and initializes a new EntitySchema based on the added fields.
|
|
31
|
-
* @returns A new EntitySchema<T> instance.
|
|
32
|
-
*/
|
|
33
|
-
createSchema(): EntitySchema<T>;
|
|
34
|
-
}
|
|
35
|
-
export declare class DynamicEntitySchemaBuilder extends EntitySchemaBuilder<DynamicEntity> {
|
|
36
|
-
constructor();
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=ComplexQuerySchemaBuilder.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ComplexQuerySchemaBuilder.d.ts","sourceRoot":"","sources":["../../src/core/ComplexQuerySchemaBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAa,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAC,yBAAyB,EAAC,MAAM,wBAAwB,CAAC;AAEjE,qBAAa,aAAa;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAEvB;;;;OAIG;IACH,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS;IAIrE;;;;OAIG;IACH,qBAAqB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;CAG/D;AAED,qBAAa,mBAAmB,CAAC,CAAC,CAAE,YAAW,yBAAyB,CAAC,CAAC,CAAC;IAG3D,OAAO,CAAC,WAAW;IAF/B,OAAO,CAAC,UAAU,CAAyC;gBAEvC,WAAW,EAAE,UAAU,CAAC;IAE5C;;;;;OAKG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAOpE;;;OAGG;IACH,YAAY,IAAI,YAAY,CAAC,CAAC,CAAC;CASlC;AAED,qBAAa,0BAA2B,SAAQ,mBAAmB,CAAC,aAAa,CAAC;;CAIjF"}
|
package/dist/knex/index.d.ts
DELETED
package/dist/knex/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/knex/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,iBAAiB,CAAC;AAEnC,cAAc,iBAAiB,CAAC;AAChC,eAAe,IAAI,CAAC"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { EntitySchema, EntityProperty, EntityKey } from "..";
|
|
2
|
-
import {ComplexQuerySchemaBuilder} from "./ForgeSQLQueryBuilder";
|
|
3
|
-
|
|
4
|
-
export class DynamicEntity {
|
|
5
|
-
[key: string]: unknown;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Retrieves a schema field by its original entity property.
|
|
9
|
-
* @param field - The entity property to search for.
|
|
10
|
-
* @returns The corresponding schema field or undefined if not found.
|
|
11
|
-
*/
|
|
12
|
-
getSchemaBySchemaField<TYPE>(field: EntityProperty): TYPE | undefined {
|
|
13
|
-
return this[field.name] as TYPE | undefined;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Retrieves a schema field by its alias.
|
|
18
|
-
* @param alias - The alias of the field.
|
|
19
|
-
* @returns The corresponding schema field or undefined if not found.
|
|
20
|
-
*/
|
|
21
|
-
getSchemaByAliasField<TYPE>(alias: string): TYPE | undefined {
|
|
22
|
-
return this[alias] as TYPE | undefined;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class EntitySchemaBuilder<T> implements ComplexQuerySchemaBuilder<T> {
|
|
27
|
-
private properties: Record<string, EntityProperty<T>> = {};
|
|
28
|
-
|
|
29
|
-
constructor(private entityClass: new () => T) {}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Adds a field to the schema definition.
|
|
33
|
-
* @param field - The entity property to add.
|
|
34
|
-
* @param alias - (Optional) Custom alias for the field name.
|
|
35
|
-
* @returns The current instance of EntitySchemaBuilder for method chaining.
|
|
36
|
-
*/
|
|
37
|
-
addField<K>(field: Partial<EntityProperty<K>>, alias?: string): this {
|
|
38
|
-
const fieldName = alias || field.name;
|
|
39
|
-
const fieldNameType = fieldName as unknown as EntityKey<T>;
|
|
40
|
-
this.properties[fieldNameType] = { ...field, name: fieldNameType } as unknown as EntityProperty<T>;
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Creates and initializes a new EntitySchema based on the added fields.
|
|
46
|
-
* @returns A new EntitySchema<T> instance.
|
|
47
|
-
*/
|
|
48
|
-
createSchema(): EntitySchema<T> {
|
|
49
|
-
const es = new EntitySchema<T>({
|
|
50
|
-
class: this.entityClass,
|
|
51
|
-
// @ts-ignore
|
|
52
|
-
properties: this.properties,
|
|
53
|
-
});
|
|
54
|
-
es.init();
|
|
55
|
-
return es;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export class DynamicEntitySchemaBuilder extends EntitySchemaBuilder<DynamicEntity> {
|
|
60
|
-
constructor() {
|
|
61
|
-
super(DynamicEntity);
|
|
62
|
-
}
|
|
63
|
-
}
|
package/src/knex/index.ts
DELETED