forge-sql-orm 2.0.1 → 2.0.3
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 +1 -1
- package/dist/ForgeSQLORM.js +8 -23
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +8 -23
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +4 -4
- package/dist/utils/forgeDriver.d.ts.map +1 -1
- 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 +1 -1
- package/src/core/ForgeSQLCrudOperations.ts +0 -18
- package/src/core/ForgeSQLQueryBuilder.ts +4 -4
- package/src/utils/forgeDriver.ts +1 -4
package/README.md
CHANGED
|
@@ -225,7 +225,7 @@ export const testEntityTimeStampVersion = mysqlTable('test_entity', {
|
|
|
225
225
|
});
|
|
226
226
|
|
|
227
227
|
// ✅ Use Forge-SQL-ORM custom types instead
|
|
228
|
-
import { forgeDateTimeString, forgeDateString,
|
|
228
|
+
import { forgeDateTimeString, forgeDateString, forgeTimestampString, forgeTimeString } from 'forge-sql-orm'
|
|
229
229
|
|
|
230
230
|
export const testEntityTimeStampVersion = mysqlTable('test_entity', {
|
|
231
231
|
id: int('id').primaryKey().autoincrement(),
|
package/dist/ForgeSQLORM.js
CHANGED
|
@@ -120,10 +120,6 @@ class ForgeSQLCrudOperations {
|
|
|
120
120
|
Object.keys(preparedModels[0]).map((key) => [key, schema[key]])
|
|
121
121
|
)
|
|
122
122
|
}) : queryBuilder;
|
|
123
|
-
const query = finalQuery.toSQL();
|
|
124
|
-
if (this.options?.logRawSqlQuery) {
|
|
125
|
-
console.debug("INSERT SQL:", query.sql);
|
|
126
|
-
}
|
|
127
123
|
const result = await finalQuery;
|
|
128
124
|
return result[0].insertId;
|
|
129
125
|
}
|
|
@@ -158,9 +154,6 @@ class ForgeSQLCrudOperations {
|
|
|
158
154
|
}
|
|
159
155
|
}
|
|
160
156
|
const queryBuilder = this.forgeOperations.getDrizzleQueryBuilder().delete(schema).where(drizzleOrm.and(...conditions));
|
|
161
|
-
if (this.options?.logRawSqlQuery) {
|
|
162
|
-
console.debug("DELETE SQL:", queryBuilder.toSQL().sql);
|
|
163
|
-
}
|
|
164
157
|
const result = await queryBuilder;
|
|
165
158
|
return result[0].affectedRows;
|
|
166
159
|
}
|
|
@@ -208,9 +201,6 @@ class ForgeSQLCrudOperations {
|
|
|
208
201
|
}
|
|
209
202
|
}
|
|
210
203
|
const queryBuilder = this.forgeOperations.getDrizzleQueryBuilder().update(schema).set(updateData).where(drizzleOrm.and(...conditions));
|
|
211
|
-
if (this.options?.logRawSqlQuery) {
|
|
212
|
-
console.debug("UPDATE SQL:", queryBuilder.toSQL().sql);
|
|
213
|
-
}
|
|
214
204
|
const result = await queryBuilder;
|
|
215
205
|
if (versionMetadata && result[0].affectedRows === 0) {
|
|
216
206
|
throw new Error(
|
|
@@ -236,9 +226,6 @@ class ForgeSQLCrudOperations {
|
|
|
236
226
|
throw new Error("WHERE conditions must be provided");
|
|
237
227
|
}
|
|
238
228
|
const queryBuilder = this.forgeOperations.getDrizzleQueryBuilder().update(schema).set(updateData).where(where);
|
|
239
|
-
if (this.options?.logRawSqlQuery) {
|
|
240
|
-
console.debug("UPDATE SQL:", queryBuilder.toSQL().sql);
|
|
241
|
-
}
|
|
242
229
|
const result = await queryBuilder;
|
|
243
230
|
return result[0].affectedRows;
|
|
244
231
|
}
|
|
@@ -468,8 +455,6 @@ const forgeDriver = {
|
|
|
468
455
|
console.error("SQL Error:", JSON.stringify(error));
|
|
469
456
|
throw error;
|
|
470
457
|
}
|
|
471
|
-
},
|
|
472
|
-
transaction: async (transactionFn) => {
|
|
473
458
|
}
|
|
474
459
|
};
|
|
475
460
|
class ForgeSQLORMImpl {
|
|
@@ -568,7 +553,7 @@ class ForgeSQLORM {
|
|
|
568
553
|
return this.ormInstance.getDrizzleQueryBuilder();
|
|
569
554
|
}
|
|
570
555
|
}
|
|
571
|
-
const
|
|
556
|
+
const forgeDateTimeString = mysqlCore.customType({
|
|
572
557
|
dataType() {
|
|
573
558
|
return "datetime";
|
|
574
559
|
},
|
|
@@ -580,7 +565,7 @@ const mySqlDateTimeString = mysqlCore.customType({
|
|
|
580
565
|
return parseDateTime(value, format);
|
|
581
566
|
}
|
|
582
567
|
});
|
|
583
|
-
const
|
|
568
|
+
const forgeTimestampString = mysqlCore.customType({
|
|
584
569
|
dataType() {
|
|
585
570
|
return "timestamp";
|
|
586
571
|
},
|
|
@@ -592,7 +577,7 @@ const mySqlTimestampString = mysqlCore.customType({
|
|
|
592
577
|
return parseDateTime(value, format);
|
|
593
578
|
}
|
|
594
579
|
});
|
|
595
|
-
const
|
|
580
|
+
const forgeDateString = mysqlCore.customType({
|
|
596
581
|
dataType() {
|
|
597
582
|
return "date";
|
|
598
583
|
},
|
|
@@ -604,7 +589,7 @@ const mySqlDateString = mysqlCore.customType({
|
|
|
604
589
|
return parseDateTime(value, format);
|
|
605
590
|
}
|
|
606
591
|
});
|
|
607
|
-
const
|
|
592
|
+
const forgeTimeString = mysqlCore.customType({
|
|
608
593
|
dataType() {
|
|
609
594
|
return "time";
|
|
610
595
|
},
|
|
@@ -619,12 +604,12 @@ exports.ForgeSQLCrudOperations = ForgeSQLCrudOperations;
|
|
|
619
604
|
exports.ForgeSQLSelectOperations = ForgeSQLSelectOperations;
|
|
620
605
|
exports.default = ForgeSQLORM;
|
|
621
606
|
exports.extractAlias = extractAlias;
|
|
607
|
+
exports.forgeDateString = forgeDateString;
|
|
608
|
+
exports.forgeDateTimeString = forgeDateTimeString;
|
|
622
609
|
exports.forgeDriver = forgeDriver;
|
|
610
|
+
exports.forgeTimeString = forgeTimeString;
|
|
611
|
+
exports.forgeTimestampString = forgeTimestampString;
|
|
623
612
|
exports.getPrimaryKeys = getPrimaryKeys;
|
|
624
613
|
exports.getTableMetadata = getTableMetadata;
|
|
625
|
-
exports.mySqlDateString = mySqlDateString;
|
|
626
|
-
exports.mySqlDateTimeString = mySqlDateTimeString;
|
|
627
|
-
exports.mySqlTimeString = mySqlTimeString;
|
|
628
|
-
exports.mySqlTimestampString = mySqlTimestampString;
|
|
629
614
|
exports.parseDateTime = parseDateTime;
|
|
630
615
|
//# sourceMappingURL=ForgeSQLORM.js.map
|
package/dist/ForgeSQLORM.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForgeSQLORM.js","sources":["../src/utils/sqlUtils.ts","../src/core/ForgeSQLCrudOperations.ts","../src/core/ForgeSQLSelectOperations.ts","../src/utils/forgeDriver.ts","../src/core/ForgeSQLORM.ts","../src/core/ForgeSQLQueryBuilder.ts"],"sourcesContent":["import moment from \"moment\";\nimport { AnyColumn } from \"drizzle-orm\";\nimport { AnyMySqlTable } from \"drizzle-orm/mysql-core/index\";\nimport { PrimaryKeyBuilder } from \"drizzle-orm/mysql-core/primary-keys\";\nimport { AnyIndexBuilder } from \"drizzle-orm/mysql-core/indexes\";\nimport { CheckBuilder } from \"drizzle-orm/mysql-core/checks\";\nimport { ForeignKeyBuilder } from \"drizzle-orm/mysql-core/foreign-keys\";\nimport { UniqueConstraintBuilder } from \"drizzle-orm/mysql-core/unique-constraint\";\n\n/**\n * Interface representing table metadata information\n */\nexport interface MetadataInfo {\n /** The name of the table */\n tableName: string;\n /** Record of column names and their corresponding column definitions */\n columns: Record<string, AnyColumn>;\n /** Array of index builders */\n indexes: AnyIndexBuilder[];\n /** Array of check constraint builders */\n checks: CheckBuilder[];\n /** Array of foreign key builders */\n foreignKeys: ForeignKeyBuilder[];\n /** Array of primary key builders */\n primaryKeys: PrimaryKeyBuilder[];\n /** Array of unique constraint builders */\n uniqueConstraints: UniqueConstraintBuilder[];\n /** Array of all extra builders */\n extras: any[];\n}\n\n/**\n * Interface for config builder data\n */\ninterface ConfigBuilderData {\n value?: any;\n [key: string]: any;\n}\n\n/**\n * Parses a date string into a Date object using the specified format\n * @param value - The date string to parse\n * @param format - The format to use for parsing\n * @returns Date object\n */\nexport const parseDateTime = (value: string, format: string): Date => {\n const m = moment(value, format, true);\n if (!m.isValid()) {\n return moment(value).toDate();\n }\n return m.toDate();\n};\n\n/**\n * Extracts the alias from a SQL query\n * @param query - The SQL query to extract the alias from\n * @returns The extracted alias or the original query if no alias found\n */\nexport function extractAlias(query: string): string {\n const match = query.match(/\\bas\\s+(['\"`]?)([\\w*]+)\\1$/i);\n return match ? match[2] : query;\n}\n\n/**\n * Gets primary keys from the schema.\n * @template T - The type of the table schema\n * @param {T} table - The table schema\n * @returns {[string, AnyColumn][]} Array of primary key name and column pairs\n */\nexport function getPrimaryKeys<T extends AnyMySqlTable>(table: T): [string, AnyColumn][] {\n const { columns, primaryKeys } = getTableMetadata(table);\n\n // First try to find primary keys in columns\n const columnPrimaryKeys = Object.entries(columns).filter(([, column]) => column.primary) as [\n string,\n AnyColumn,\n ][];\n\n if (columnPrimaryKeys.length > 0) {\n return columnPrimaryKeys;\n }\n\n // If no primary keys found in columns, check primary key builders\n if (Array.isArray(primaryKeys) && primaryKeys.length > 0) {\n // Collect all primary key columns from all primary key builders\n const primaryKeyColumns = new Set<[string, AnyColumn]>();\n\n primaryKeys.forEach((primaryKeyBuilder) => {\n // Get primary key columns from each builder\n Object.entries(columns)\n .filter(([, column]) => {\n // @ts-ignore - PrimaryKeyBuilder has internal columns property\n return primaryKeyBuilder.columns.includes(column);\n })\n .forEach(([name, column]) => {\n primaryKeyColumns.add([name, column]);\n });\n });\n\n return Array.from(primaryKeyColumns);\n }\n\n return [];\n}\n\n/**\n * Extracts table metadata from the schema.\n * @param {AnyMySqlTable} table - The table schema\n * @returns {MetadataInfo} Object containing table metadata\n */\nexport function getTableMetadata(table: AnyMySqlTable): MetadataInfo {\n const symbols = Object.getOwnPropertySymbols(table);\n const nameSymbol = symbols.find((s) => s.toString().includes(\"Name\"));\n const columnsSymbol = symbols.find((s) => s.toString().includes(\"Columns\"));\n const extraSymbol = symbols.find((s) => s.toString().includes(\"ExtraConfigBuilder\"));\n\n // Initialize builders arrays\n const builders = {\n indexes: [] as AnyIndexBuilder[],\n checks: [] as CheckBuilder[],\n foreignKeys: [] as ForeignKeyBuilder[],\n primaryKeys: [] as PrimaryKeyBuilder[],\n uniqueConstraints: [] as UniqueConstraintBuilder[],\n extras: [] as any[],\n };\n\n // Process extra configuration if available\n if (extraSymbol) {\n // @ts-ignore\n const extraConfigBuilder = table[extraSymbol];\n if (extraConfigBuilder && typeof extraConfigBuilder === \"function\") {\n const configBuilderData = extraConfigBuilder(table);\n if (configBuilderData) {\n // Convert configBuilderData to array if it's an object\n const configBuilders = Array.isArray(configBuilderData)\n ? configBuilderData\n : Object.values(configBuilderData).map(\n (item) => (item as ConfigBuilderData).value || item,\n );\n\n // Process each builder\n configBuilders.forEach((builder) => {\n if (!builder?.constructor) return;\n\n const builderName = builder.constructor.name.toLowerCase();\n\n // Map builder types to their corresponding arrays\n const builderMap = {\n indexbuilder: builders.indexes,\n checkbuilder: builders.checks,\n foreignkeybuilder: builders.foreignKeys,\n primarykeybuilder: builders.primaryKeys,\n uniqueconstraintbuilder: builders.uniqueConstraints,\n };\n\n // Add builder to appropriate array if it matches any type\n for (const [type, array] of Object.entries(builderMap)) {\n if (builderName.includes(type)) {\n array.push(builder);\n break;\n }\n }\n\n // Always add to extras array\n builders.extras.push(builder);\n });\n }\n }\n }\n\n return {\n tableName: nameSymbol ? (table as any)[nameSymbol] : \"\",\n columns: columnsSymbol ? ((table as any)[columnsSymbol] as Record<string, AnyColumn>) : {},\n ...builders,\n };\n}\n","import { ForgeSqlOrmOptions } from \"..\";\nimport { CRUDForgeSQL, ForgeSqlOperation } from \"./ForgeSQLQueryBuilder\";\nimport { AnyMySqlTable } from \"drizzle-orm/mysql-core/index\";\nimport { AnyColumn, InferInsertModel } from \"drizzle-orm\";\nimport { eq, and } from \"drizzle-orm\";\nimport { SQL } from \"drizzle-orm\";\nimport { getPrimaryKeys, getTableMetadata } from \"../utils/sqlUtils\";\n\n/**\n * Class implementing CRUD operations for ForgeSQL ORM.\n * Provides methods for inserting, updating, and deleting records with support for optimistic locking.\n */\nexport class ForgeSQLCrudOperations implements CRUDForgeSQL {\n private readonly forgeOperations: ForgeSqlOperation;\n private readonly options: ForgeSqlOrmOptions;\n\n /**\n * Creates a new instance of ForgeSQLCrudOperations.\n * @param forgeSqlOperations - The ForgeSQL operations instance\n * @param options - Configuration options for the ORM\n */\n constructor(forgeSqlOperations: ForgeSqlOperation, options: ForgeSqlOrmOptions) {\n this.forgeOperations = forgeSqlOperations;\n this.options = options;\n }\n\n /**\n * Inserts records into the database with optional versioning support.\n * If a version field exists in the schema, versioning is applied.\n *\n * @template T - The type of the table schema\n * @param {T} schema - The entity schema\n * @param {Partial<InferInsertModel<T>>[]} models - Array of entities to insert\n * @param {boolean} [updateIfExists=false] - Whether to update existing records\n * @returns {Promise<number>} The number of inserted rows\n * @throws {Error} If the insert operation fails\n */\n async insert<T extends AnyMySqlTable>(\n schema: T,\n models: Partial<InferInsertModel<T>>[],\n updateIfExists: boolean = false,\n ): Promise<number> {\n if (!models?.length) return 0;\n\n const { tableName, columns } = getTableMetadata(schema);\n const versionMetadata = this.validateVersionField(tableName, columns);\n\n // Prepare models with version field if needed\n const preparedModels = models.map((model) =>\n this.prepareModelWithVersion(model, versionMetadata, columns),\n );\n\n // Build insert query\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .insert(schema)\n .values(preparedModels);\n\n // Add onDuplicateKeyUpdate if needed\n const finalQuery = updateIfExists\n ? queryBuilder.onDuplicateKeyUpdate({\n set: Object.fromEntries(\n Object.keys(preparedModels[0]).map((key) => [key, (schema as any)[key]]),\n ) as any,\n })\n : queryBuilder;\n\n // Execute query\n const query = finalQuery.toSQL();\n if (this.options?.logRawSqlQuery) {\n console.debug(\"INSERT SQL:\", query.sql);\n }\n\n const result = await finalQuery;\n return result[0].insertId;\n }\n\n /**\n * Deletes a record by its primary key with optional version check.\n * If versioning is enabled, ensures the record hasn't been modified since last read.\n *\n * @template T - The type of the table schema\n * @param {unknown} id - The ID of the record to delete\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} Number of affected rows\n * @throws {Error} If the delete operation fails\n * @throws {Error} If multiple primary keys are found\n */\n async deleteById<T extends AnyMySqlTable>(id: unknown, schema: T): Promise<number> {\n const { tableName, columns } = getTableMetadata(schema);\n const primaryKeys = this.getPrimaryKeys(schema);\n\n if (primaryKeys.length !== 1) {\n throw new Error(\"Only single primary key is supported\");\n }\n\n const [primaryKeyName, primaryKeyColumn] = primaryKeys[0];\n const versionMetadata = this.validateVersionField(tableName, columns);\n\n // Build delete conditions\n const conditions: SQL<unknown>[] = [eq(primaryKeyColumn, id)];\n\n // Add version check if needed\n if (versionMetadata && columns) {\n const versionField = columns[versionMetadata.fieldName];\n if (versionField) {\n const oldModel = await this.getOldModel({ [primaryKeyName]: id }, schema, [\n versionMetadata.fieldName,\n versionField,\n ]);\n conditions.push(eq(versionField, (oldModel as any)[versionMetadata.fieldName]));\n }\n }\n\n // Execute delete query\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .delete(schema)\n .where(and(...conditions));\n\n if (this.options?.logRawSqlQuery) {\n console.debug(\"DELETE SQL:\", queryBuilder.toSQL().sql);\n }\n\n const result =await queryBuilder;\n result\n\n return result[0].affectedRows;\n }\n\n /**\n * Updates a record by its primary key with optimistic locking support.\n * If versioning is enabled:\n * - Retrieves the current version\n * - Checks for concurrent modifications\n * - Increments the version on successful update\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity with updated values\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} Number of affected rows\n * @throws {Error} If the primary key is not provided\n * @throws {Error} If optimistic locking check fails\n * @throws {Error} If multiple primary keys are found\n */\n async updateById<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n schema: T,\n ): Promise<number> {\n const { tableName, columns } = getTableMetadata(schema);\n const primaryKeys = this.getPrimaryKeys(schema);\n\n if (primaryKeys.length !== 1) {\n throw new Error(\"Only single primary key is supported\");\n }\n\n const [primaryKeyName, primaryKeyColumn] = primaryKeys[0];\n const versionMetadata = this.validateVersionField(tableName, columns);\n\n // Validate primary key\n if (!(primaryKeyName in entity)) {\n throw new Error(`Primary key ${primaryKeyName} must be provided in the entity`);\n }\n\n // Get current version if needed\n const currentVersion = await this.getCurrentVersion(\n entity,\n primaryKeyName,\n versionMetadata,\n columns,\n schema,\n );\n\n // Prepare update data with version\n const updateData = this.prepareUpdateData(entity, versionMetadata, columns, currentVersion);\n\n // Build update conditions\n const conditions: SQL<unknown>[] = [\n eq(primaryKeyColumn, entity[primaryKeyName as keyof typeof entity]),\n ];\n if (versionMetadata && columns) {\n const versionField = columns[versionMetadata.fieldName];\n if (versionField) {\n conditions.push(eq(versionField, currentVersion));\n }\n }\n\n // Execute update query\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .update(schema)\n .set(updateData)\n .where(and(...conditions));\n\n if (this.options?.logRawSqlQuery) {\n console.debug(\"UPDATE SQL:\", queryBuilder.toSQL().sql);\n }\n\n const result = await queryBuilder;\n // Check optimistic locking\n if (versionMetadata && result[0].affectedRows === 0) {\n throw new Error(\n `Optimistic locking failed: record with primary key ${entity[primaryKeyName as keyof typeof entity]} has been modified`,\n );\n }\n\n return result[0].affectedRows;\n }\n\n /**\n * Updates specified fields of records based on provided conditions.\n * This method does not support versioning and should be used with caution.\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} updateData - The data to update\n * @param {T} schema - The entity schema\n * @param {SQL<unknown>} where - The WHERE conditions\n * @returns {Promise<number>} Number of affected rows\n * @throws {Error} If WHERE conditions are not provided\n * @throws {Error} If the update operation fails\n */\n async updateFields<T extends AnyMySqlTable>(\n updateData: Partial<InferInsertModel<T>>,\n schema: T,\n where?: SQL<unknown>,\n ): Promise<number> {\n if (!where) {\n throw new Error(\"WHERE conditions must be provided\");\n }\n\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .update(schema)\n .set(updateData)\n .where(where);\n\n if (this.options?.logRawSqlQuery) {\n console.debug(\"UPDATE SQL:\", queryBuilder.toSQL().sql);\n }\n\n const result = await queryBuilder;\n return result[0].affectedRows;\n }\n\n // Helper methods\n\n /**\n * Gets primary keys from the schema.\n * @template T - The type of the table schema\n * @param {T} schema - The table schema\n * @returns {[string, AnyColumn][]} Array of primary key name and column pairs\n * @throws {Error} If no primary keys are found\n */\n private getPrimaryKeys<T extends AnyMySqlTable>(schema: T): [string, AnyColumn][] {\n const primaryKeys = getPrimaryKeys(schema);\n if (!primaryKeys) {\n throw new Error(`No primary keys found for schema: ${schema}`);\n }\n\n return primaryKeys;\n }\n\n /**\n * Validates and retrieves version field metadata.\n * @param {string} tableName - The name of the table\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @returns {Object | undefined} Version field metadata if valid, undefined otherwise\n */\n private validateVersionField(\n tableName: string,\n columns: Record<string, AnyColumn>,\n ): { fieldName: string; type: string } | undefined {\n if (this.options.disableOptimisticLocking) {\n return undefined;\n }\n const versionMetadata = this.options.additionalMetadata?.[tableName]?.versionField;\n if (!versionMetadata) return undefined;\n\n const versionField = columns[versionMetadata.fieldName];\n if (!versionField) {\n console.warn(\n `Version field \"${versionMetadata.fieldName}\" not found in table ${tableName}. Versioning will be skipped.`,\n );\n return undefined;\n }\n\n if (!versionField.notNull) {\n console.warn(\n `Version field \"${versionMetadata.fieldName}\" in table ${tableName} is nullable. Versioning may not work correctly.`,\n );\n return undefined;\n }\n\n const fieldType = versionField.getSQLType();\n const isSupportedType =\n fieldType === \"datetime\" ||\n fieldType === \"timestamp\" ||\n fieldType === \"int\" ||\n fieldType === \"number\" ||\n fieldType === \"decimal\";\n\n if (!isSupportedType) {\n console.warn(\n `Version field \"${versionMetadata.fieldName}\" in table ${tableName} has unsupported type \"${fieldType}\". ` +\n `Only datetime, timestamp, int, and decimal types are supported for versioning. Versioning will be skipped.`,\n );\n return undefined;\n }\n\n return { fieldName: versionMetadata.fieldName, type: fieldType };\n }\n\n /**\n * Gets the current version of an entity.\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity\n * @param {string} primaryKeyName - The name of the primary key\n * @param {Object | undefined} versionMetadata - Version field metadata\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @param {T} schema - The table schema\n * @returns {Promise<unknown>} The current version value\n */\n private async getCurrentVersion<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n primaryKeyName: string,\n versionMetadata: { fieldName: string; type: string } | undefined,\n columns: Record<string, AnyColumn>,\n schema: T,\n ): Promise<unknown> {\n if (!versionMetadata || !columns) return undefined;\n\n const versionField = columns[versionMetadata.fieldName];\n if (!versionField) return undefined;\n\n if (versionMetadata.fieldName in entity) {\n return entity[versionMetadata.fieldName as keyof typeof entity];\n }\n\n const oldModel = await this.getOldModel(\n { [primaryKeyName]: entity[primaryKeyName as keyof typeof entity] },\n schema,\n [versionMetadata.fieldName, versionField],\n );\n\n return (oldModel as any)[versionMetadata.fieldName];\n }\n\n /**\n * Prepares a model for insertion with version field.\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} model - The model to prepare\n * @param {Object | undefined} versionMetadata - Version field metadata\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @returns {InferInsertModel<T>} The prepared model\n */\n private prepareModelWithVersion<T extends AnyMySqlTable>(\n model: Partial<InferInsertModel<T>>,\n versionMetadata: { fieldName: string; type: string } | undefined,\n columns: Record<string, AnyColumn>,\n ): InferInsertModel<T> {\n if (!versionMetadata || !columns) return model as InferInsertModel<T>;\n\n const versionField = columns[versionMetadata.fieldName];\n if (!versionField) return model as InferInsertModel<T>;\n\n const modelWithVersion = { ...model };\n const fieldType = versionField.getSQLType();\n const versionValue = fieldType === \"datetime\" || fieldType === \"timestamp\" ? new Date() : 1;\n modelWithVersion[versionMetadata.fieldName as keyof typeof modelWithVersion] =\n versionValue as any;\n\n return modelWithVersion as InferInsertModel<T>;\n }\n\n /**\n * Prepares update data with version field.\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity to update\n * @param {Object | undefined} versionMetadata - Version field metadata\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @param {unknown} currentVersion - The current version value\n * @returns {Partial<InferInsertModel<T>>} The prepared update data\n */\n private prepareUpdateData<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n versionMetadata: { fieldName: string; type: string } | undefined,\n columns: Record<string, AnyColumn>,\n currentVersion: unknown,\n ): Partial<InferInsertModel<T>> {\n const updateData = { ...entity };\n\n if (versionMetadata && columns) {\n const versionField = columns[versionMetadata.fieldName];\n if (versionField) {\n const fieldType = versionField.getSQLType();\n updateData[versionMetadata.fieldName as keyof typeof updateData] =\n fieldType === \"datetime\" || fieldType === \"timestamp\"\n ? new Date()\n : (((currentVersion as number) + 1) as any);\n }\n }\n\n return updateData;\n }\n\n /**\n * Retrieves an existing model by primary key.\n * @template T - The type of the table schema\n * @param {Record<string, unknown>} primaryKeyValues - The primary key values\n * @param {T} schema - The table schema\n * @param {[string, AnyColumn]} versionField - The version field name and column\n * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} The existing model\n * @throws {Error} If the record is not found\n */\n private async getOldModel<T extends AnyMySqlTable>(\n primaryKeyValues: Record<string, unknown>,\n schema: T,\n versionField: [string, AnyColumn],\n ): Promise<\n Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined\n > {\n const [versionFieldName, versionFieldColumn] = versionField;\n const primaryKeys = this.getPrimaryKeys(schema);\n const [primaryKeyName, primaryKeyColumn] = primaryKeys[0];\n\n const resultQuery = this.forgeOperations\n .getDrizzleQueryBuilder()\n .select({\n [primaryKeyName]: primaryKeyColumn as any,\n [versionFieldName]: versionFieldColumn as any,\n })\n .from(schema)\n .where(eq(primaryKeyColumn, primaryKeyValues[primaryKeyName]));\n\n const model = await this.forgeOperations.fetch().executeQueryOnlyOne(resultQuery);\n\n if (!model) {\n throw new Error(`Record not found in table ${schema}`);\n }\n\n return model as Awaited<T> extends Array<any> ? Awaited<T>[number] : Awaited<T>;\n }\n}\n","import { sql, UpdateQueryResponse } from \"@forge/sql\";\nimport { ForgeSqlOrmOptions, SchemaSqlForgeSql } from \"./ForgeSQLQueryBuilder\";\nimport {\n AnyMySqlSelectQueryBuilder,\n MySqlSelectDynamic,\n} from \"drizzle-orm/mysql-core/query-builders/select.types\";\n\n/**\n * Class implementing SQL select operations for ForgeSQL ORM.\n * Provides methods for executing queries and mapping results to entity types.\n */\nexport class ForgeSQLSelectOperations implements SchemaSqlForgeSql {\n private readonly options: ForgeSqlOrmOptions;\n\n /**\n * Creates a new instance of ForgeSQLSelectOperations.\n * @param {ForgeSqlOrmOptions} options - Configuration options for the ORM\n */\n constructor(options: ForgeSqlOrmOptions) {\n this.options = options;\n }\n\n /**\n * Executes a Drizzle query and returns a single result.\n * Throws an error if more than one record is returned.\n *\n * @template T - The type of the query builder\n * @param {T} query - The Drizzle query to execute\n * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} A single result object or undefined\n * @throws {Error} If more than one record is returned\n */\n async executeQueryOnlyOne<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(\n query: T,\n ): Promise<\n Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined\n > {\n const results: Awaited<T> = await query;\n const datas = results as unknown[];\n if (!datas.length) {\n return undefined;\n }\n if (datas.length > 1) {\n throw new Error(`Expected 1 record but returned ${datas.length}`);\n }\n\n return datas[0] as Awaited<T> extends Array<any> ? Awaited<T>[number] : Awaited<T>;\n }\n\n /**\n * Executes a raw SQL query and returns the results.\n * Logs the query if logging is enabled.\n *\n * @template T - The type of the result objects\n * @param {string} query - The raw SQL query to execute\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<T[]>} A list of results as objects\n */\n async executeRawSQL<T extends object | unknown>(query: string, params?: unknown[]): Promise<T[]> {\n if (this.options.logRawSqlQuery) {\n console.debug(\"Executing raw SQL: \" + query);\n }\n const sqlStatement = sql.prepare<T>(query);\n if (params) {\n if (this.options.logRawSqlQuery && this.options.logRawSqlQueryParams) {\n console.debug(\"Executing with SQL Params: \" + JSON.stringify(params));\n }\n sqlStatement.bindParams(...params);\n }\n const result = await sqlStatement.execute();\n return result.rows as T[];\n }\n\n /**\n * Executes a raw SQL update query.\n * @param {string} query - The raw SQL update query\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<UpdateQueryResponse>} The update response containing affected rows\n */\n async executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse> {\n const sqlStatement = sql.prepare<UpdateQueryResponse>(query);\n if (params) {\n sqlStatement.bindParams(...params);\n }\n const updateQueryResponseResults = await sqlStatement.execute();\n return updateQueryResponseResults.rows;\n }\n}\n","import { sql } from \"@forge/sql\";\nimport {AnyMySql2Connection} from \"drizzle-orm/mysql2/driver\";\n\ninterface ForgeSQLResult {\n rows: Record<string, unknown>[] | Record<string, unknown>;\n}\n\nexport const forgeDriver = {\n query: async (query: { sql: string }, params?: unknown[]) => {\n try {\n const sqlStatement = await sql.prepare<unknown>(query.sql);\n if (params) {\n await sqlStatement.bindParams(...params);\n }\n const result = await sqlStatement.execute() as ForgeSQLResult;\n\n let rows;\n if (Array.isArray(result.rows)) {\n rows = [\n result.rows.map(r => Object.values(r as Record<string, unknown>))\n ];\n } else {\n rows = [\n result.rows as Record<string, unknown>\n ];\n }\n\n return rows;\n } catch (error) {\n console.error(\"SQL Error:\", JSON.stringify(error));\n throw error;\n }\n },\n transaction: async (transactionFn: (tx: any) => Promise<void>) => {\n // Implementation will be added later\n },\n} as unknown as AnyMySql2Connection;","import { ForgeSQLCrudOperations } from \"./ForgeSQLCrudOperations\";\nimport {\n CRUDForgeSQL,\n ForgeSqlOperation,\n ForgeSqlOrmOptions,\n SchemaSqlForgeSql,\n} from \"./ForgeSQLQueryBuilder\";\nimport { ForgeSQLSelectOperations } from \"./ForgeSQLSelectOperations\";\nimport { drizzle } from \"drizzle-orm/mysql2\";\nimport { forgeDriver } from \"../utils/forgeDriver\";\n\n/**\n * Implementation of ForgeSQLORM that uses Drizzle ORM for query building.\n * This class provides a bridge between Forge SQL and Drizzle ORM, allowing\n * to use Drizzle's query builder while executing queries through Forge SQL.\n */\nclass ForgeSQLORMImpl implements ForgeSqlOperation {\n private static instance: ForgeSQLORMImpl | null = null;\n private readonly drizzle;\n private readonly crudOperations: CRUDForgeSQL;\n private readonly fetchOperations: SchemaSqlForgeSql;\n\n /**\n * Private constructor to enforce singleton behavior.\n * @param options - Options for configuring ForgeSQL ORM behavior.\n */\n private constructor(options?: ForgeSqlOrmOptions) {\n try {\n const newOptions: ForgeSqlOrmOptions = options ?? {\n logRawSqlQuery: false,\n disableOptimisticLocking: false,\n };\n if (newOptions.logRawSqlQuery) {\n console.debug(\"Initializing ForgeSQLORM...\");\n }\n // Initialize Drizzle instance with our custom driver\n this.drizzle = drizzle(forgeDriver);\n this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);\n this.fetchOperations = new ForgeSQLSelectOperations(newOptions);\n } catch (error) {\n console.error(\"ForgeSQLORM initialization failed:\", error);\n throw error;\n }\n }\n\n /**\n * Returns the singleton instance of ForgeSQLORMImpl.\n * @param options - Options for configuring ForgeSQL ORM behavior.\n * @returns The singleton instance of ForgeSQLORMImpl.\n */\n static getInstance(options?: ForgeSqlOrmOptions): ForgeSqlOperation {\n if (!ForgeSQLORMImpl.instance) {\n ForgeSQLORMImpl.instance = new ForgeSQLORMImpl(options);\n }\n return ForgeSQLORMImpl.instance;\n }\n\n /**\n * Retrieves the CRUD operations instance.\n * @returns CRUD operations.\n */\n crud(): CRUDForgeSQL {\n return this.crudOperations;\n }\n\n /**\n * Retrieves the fetch operations instance.\n * @returns Fetch operations.\n */\n fetch(): SchemaSqlForgeSql {\n return this.fetchOperations;\n }\n\n /**\n * Returns a Drizzle query builder instance.\n *\n * ⚠️ IMPORTANT: This method should be used ONLY for query building purposes.\n * The returned instance should NOT be used for direct database connections or query execution.\n * All database operations should be performed through Forge SQL's executeRawSQL or executeRawUpdateSQL methods.\n *\n * @returns A Drizzle query builder instance for query construction only.\n */\n getDrizzleQueryBuilder() {\n return this.drizzle;\n }\n}\n\n/**\n * Public class that acts as a wrapper around the private ForgeSQLORMImpl.\n * Provides a clean interface for working with Forge SQL and Drizzle ORM.\n */\nclass ForgeSQLORM {\n private readonly ormInstance: ForgeSqlOperation;\n\n constructor(options?: ForgeSqlOrmOptions) {\n this.ormInstance = ForgeSQLORMImpl.getInstance(options);\n }\n\n /**\n * Proxies the `crud` method from `ForgeSQLORMImpl`.\n * @returns CRUD operations.\n */\n crud(): CRUDForgeSQL {\n return this.ormInstance.crud();\n }\n\n /**\n * Proxies the `fetch` method from `ForgeSQLORMImpl`.\n * @returns Fetch operations.\n */\n fetch(): SchemaSqlForgeSql {\n return this.ormInstance.fetch();\n }\n\n /**\n * Returns a Drizzle query builder instance.\n *\n * ⚠️ IMPORTANT: This method should be used ONLY for query building purposes.\n * The returned instance should NOT be used for direct database connections or query execution.\n * All database operations should be performed through Forge SQL's executeRawSQL or executeRawUpdateSQL methods.\n *\n * @returns A Drizzle query builder instance for query construction only.\n */\n getDrizzleQueryBuilder() {\n return this.ormInstance.getDrizzleQueryBuilder();\n }\n}\n\nexport default ForgeSQLORM;\n","import { UpdateQueryResponse } from \"@forge/sql\";\nimport { SqlParameters } from \"@forge/sql/out/sql-statement\";\nimport { MySql2Database } from \"drizzle-orm/mysql2/driver\";\nimport { AnyMySqlSelectQueryBuilder, AnyMySqlTable, customType } from \"drizzle-orm/mysql-core\";\nimport { MySqlSelectDynamic } from \"drizzle-orm/mysql-core/query-builders/select.types\";\nimport { InferInsertModel, SQL } from \"drizzle-orm\";\nimport moment from \"moment/moment\";\nimport { parseDateTime } from \"../utils/sqlUtils\";\n\n// ============= Core Types =============\n\n/**\n * Interface representing the main ForgeSQL operations.\n * Provides access to CRUD operations and schema-level SQL operations.\n */\nexport interface ForgeSqlOperation extends QueryBuilderForgeSql {\n /**\n * Provides CRUD (Create, Read, Update, Delete) operations.\n * @returns {CRUDForgeSQL} Interface for performing CRUD operations\n */\n crud(): CRUDForgeSQL;\n\n /**\n * Provides schema-level SQL fetch operations.\n * @returns {SchemaSqlForgeSql} Interface for executing schema-bound SQL queries\n */\n fetch(): SchemaSqlForgeSql;\n}\n\n/**\n * Interface for Query Builder operations.\n * Provides access to the underlying Drizzle ORM query builder.\n */\nexport interface QueryBuilderForgeSql {\n /**\n * Creates a new query builder for the given entity.\n * @returns {MySql2Database<Record<string, unknown>>} The Drizzle database instance for building queries\n */\n getDrizzleQueryBuilder(): MySql2Database<Record<string, unknown>>;\n}\n\n// ============= CRUD Operations =============\n\n/**\n * Interface for CRUD (Create, Read, Update, Delete) operations.\n * Provides methods for basic database operations with support for optimistic locking.\n */\nexport interface CRUDForgeSQL {\n /**\n * Inserts multiple records into the database.\n * @template T - The type of the table schema\n * @param {T} schema - The entity schema\n * @param {Partial<InferInsertModel<T>>[]} models - The list of entities to insert\n * @param {boolean} [updateIfExists] - Whether to update the row if it already exists (default: false)\n * @returns {Promise<number>} The number of inserted rows\n * @throws {Error} If the insert operation fails\n */\n insert<T extends AnyMySqlTable>(\n schema: T,\n models: Partial<InferInsertModel<T>>[],\n updateIfExists?: boolean,\n ): Promise<number>;\n\n /**\n * Deletes a record by its ID.\n * @template T - The type of the table schema\n * @param {unknown} id - The ID of the record to delete\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} The number of rows affected\n * @throws {Error} If the delete operation fails\n */\n deleteById<T extends AnyMySqlTable>(id: unknown, schema: T): Promise<number>;\n\n /**\n * Updates a record by its ID with optimistic locking support.\n * If a version field is defined in the schema, versioning is applied:\n * - the current record version is retrieved\n * - checked for concurrent modifications\n * - and then incremented\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity with updated values\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} The number of rows affected\n * @throws {Error} If the primary key is not included in the update fields\n * @throws {Error} If optimistic locking check fails\n */\n updateById<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n schema: T,\n ): Promise<number>;\n\n /**\n * Updates specified fields of records based on provided conditions.\n * If the \"where\" parameter is not provided, the WHERE clause is built from the entity fields\n * that are not included in the list of fields to update.\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} updateData - The object containing values to update\n * @param {T} schema - The entity schema\n * @param {SQL<unknown>} [where] - Optional filtering conditions for the WHERE clause\n * @returns {Promise<number>} The number of affected rows\n * @throws {Error} If no filtering criteria are provided\n * @throws {Error} If the update operation fails\n */\n updateFields<T extends AnyMySqlTable>(\n updateData: Partial<InferInsertModel<T>>,\n schema: T,\n where?: SQL<unknown>,\n ): Promise<number>;\n}\n\n// ============= Schema SQL Operations =============\n\n/**\n * Interface for schema-level SQL operations.\n * Provides methods for executing SQL queries with schema binding and type safety.\n */\nexport interface SchemaSqlForgeSql {\n /**\n * Executes a Drizzle query and returns a single result.\n * @template T - The type of the query builder\n * @param {T} query - The Drizzle query to execute\n * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} A single result object or undefined\n * @throws {Error} If more than one record is returned\n * @throws {Error} If the query execution fails\n */\n executeQueryOnlyOne<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(\n query: T,\n ): Promise<\n Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined\n >;\n\n /**\n * Executes a raw SQL query and returns the results.\n * @template T - The type of the result objects\n * @param {string} query - The raw SQL query\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<T[]>} A list of results as objects\n * @throws {Error} If the query execution fails\n */\n executeRawSQL<T extends object | unknown>(query: string, params?: SqlParameters[]): Promise<T[]>;\n\n /**\n * Executes a raw SQL update query.\n * @param {string} query - The raw SQL update query\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<UpdateQueryResponse>} The update response containing affected rows\n * @throws {Error} If the update operation fails\n */\n executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse>;\n}\n\n// ============= Configuration Types =============\n\n/**\n * Interface for version field metadata.\n * Defines the configuration for optimistic locking version fields.\n */\nexport interface VersionFieldMetadata {\n /** Name of the version field */\n fieldName: string;\n}\n\n/**\n * Interface for table metadata.\n * Defines the configuration for a specific table.\n */\nexport interface TableMetadata {\n /** Name of the table */\n tableName: string;\n /** Version field configuration for optimistic locking */\n versionField: VersionFieldMetadata;\n}\n\n/**\n * Type for additional metadata configuration.\n * Maps table names to their metadata configuration.\n */\nexport type AdditionalMetadata = Record<string, TableMetadata>;\n\n/**\n * Options for configuring ForgeSQL ORM behavior.\n */\nexport interface ForgeSqlOrmOptions {\n /**\n * Enables logging of raw SQL queries in the Atlassian Forge Developer Console.\n * Useful for debugging and monitoring SQL operations.\n * @default false\n */\n logRawSqlQuery?: boolean;\n /**\n * Enables logging of raw SQL queries in the Atlassian Forge Developer Console.\n * Useful for debugging and monitoring SQL operations.\n * @default false\n */\n logRawSqlQueryParams?: boolean;\n\n /**\n * Disables optimistic locking for all operations.\n * When enabled, version checks are skipped during updates.\n * @default false\n */\n disableOptimisticLocking?: boolean;\n\n /**\n * Additional metadata for table configuration.\n * Allows specifying table-specific settings and behaviors.\n * @example\n * ```typescript\n * {\n * users: {\n * tableName: \"users\",\n * versionField: {\n * fieldName: \"updatedAt\",\n * type: \"datetime\",\n * nullable: false\n * }\n * }\n * }\n * ```\n */\n additionalMetadata?: AdditionalMetadata;\n}\n\n// ============= Custom Types =============\n\n/**\n * Custom type for MySQL datetime fields.\n * Handles conversion between JavaScript Date objects and MySQL datetime strings.\n */\nexport const mySqlDateTimeString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"datetime\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"YYYY-MM-DDTHH:mm:ss.SSS\");\n },\n fromDriver(value: unknown) {\n const format = \"YYYY-MM-DDTHH:mm:ss.SSS\";\n return parseDateTime(value as string, format);\n },\n});\n\n/**\n * Custom type for MySQL timestamp fields.\n * Handles conversion between JavaScript Date objects and MySQL timestamp strings.\n */\nexport const mySqlTimestampString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"timestamp\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"YYYY-MM-DDTHH:mm:ss.SSS\");\n },\n fromDriver(value: unknown) {\n const format = \"YYYY-MM-DDTHH:mm:ss.SSS\";\n return parseDateTime(value as string, format);\n },\n});\n\n/**\n * Custom type for MySQL date fields.\n * Handles conversion between JavaScript Date objects and MySQL date strings.\n */\nexport const mySqlDateString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"date\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"YYYY-MM-DD\");\n },\n fromDriver(value: unknown) {\n const format = \"YYYY-MM-DD\";\n return parseDateTime(value as string, format);\n },\n});\n\n/**\n * Custom type for MySQL time fields.\n * Handles conversion between JavaScript Date objects and MySQL time strings.\n */\nexport const mySqlTimeString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"time\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"HH:mm:ss.SSS\");\n },\n fromDriver(value: unknown) {\n return parseDateTime(value as string, \"HH:mm:ss.SSS\");\n },\n});\n"],"names":["eq","and","sql","drizzle","customType","moment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ForgeSQLORM.js","sources":["../src/utils/sqlUtils.ts","../src/core/ForgeSQLCrudOperations.ts","../src/core/ForgeSQLSelectOperations.ts","../src/utils/forgeDriver.ts","../src/core/ForgeSQLORM.ts","../src/core/ForgeSQLQueryBuilder.ts"],"sourcesContent":["import moment from \"moment\";\nimport { AnyColumn } from \"drizzle-orm\";\nimport { AnyMySqlTable } from \"drizzle-orm/mysql-core/index\";\nimport { PrimaryKeyBuilder } from \"drizzle-orm/mysql-core/primary-keys\";\nimport { AnyIndexBuilder } from \"drizzle-orm/mysql-core/indexes\";\nimport { CheckBuilder } from \"drizzle-orm/mysql-core/checks\";\nimport { ForeignKeyBuilder } from \"drizzle-orm/mysql-core/foreign-keys\";\nimport { UniqueConstraintBuilder } from \"drizzle-orm/mysql-core/unique-constraint\";\n\n/**\n * Interface representing table metadata information\n */\nexport interface MetadataInfo {\n /** The name of the table */\n tableName: string;\n /** Record of column names and their corresponding column definitions */\n columns: Record<string, AnyColumn>;\n /** Array of index builders */\n indexes: AnyIndexBuilder[];\n /** Array of check constraint builders */\n checks: CheckBuilder[];\n /** Array of foreign key builders */\n foreignKeys: ForeignKeyBuilder[];\n /** Array of primary key builders */\n primaryKeys: PrimaryKeyBuilder[];\n /** Array of unique constraint builders */\n uniqueConstraints: UniqueConstraintBuilder[];\n /** Array of all extra builders */\n extras: any[];\n}\n\n/**\n * Interface for config builder data\n */\ninterface ConfigBuilderData {\n value?: any;\n [key: string]: any;\n}\n\n/**\n * Parses a date string into a Date object using the specified format\n * @param value - The date string to parse\n * @param format - The format to use for parsing\n * @returns Date object\n */\nexport const parseDateTime = (value: string, format: string): Date => {\n const m = moment(value, format, true);\n if (!m.isValid()) {\n return moment(value).toDate();\n }\n return m.toDate();\n};\n\n/**\n * Extracts the alias from a SQL query\n * @param query - The SQL query to extract the alias from\n * @returns The extracted alias or the original query if no alias found\n */\nexport function extractAlias(query: string): string {\n const match = query.match(/\\bas\\s+(['\"`]?)([\\w*]+)\\1$/i);\n return match ? match[2] : query;\n}\n\n/**\n * Gets primary keys from the schema.\n * @template T - The type of the table schema\n * @param {T} table - The table schema\n * @returns {[string, AnyColumn][]} Array of primary key name and column pairs\n */\nexport function getPrimaryKeys<T extends AnyMySqlTable>(table: T): [string, AnyColumn][] {\n const { columns, primaryKeys } = getTableMetadata(table);\n\n // First try to find primary keys in columns\n const columnPrimaryKeys = Object.entries(columns).filter(([, column]) => column.primary) as [\n string,\n AnyColumn,\n ][];\n\n if (columnPrimaryKeys.length > 0) {\n return columnPrimaryKeys;\n }\n\n // If no primary keys found in columns, check primary key builders\n if (Array.isArray(primaryKeys) && primaryKeys.length > 0) {\n // Collect all primary key columns from all primary key builders\n const primaryKeyColumns = new Set<[string, AnyColumn]>();\n\n primaryKeys.forEach((primaryKeyBuilder) => {\n // Get primary key columns from each builder\n Object.entries(columns)\n .filter(([, column]) => {\n // @ts-ignore - PrimaryKeyBuilder has internal columns property\n return primaryKeyBuilder.columns.includes(column);\n })\n .forEach(([name, column]) => {\n primaryKeyColumns.add([name, column]);\n });\n });\n\n return Array.from(primaryKeyColumns);\n }\n\n return [];\n}\n\n/**\n * Extracts table metadata from the schema.\n * @param {AnyMySqlTable} table - The table schema\n * @returns {MetadataInfo} Object containing table metadata\n */\nexport function getTableMetadata(table: AnyMySqlTable): MetadataInfo {\n const symbols = Object.getOwnPropertySymbols(table);\n const nameSymbol = symbols.find((s) => s.toString().includes(\"Name\"));\n const columnsSymbol = symbols.find((s) => s.toString().includes(\"Columns\"));\n const extraSymbol = symbols.find((s) => s.toString().includes(\"ExtraConfigBuilder\"));\n\n // Initialize builders arrays\n const builders = {\n indexes: [] as AnyIndexBuilder[],\n checks: [] as CheckBuilder[],\n foreignKeys: [] as ForeignKeyBuilder[],\n primaryKeys: [] as PrimaryKeyBuilder[],\n uniqueConstraints: [] as UniqueConstraintBuilder[],\n extras: [] as any[],\n };\n\n // Process extra configuration if available\n if (extraSymbol) {\n // @ts-ignore\n const extraConfigBuilder = table[extraSymbol];\n if (extraConfigBuilder && typeof extraConfigBuilder === \"function\") {\n const configBuilderData = extraConfigBuilder(table);\n if (configBuilderData) {\n // Convert configBuilderData to array if it's an object\n const configBuilders = Array.isArray(configBuilderData)\n ? configBuilderData\n : Object.values(configBuilderData).map(\n (item) => (item as ConfigBuilderData).value || item,\n );\n\n // Process each builder\n configBuilders.forEach((builder) => {\n if (!builder?.constructor) return;\n\n const builderName = builder.constructor.name.toLowerCase();\n\n // Map builder types to their corresponding arrays\n const builderMap = {\n indexbuilder: builders.indexes,\n checkbuilder: builders.checks,\n foreignkeybuilder: builders.foreignKeys,\n primarykeybuilder: builders.primaryKeys,\n uniqueconstraintbuilder: builders.uniqueConstraints,\n };\n\n // Add builder to appropriate array if it matches any type\n for (const [type, array] of Object.entries(builderMap)) {\n if (builderName.includes(type)) {\n array.push(builder);\n break;\n }\n }\n\n // Always add to extras array\n builders.extras.push(builder);\n });\n }\n }\n }\n\n return {\n tableName: nameSymbol ? (table as any)[nameSymbol] : \"\",\n columns: columnsSymbol ? ((table as any)[columnsSymbol] as Record<string, AnyColumn>) : {},\n ...builders,\n };\n}\n","import { ForgeSqlOrmOptions } from \"..\";\nimport { CRUDForgeSQL, ForgeSqlOperation } from \"./ForgeSQLQueryBuilder\";\nimport { AnyMySqlTable } from \"drizzle-orm/mysql-core/index\";\nimport { AnyColumn, InferInsertModel } from \"drizzle-orm\";\nimport { eq, and } from \"drizzle-orm\";\nimport { SQL } from \"drizzle-orm\";\nimport { getPrimaryKeys, getTableMetadata } from \"../utils/sqlUtils\";\n\n/**\n * Class implementing CRUD operations for ForgeSQL ORM.\n * Provides methods for inserting, updating, and deleting records with support for optimistic locking.\n */\nexport class ForgeSQLCrudOperations implements CRUDForgeSQL {\n private readonly forgeOperations: ForgeSqlOperation;\n private readonly options: ForgeSqlOrmOptions;\n\n /**\n * Creates a new instance of ForgeSQLCrudOperations.\n * @param forgeSqlOperations - The ForgeSQL operations instance\n * @param options - Configuration options for the ORM\n */\n constructor(forgeSqlOperations: ForgeSqlOperation, options: ForgeSqlOrmOptions) {\n this.forgeOperations = forgeSqlOperations;\n this.options = options;\n }\n\n /**\n * Inserts records into the database with optional versioning support.\n * If a version field exists in the schema, versioning is applied.\n *\n * @template T - The type of the table schema\n * @param {T} schema - The entity schema\n * @param {Partial<InferInsertModel<T>>[]} models - Array of entities to insert\n * @param {boolean} [updateIfExists=false] - Whether to update existing records\n * @returns {Promise<number>} The number of inserted rows\n * @throws {Error} If the insert operation fails\n */\n async insert<T extends AnyMySqlTable>(\n schema: T,\n models: Partial<InferInsertModel<T>>[],\n updateIfExists: boolean = false,\n ): Promise<number> {\n if (!models?.length) return 0;\n\n const { tableName, columns } = getTableMetadata(schema);\n const versionMetadata = this.validateVersionField(tableName, columns);\n\n // Prepare models with version field if needed\n const preparedModels = models.map((model) =>\n this.prepareModelWithVersion(model, versionMetadata, columns),\n );\n\n // Build insert query\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .insert(schema)\n .values(preparedModels);\n\n // Add onDuplicateKeyUpdate if needed\n const finalQuery = updateIfExists\n ? queryBuilder.onDuplicateKeyUpdate({\n set: Object.fromEntries(\n Object.keys(preparedModels[0]).map((key) => [key, (schema as any)[key]]),\n ) as any,\n })\n : queryBuilder;\n\n // Execute query\n const result = await finalQuery;\n return result[0].insertId;\n }\n\n /**\n * Deletes a record by its primary key with optional version check.\n * If versioning is enabled, ensures the record hasn't been modified since last read.\n *\n * @template T - The type of the table schema\n * @param {unknown} id - The ID of the record to delete\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} Number of affected rows\n * @throws {Error} If the delete operation fails\n * @throws {Error} If multiple primary keys are found\n */\n async deleteById<T extends AnyMySqlTable>(id: unknown, schema: T): Promise<number> {\n const { tableName, columns } = getTableMetadata(schema);\n const primaryKeys = this.getPrimaryKeys(schema);\n\n if (primaryKeys.length !== 1) {\n throw new Error(\"Only single primary key is supported\");\n }\n\n const [primaryKeyName, primaryKeyColumn] = primaryKeys[0];\n const versionMetadata = this.validateVersionField(tableName, columns);\n\n // Build delete conditions\n const conditions: SQL<unknown>[] = [eq(primaryKeyColumn, id)];\n\n // Add version check if needed\n if (versionMetadata && columns) {\n const versionField = columns[versionMetadata.fieldName];\n if (versionField) {\n const oldModel = await this.getOldModel({ [primaryKeyName]: id }, schema, [\n versionMetadata.fieldName,\n versionField,\n ]);\n conditions.push(eq(versionField, (oldModel as any)[versionMetadata.fieldName]));\n }\n }\n\n // Execute delete query\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .delete(schema)\n .where(and(...conditions));\n\n const result =await queryBuilder;\n\n return result[0].affectedRows;\n }\n\n /**\n * Updates a record by its primary key with optimistic locking support.\n * If versioning is enabled:\n * - Retrieves the current version\n * - Checks for concurrent modifications\n * - Increments the version on successful update\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity with updated values\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} Number of affected rows\n * @throws {Error} If the primary key is not provided\n * @throws {Error} If optimistic locking check fails\n * @throws {Error} If multiple primary keys are found\n */\n async updateById<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n schema: T,\n ): Promise<number> {\n const { tableName, columns } = getTableMetadata(schema);\n const primaryKeys = this.getPrimaryKeys(schema);\n\n if (primaryKeys.length !== 1) {\n throw new Error(\"Only single primary key is supported\");\n }\n\n const [primaryKeyName, primaryKeyColumn] = primaryKeys[0];\n const versionMetadata = this.validateVersionField(tableName, columns);\n\n // Validate primary key\n if (!(primaryKeyName in entity)) {\n throw new Error(`Primary key ${primaryKeyName} must be provided in the entity`);\n }\n\n // Get current version if needed\n const currentVersion = await this.getCurrentVersion(\n entity,\n primaryKeyName,\n versionMetadata,\n columns,\n schema,\n );\n\n // Prepare update data with version\n const updateData = this.prepareUpdateData(entity, versionMetadata, columns, currentVersion);\n\n // Build update conditions\n const conditions: SQL<unknown>[] = [\n eq(primaryKeyColumn, entity[primaryKeyName as keyof typeof entity]),\n ];\n if (versionMetadata && columns) {\n const versionField = columns[versionMetadata.fieldName];\n if (versionField) {\n conditions.push(eq(versionField, currentVersion));\n }\n }\n\n // Execute update query\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .update(schema)\n .set(updateData)\n .where(and(...conditions));\n\n const result = await queryBuilder;\n // Check optimistic locking\n if (versionMetadata && result[0].affectedRows === 0) {\n throw new Error(\n `Optimistic locking failed: record with primary key ${entity[primaryKeyName as keyof typeof entity]} has been modified`,\n );\n }\n\n return result[0].affectedRows;\n }\n\n /**\n * Updates specified fields of records based on provided conditions.\n * This method does not support versioning and should be used with caution.\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} updateData - The data to update\n * @param {T} schema - The entity schema\n * @param {SQL<unknown>} where - The WHERE conditions\n * @returns {Promise<number>} Number of affected rows\n * @throws {Error} If WHERE conditions are not provided\n * @throws {Error} If the update operation fails\n */\n async updateFields<T extends AnyMySqlTable>(\n updateData: Partial<InferInsertModel<T>>,\n schema: T,\n where?: SQL<unknown>,\n ): Promise<number> {\n if (!where) {\n throw new Error(\"WHERE conditions must be provided\");\n }\n\n const queryBuilder = this.forgeOperations\n .getDrizzleQueryBuilder()\n .update(schema)\n .set(updateData)\n .where(where);\n\n const result = await queryBuilder;\n return result[0].affectedRows;\n }\n\n // Helper methods\n\n /**\n * Gets primary keys from the schema.\n * @template T - The type of the table schema\n * @param {T} schema - The table schema\n * @returns {[string, AnyColumn][]} Array of primary key name and column pairs\n * @throws {Error} If no primary keys are found\n */\n private getPrimaryKeys<T extends AnyMySqlTable>(schema: T): [string, AnyColumn][] {\n const primaryKeys = getPrimaryKeys(schema);\n if (!primaryKeys) {\n throw new Error(`No primary keys found for schema: ${schema}`);\n }\n\n return primaryKeys;\n }\n\n /**\n * Validates and retrieves version field metadata.\n * @param {string} tableName - The name of the table\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @returns {Object | undefined} Version field metadata if valid, undefined otherwise\n */\n private validateVersionField(\n tableName: string,\n columns: Record<string, AnyColumn>,\n ): { fieldName: string; type: string } | undefined {\n if (this.options.disableOptimisticLocking) {\n return undefined;\n }\n const versionMetadata = this.options.additionalMetadata?.[tableName]?.versionField;\n if (!versionMetadata) return undefined;\n\n const versionField = columns[versionMetadata.fieldName];\n if (!versionField) {\n console.warn(\n `Version field \"${versionMetadata.fieldName}\" not found in table ${tableName}. Versioning will be skipped.`,\n );\n return undefined;\n }\n\n if (!versionField.notNull) {\n console.warn(\n `Version field \"${versionMetadata.fieldName}\" in table ${tableName} is nullable. Versioning may not work correctly.`,\n );\n return undefined;\n }\n\n const fieldType = versionField.getSQLType();\n const isSupportedType =\n fieldType === \"datetime\" ||\n fieldType === \"timestamp\" ||\n fieldType === \"int\" ||\n fieldType === \"number\" ||\n fieldType === \"decimal\";\n\n if (!isSupportedType) {\n console.warn(\n `Version field \"${versionMetadata.fieldName}\" in table ${tableName} has unsupported type \"${fieldType}\". ` +\n `Only datetime, timestamp, int, and decimal types are supported for versioning. Versioning will be skipped.`,\n );\n return undefined;\n }\n\n return { fieldName: versionMetadata.fieldName, type: fieldType };\n }\n\n /**\n * Gets the current version of an entity.\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity\n * @param {string} primaryKeyName - The name of the primary key\n * @param {Object | undefined} versionMetadata - Version field metadata\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @param {T} schema - The table schema\n * @returns {Promise<unknown>} The current version value\n */\n private async getCurrentVersion<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n primaryKeyName: string,\n versionMetadata: { fieldName: string; type: string } | undefined,\n columns: Record<string, AnyColumn>,\n schema: T,\n ): Promise<unknown> {\n if (!versionMetadata || !columns) return undefined;\n\n const versionField = columns[versionMetadata.fieldName];\n if (!versionField) return undefined;\n\n if (versionMetadata.fieldName in entity) {\n return entity[versionMetadata.fieldName as keyof typeof entity];\n }\n\n const oldModel = await this.getOldModel(\n { [primaryKeyName]: entity[primaryKeyName as keyof typeof entity] },\n schema,\n [versionMetadata.fieldName, versionField],\n );\n\n return (oldModel as any)[versionMetadata.fieldName];\n }\n\n /**\n * Prepares a model for insertion with version field.\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} model - The model to prepare\n * @param {Object | undefined} versionMetadata - Version field metadata\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @returns {InferInsertModel<T>} The prepared model\n */\n private prepareModelWithVersion<T extends AnyMySqlTable>(\n model: Partial<InferInsertModel<T>>,\n versionMetadata: { fieldName: string; type: string } | undefined,\n columns: Record<string, AnyColumn>,\n ): InferInsertModel<T> {\n if (!versionMetadata || !columns) return model as InferInsertModel<T>;\n\n const versionField = columns[versionMetadata.fieldName];\n if (!versionField) return model as InferInsertModel<T>;\n\n const modelWithVersion = { ...model };\n const fieldType = versionField.getSQLType();\n const versionValue = fieldType === \"datetime\" || fieldType === \"timestamp\" ? new Date() : 1;\n modelWithVersion[versionMetadata.fieldName as keyof typeof modelWithVersion] =\n versionValue as any;\n\n return modelWithVersion as InferInsertModel<T>;\n }\n\n /**\n * Prepares update data with version field.\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity to update\n * @param {Object | undefined} versionMetadata - Version field metadata\n * @param {Record<string, AnyColumn>} columns - The table columns\n * @param {unknown} currentVersion - The current version value\n * @returns {Partial<InferInsertModel<T>>} The prepared update data\n */\n private prepareUpdateData<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n versionMetadata: { fieldName: string; type: string } | undefined,\n columns: Record<string, AnyColumn>,\n currentVersion: unknown,\n ): Partial<InferInsertModel<T>> {\n const updateData = { ...entity };\n\n if (versionMetadata && columns) {\n const versionField = columns[versionMetadata.fieldName];\n if (versionField) {\n const fieldType = versionField.getSQLType();\n updateData[versionMetadata.fieldName as keyof typeof updateData] =\n fieldType === \"datetime\" || fieldType === \"timestamp\"\n ? new Date()\n : (((currentVersion as number) + 1) as any);\n }\n }\n\n return updateData;\n }\n\n /**\n * Retrieves an existing model by primary key.\n * @template T - The type of the table schema\n * @param {Record<string, unknown>} primaryKeyValues - The primary key values\n * @param {T} schema - The table schema\n * @param {[string, AnyColumn]} versionField - The version field name and column\n * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} The existing model\n * @throws {Error} If the record is not found\n */\n private async getOldModel<T extends AnyMySqlTable>(\n primaryKeyValues: Record<string, unknown>,\n schema: T,\n versionField: [string, AnyColumn],\n ): Promise<\n Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined\n > {\n const [versionFieldName, versionFieldColumn] = versionField;\n const primaryKeys = this.getPrimaryKeys(schema);\n const [primaryKeyName, primaryKeyColumn] = primaryKeys[0];\n\n const resultQuery = this.forgeOperations\n .getDrizzleQueryBuilder()\n .select({\n [primaryKeyName]: primaryKeyColumn as any,\n [versionFieldName]: versionFieldColumn as any,\n })\n .from(schema)\n .where(eq(primaryKeyColumn, primaryKeyValues[primaryKeyName]));\n\n const model = await this.forgeOperations.fetch().executeQueryOnlyOne(resultQuery);\n\n if (!model) {\n throw new Error(`Record not found in table ${schema}`);\n }\n\n return model as Awaited<T> extends Array<any> ? Awaited<T>[number] : Awaited<T>;\n }\n}\n","import { sql, UpdateQueryResponse } from \"@forge/sql\";\nimport { ForgeSqlOrmOptions, SchemaSqlForgeSql } from \"./ForgeSQLQueryBuilder\";\nimport {\n AnyMySqlSelectQueryBuilder,\n MySqlSelectDynamic,\n} from \"drizzle-orm/mysql-core/query-builders/select.types\";\n\n/**\n * Class implementing SQL select operations for ForgeSQL ORM.\n * Provides methods for executing queries and mapping results to entity types.\n */\nexport class ForgeSQLSelectOperations implements SchemaSqlForgeSql {\n private readonly options: ForgeSqlOrmOptions;\n\n /**\n * Creates a new instance of ForgeSQLSelectOperations.\n * @param {ForgeSqlOrmOptions} options - Configuration options for the ORM\n */\n constructor(options: ForgeSqlOrmOptions) {\n this.options = options;\n }\n\n /**\n * Executes a Drizzle query and returns a single result.\n * Throws an error if more than one record is returned.\n *\n * @template T - The type of the query builder\n * @param {T} query - The Drizzle query to execute\n * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} A single result object or undefined\n * @throws {Error} If more than one record is returned\n */\n async executeQueryOnlyOne<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(\n query: T,\n ): Promise<\n Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined\n > {\n const results: Awaited<T> = await query;\n const datas = results as unknown[];\n if (!datas.length) {\n return undefined;\n }\n if (datas.length > 1) {\n throw new Error(`Expected 1 record but returned ${datas.length}`);\n }\n\n return datas[0] as Awaited<T> extends Array<any> ? Awaited<T>[number] : Awaited<T>;\n }\n\n /**\n * Executes a raw SQL query and returns the results.\n * Logs the query if logging is enabled.\n *\n * @template T - The type of the result objects\n * @param {string} query - The raw SQL query to execute\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<T[]>} A list of results as objects\n */\n async executeRawSQL<T extends object | unknown>(query: string, params?: unknown[]): Promise<T[]> {\n if (this.options.logRawSqlQuery) {\n console.debug(\"Executing raw SQL: \" + query);\n }\n const sqlStatement = sql.prepare<T>(query);\n if (params) {\n if (this.options.logRawSqlQuery && this.options.logRawSqlQueryParams) {\n console.debug(\"Executing with SQL Params: \" + JSON.stringify(params));\n }\n sqlStatement.bindParams(...params);\n }\n const result = await sqlStatement.execute();\n return result.rows as T[];\n }\n\n /**\n * Executes a raw SQL update query.\n * @param {string} query - The raw SQL update query\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<UpdateQueryResponse>} The update response containing affected rows\n */\n async executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse> {\n const sqlStatement = sql.prepare<UpdateQueryResponse>(query);\n if (params) {\n sqlStatement.bindParams(...params);\n }\n const updateQueryResponseResults = await sqlStatement.execute();\n return updateQueryResponseResults.rows;\n }\n}\n","import { sql } from \"@forge/sql\";\nimport {AnyMySql2Connection} from \"drizzle-orm/mysql2/driver\";\n\ninterface ForgeSQLResult {\n rows: Record<string, unknown>[] | Record<string, unknown>;\n}\n\nexport const forgeDriver = {\n query: async (query: { sql: string }, params?: unknown[]) => {\n try {\n const sqlStatement = await sql.prepare<unknown>(query.sql);\n if (params) {\n await sqlStatement.bindParams(...params);\n }\n const result = await sqlStatement.execute() as ForgeSQLResult;\n\n let rows;\n if (Array.isArray(result.rows)) {\n rows = [\n result.rows.map(r => Object.values(r as Record<string, unknown>))\n ];\n } else {\n rows = [\n result.rows as Record<string, unknown>\n ];\n }\n\n return rows;\n } catch (error) {\n console.error(\"SQL Error:\", JSON.stringify(error));\n throw error;\n }\n }\n} as unknown as AnyMySql2Connection;","import { ForgeSQLCrudOperations } from \"./ForgeSQLCrudOperations\";\nimport {\n CRUDForgeSQL,\n ForgeSqlOperation,\n ForgeSqlOrmOptions,\n SchemaSqlForgeSql,\n} from \"./ForgeSQLQueryBuilder\";\nimport { ForgeSQLSelectOperations } from \"./ForgeSQLSelectOperations\";\nimport { drizzle } from \"drizzle-orm/mysql2\";\nimport { forgeDriver } from \"../utils/forgeDriver\";\n\n/**\n * Implementation of ForgeSQLORM that uses Drizzle ORM for query building.\n * This class provides a bridge between Forge SQL and Drizzle ORM, allowing\n * to use Drizzle's query builder while executing queries through Forge SQL.\n */\nclass ForgeSQLORMImpl implements ForgeSqlOperation {\n private static instance: ForgeSQLORMImpl | null = null;\n private readonly drizzle;\n private readonly crudOperations: CRUDForgeSQL;\n private readonly fetchOperations: SchemaSqlForgeSql;\n\n /**\n * Private constructor to enforce singleton behavior.\n * @param options - Options for configuring ForgeSQL ORM behavior.\n */\n private constructor(options?: ForgeSqlOrmOptions) {\n try {\n const newOptions: ForgeSqlOrmOptions = options ?? {\n logRawSqlQuery: false,\n disableOptimisticLocking: false,\n };\n if (newOptions.logRawSqlQuery) {\n console.debug(\"Initializing ForgeSQLORM...\");\n }\n // Initialize Drizzle instance with our custom driver\n this.drizzle = drizzle(forgeDriver);\n this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);\n this.fetchOperations = new ForgeSQLSelectOperations(newOptions);\n } catch (error) {\n console.error(\"ForgeSQLORM initialization failed:\", error);\n throw error;\n }\n }\n\n /**\n * Returns the singleton instance of ForgeSQLORMImpl.\n * @param options - Options for configuring ForgeSQL ORM behavior.\n * @returns The singleton instance of ForgeSQLORMImpl.\n */\n static getInstance(options?: ForgeSqlOrmOptions): ForgeSqlOperation {\n if (!ForgeSQLORMImpl.instance) {\n ForgeSQLORMImpl.instance = new ForgeSQLORMImpl(options);\n }\n return ForgeSQLORMImpl.instance;\n }\n\n /**\n * Retrieves the CRUD operations instance.\n * @returns CRUD operations.\n */\n crud(): CRUDForgeSQL {\n return this.crudOperations;\n }\n\n /**\n * Retrieves the fetch operations instance.\n * @returns Fetch operations.\n */\n fetch(): SchemaSqlForgeSql {\n return this.fetchOperations;\n }\n\n /**\n * Returns a Drizzle query builder instance.\n *\n * ⚠️ IMPORTANT: This method should be used ONLY for query building purposes.\n * The returned instance should NOT be used for direct database connections or query execution.\n * All database operations should be performed through Forge SQL's executeRawSQL or executeRawUpdateSQL methods.\n *\n * @returns A Drizzle query builder instance for query construction only.\n */\n getDrizzleQueryBuilder() {\n return this.drizzle;\n }\n}\n\n/**\n * Public class that acts as a wrapper around the private ForgeSQLORMImpl.\n * Provides a clean interface for working with Forge SQL and Drizzle ORM.\n */\nclass ForgeSQLORM {\n private readonly ormInstance: ForgeSqlOperation;\n\n constructor(options?: ForgeSqlOrmOptions) {\n this.ormInstance = ForgeSQLORMImpl.getInstance(options);\n }\n\n /**\n * Proxies the `crud` method from `ForgeSQLORMImpl`.\n * @returns CRUD operations.\n */\n crud(): CRUDForgeSQL {\n return this.ormInstance.crud();\n }\n\n /**\n * Proxies the `fetch` method from `ForgeSQLORMImpl`.\n * @returns Fetch operations.\n */\n fetch(): SchemaSqlForgeSql {\n return this.ormInstance.fetch();\n }\n\n /**\n * Returns a Drizzle query builder instance.\n *\n * ⚠️ IMPORTANT: This method should be used ONLY for query building purposes.\n * The returned instance should NOT be used for direct database connections or query execution.\n * All database operations should be performed through Forge SQL's executeRawSQL or executeRawUpdateSQL methods.\n *\n * @returns A Drizzle query builder instance for query construction only.\n */\n getDrizzleQueryBuilder() {\n return this.ormInstance.getDrizzleQueryBuilder();\n }\n}\n\nexport default ForgeSQLORM;\n","import { UpdateQueryResponse } from \"@forge/sql\";\nimport { SqlParameters } from \"@forge/sql/out/sql-statement\";\nimport { MySql2Database } from \"drizzle-orm/mysql2/driver\";\nimport { AnyMySqlSelectQueryBuilder, AnyMySqlTable, customType } from \"drizzle-orm/mysql-core\";\nimport { MySqlSelectDynamic } from \"drizzle-orm/mysql-core/query-builders/select.types\";\nimport { InferInsertModel, SQL } from \"drizzle-orm\";\nimport moment from \"moment/moment\";\nimport { parseDateTime } from \"../utils/sqlUtils\";\n\n// ============= Core Types =============\n\n/**\n * Interface representing the main ForgeSQL operations.\n * Provides access to CRUD operations and schema-level SQL operations.\n */\nexport interface ForgeSqlOperation extends QueryBuilderForgeSql {\n /**\n * Provides CRUD (Create, Read, Update, Delete) operations.\n * @returns {CRUDForgeSQL} Interface for performing CRUD operations\n */\n crud(): CRUDForgeSQL;\n\n /**\n * Provides schema-level SQL fetch operations.\n * @returns {SchemaSqlForgeSql} Interface for executing schema-bound SQL queries\n */\n fetch(): SchemaSqlForgeSql;\n}\n\n/**\n * Interface for Query Builder operations.\n * Provides access to the underlying Drizzle ORM query builder.\n */\nexport interface QueryBuilderForgeSql {\n /**\n * Creates a new query builder for the given entity.\n * @returns {MySql2Database<Record<string, unknown>>} The Drizzle database instance for building queries\n */\n getDrizzleQueryBuilder(): MySql2Database<Record<string, unknown>>;\n}\n\n// ============= CRUD Operations =============\n\n/**\n * Interface for CRUD (Create, Read, Update, Delete) operations.\n * Provides methods for basic database operations with support for optimistic locking.\n */\nexport interface CRUDForgeSQL {\n /**\n * Inserts multiple records into the database.\n * @template T - The type of the table schema\n * @param {T} schema - The entity schema\n * @param {Partial<InferInsertModel<T>>[]} models - The list of entities to insert\n * @param {boolean} [updateIfExists] - Whether to update the row if it already exists (default: false)\n * @returns {Promise<number>} The number of inserted rows\n * @throws {Error} If the insert operation fails\n */\n insert<T extends AnyMySqlTable>(\n schema: T,\n models: Partial<InferInsertModel<T>>[],\n updateIfExists?: boolean,\n ): Promise<number>;\n\n /**\n * Deletes a record by its ID.\n * @template T - The type of the table schema\n * @param {unknown} id - The ID of the record to delete\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} The number of rows affected\n * @throws {Error} If the delete operation fails\n */\n deleteById<T extends AnyMySqlTable>(id: unknown, schema: T): Promise<number>;\n\n /**\n * Updates a record by its ID with optimistic locking support.\n * If a version field is defined in the schema, versioning is applied:\n * - the current record version is retrieved\n * - checked for concurrent modifications\n * - and then incremented\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} entity - The entity with updated values\n * @param {T} schema - The entity schema\n * @returns {Promise<number>} The number of rows affected\n * @throws {Error} If the primary key is not included in the update fields\n * @throws {Error} If optimistic locking check fails\n */\n updateById<T extends AnyMySqlTable>(\n entity: Partial<InferInsertModel<T>>,\n schema: T,\n ): Promise<number>;\n\n /**\n * Updates specified fields of records based on provided conditions.\n * If the \"where\" parameter is not provided, the WHERE clause is built from the entity fields\n * that are not included in the list of fields to update.\n *\n * @template T - The type of the table schema\n * @param {Partial<InferInsertModel<T>>} updateData - The object containing values to update\n * @param {T} schema - The entity schema\n * @param {SQL<unknown>} [where] - Optional filtering conditions for the WHERE clause\n * @returns {Promise<number>} The number of affected rows\n * @throws {Error} If no filtering criteria are provided\n * @throws {Error} If the update operation fails\n */\n updateFields<T extends AnyMySqlTable>(\n updateData: Partial<InferInsertModel<T>>,\n schema: T,\n where?: SQL<unknown>,\n ): Promise<number>;\n}\n\n// ============= Schema SQL Operations =============\n\n/**\n * Interface for schema-level SQL operations.\n * Provides methods for executing SQL queries with schema binding and type safety.\n */\nexport interface SchemaSqlForgeSql {\n /**\n * Executes a Drizzle query and returns a single result.\n * @template T - The type of the query builder\n * @param {T} query - The Drizzle query to execute\n * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} A single result object or undefined\n * @throws {Error} If more than one record is returned\n * @throws {Error} If the query execution fails\n */\n executeQueryOnlyOne<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(\n query: T,\n ): Promise<\n Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined\n >;\n\n /**\n * Executes a raw SQL query and returns the results.\n * @template T - The type of the result objects\n * @param {string} query - The raw SQL query\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<T[]>} A list of results as objects\n * @throws {Error} If the query execution fails\n */\n executeRawSQL<T extends object | unknown>(query: string, params?: SqlParameters[]): Promise<T[]>;\n\n /**\n * Executes a raw SQL update query.\n * @param {string} query - The raw SQL update query\n * @param {SqlParameters[]} [params] - Optional SQL parameters\n * @returns {Promise<UpdateQueryResponse>} The update response containing affected rows\n * @throws {Error} If the update operation fails\n */\n executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse>;\n}\n\n// ============= Configuration Types =============\n\n/**\n * Interface for version field metadata.\n * Defines the configuration for optimistic locking version fields.\n */\nexport interface VersionFieldMetadata {\n /** Name of the version field */\n fieldName: string;\n}\n\n/**\n * Interface for table metadata.\n * Defines the configuration for a specific table.\n */\nexport interface TableMetadata {\n /** Name of the table */\n tableName: string;\n /** Version field configuration for optimistic locking */\n versionField: VersionFieldMetadata;\n}\n\n/**\n * Type for additional metadata configuration.\n * Maps table names to their metadata configuration.\n */\nexport type AdditionalMetadata = Record<string, TableMetadata>;\n\n/**\n * Options for configuring ForgeSQL ORM behavior.\n */\nexport interface ForgeSqlOrmOptions {\n /**\n * Enables logging of raw SQL queries in the Atlassian Forge Developer Console.\n * Useful for debugging and monitoring SQL operations.\n * @default false\n */\n logRawSqlQuery?: boolean;\n /**\n * Enables logging of raw SQL queries in the Atlassian Forge Developer Console.\n * Useful for debugging and monitoring SQL operations.\n * @default false\n */\n logRawSqlQueryParams?: boolean;\n\n /**\n * Disables optimistic locking for all operations.\n * When enabled, version checks are skipped during updates.\n * @default false\n */\n disableOptimisticLocking?: boolean;\n\n /**\n * Additional metadata for table configuration.\n * Allows specifying table-specific settings and behaviors.\n * @example\n * ```typescript\n * {\n * users: {\n * tableName: \"users\",\n * versionField: {\n * fieldName: \"updatedAt\",\n * type: \"datetime\",\n * nullable: false\n * }\n * }\n * }\n * ```\n */\n additionalMetadata?: AdditionalMetadata;\n}\n\n// ============= Custom Types =============\n\n/**\n * Custom type for MySQL datetime fields.\n * Handles conversion between JavaScript Date objects and MySQL datetime strings.\n */\nexport const forgeDateTimeString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"datetime\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"YYYY-MM-DDTHH:mm:ss.SSS\");\n },\n fromDriver(value: unknown) {\n const format = \"YYYY-MM-DDTHH:mm:ss.SSS\";\n return parseDateTime(value as string, format);\n },\n});\n\n/**\n * Custom type for MySQL timestamp fields.\n * Handles conversion between JavaScript Date objects and MySQL timestamp strings.\n */\nexport const forgeTimestampString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"timestamp\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"YYYY-MM-DDTHH:mm:ss.SSS\");\n },\n fromDriver(value: unknown) {\n const format = \"YYYY-MM-DDTHH:mm:ss.SSS\";\n return parseDateTime(value as string, format);\n },\n});\n\n/**\n * Custom type for MySQL date fields.\n * Handles conversion between JavaScript Date objects and MySQL date strings.\n */\nexport const forgeDateString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"date\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"YYYY-MM-DD\");\n },\n fromDriver(value: unknown) {\n const format = \"YYYY-MM-DD\";\n return parseDateTime(value as string, format);\n },\n});\n\n/**\n * Custom type for MySQL time fields.\n * Handles conversion between JavaScript Date objects and MySQL time strings.\n */\nexport const forgeTimeString = customType<{\n data: Date;\n driver: string;\n config: { format?: string };\n}>({\n dataType() {\n return \"time\";\n },\n toDriver(value: Date) {\n return moment(value as Date).format(\"HH:mm:ss.SSS\");\n },\n fromDriver(value: unknown) {\n return parseDateTime(value as string, \"HH:mm:ss.SSS\");\n },\n});\n"],"names":["eq","and","sql","drizzle","customType","moment"],"mappings":"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"}
|
package/dist/ForgeSQLORM.mjs
CHANGED
|
@@ -118,10 +118,6 @@ class ForgeSQLCrudOperations {
|
|
|
118
118
|
Object.keys(preparedModels[0]).map((key) => [key, schema[key]])
|
|
119
119
|
)
|
|
120
120
|
}) : queryBuilder;
|
|
121
|
-
const query = finalQuery.toSQL();
|
|
122
|
-
if (this.options?.logRawSqlQuery) {
|
|
123
|
-
console.debug("INSERT SQL:", query.sql);
|
|
124
|
-
}
|
|
125
121
|
const result = await finalQuery;
|
|
126
122
|
return result[0].insertId;
|
|
127
123
|
}
|
|
@@ -156,9 +152,6 @@ class ForgeSQLCrudOperations {
|
|
|
156
152
|
}
|
|
157
153
|
}
|
|
158
154
|
const queryBuilder = this.forgeOperations.getDrizzleQueryBuilder().delete(schema).where(and(...conditions));
|
|
159
|
-
if (this.options?.logRawSqlQuery) {
|
|
160
|
-
console.debug("DELETE SQL:", queryBuilder.toSQL().sql);
|
|
161
|
-
}
|
|
162
155
|
const result = await queryBuilder;
|
|
163
156
|
return result[0].affectedRows;
|
|
164
157
|
}
|
|
@@ -206,9 +199,6 @@ class ForgeSQLCrudOperations {
|
|
|
206
199
|
}
|
|
207
200
|
}
|
|
208
201
|
const queryBuilder = this.forgeOperations.getDrizzleQueryBuilder().update(schema).set(updateData).where(and(...conditions));
|
|
209
|
-
if (this.options?.logRawSqlQuery) {
|
|
210
|
-
console.debug("UPDATE SQL:", queryBuilder.toSQL().sql);
|
|
211
|
-
}
|
|
212
202
|
const result = await queryBuilder;
|
|
213
203
|
if (versionMetadata && result[0].affectedRows === 0) {
|
|
214
204
|
throw new Error(
|
|
@@ -234,9 +224,6 @@ class ForgeSQLCrudOperations {
|
|
|
234
224
|
throw new Error("WHERE conditions must be provided");
|
|
235
225
|
}
|
|
236
226
|
const queryBuilder = this.forgeOperations.getDrizzleQueryBuilder().update(schema).set(updateData).where(where);
|
|
237
|
-
if (this.options?.logRawSqlQuery) {
|
|
238
|
-
console.debug("UPDATE SQL:", queryBuilder.toSQL().sql);
|
|
239
|
-
}
|
|
240
227
|
const result = await queryBuilder;
|
|
241
228
|
return result[0].affectedRows;
|
|
242
229
|
}
|
|
@@ -466,8 +453,6 @@ const forgeDriver = {
|
|
|
466
453
|
console.error("SQL Error:", JSON.stringify(error));
|
|
467
454
|
throw error;
|
|
468
455
|
}
|
|
469
|
-
},
|
|
470
|
-
transaction: async (transactionFn) => {
|
|
471
456
|
}
|
|
472
457
|
};
|
|
473
458
|
class ForgeSQLORMImpl {
|
|
@@ -566,7 +551,7 @@ class ForgeSQLORM {
|
|
|
566
551
|
return this.ormInstance.getDrizzleQueryBuilder();
|
|
567
552
|
}
|
|
568
553
|
}
|
|
569
|
-
const
|
|
554
|
+
const forgeDateTimeString = customType({
|
|
570
555
|
dataType() {
|
|
571
556
|
return "datetime";
|
|
572
557
|
},
|
|
@@ -578,7 +563,7 @@ const mySqlDateTimeString = customType({
|
|
|
578
563
|
return parseDateTime(value, format);
|
|
579
564
|
}
|
|
580
565
|
});
|
|
581
|
-
const
|
|
566
|
+
const forgeTimestampString = customType({
|
|
582
567
|
dataType() {
|
|
583
568
|
return "timestamp";
|
|
584
569
|
},
|
|
@@ -590,7 +575,7 @@ const mySqlTimestampString = customType({
|
|
|
590
575
|
return parseDateTime(value, format);
|
|
591
576
|
}
|
|
592
577
|
});
|
|
593
|
-
const
|
|
578
|
+
const forgeDateString = customType({
|
|
594
579
|
dataType() {
|
|
595
580
|
return "date";
|
|
596
581
|
},
|
|
@@ -602,7 +587,7 @@ const mySqlDateString = customType({
|
|
|
602
587
|
return parseDateTime(value, format);
|
|
603
588
|
}
|
|
604
589
|
});
|
|
605
|
-
const
|
|
590
|
+
const forgeTimeString = customType({
|
|
606
591
|
dataType() {
|
|
607
592
|
return "time";
|
|
608
593
|
},
|
|
@@ -618,13 +603,13 @@ export {
|
|
|
618
603
|
ForgeSQLSelectOperations,
|
|
619
604
|
ForgeSQLORM as default,
|
|
620
605
|
extractAlias,
|
|
606
|
+
forgeDateString,
|
|
607
|
+
forgeDateTimeString,
|
|
621
608
|
forgeDriver,
|
|
609
|
+
forgeTimeString,
|
|
610
|
+
forgeTimestampString,
|
|
622
611
|
getPrimaryKeys,
|
|
623
612
|
getTableMetadata,
|
|
624
|
-
mySqlDateString,
|
|
625
|
-
mySqlDateTimeString,
|
|
626
|
-
mySqlTimeString,
|
|
627
|
-
mySqlTimestampString,
|
|
628
613
|
parseDateTime
|
|
629
614
|
};
|
|
630
615
|
//# sourceMappingURL=ForgeSQLORM.mjs.map
|