UNPKG

forge-sql-orm

Version:

Drizzle ORM integration for Forge-SQL in Atlassian Forge applications.

439 lines 17.6 kB
import { UpdateQueryResponse } from "@forge/sql"; import { SqlParameters } from "@forge/sql/out/sql-statement"; import { AnyMySqlSelectQueryBuilder, AnyMySqlTable, MySqlSelectBuilder } from "drizzle-orm/mysql-core"; import { MySqlSelectDynamic, type SelectedFields } from "drizzle-orm/mysql-core/query-builders/select.types"; import { InferInsertModel, Query, SQL } from "drizzle-orm"; import { MySqlRemoteDatabase, MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy/index"; import { SqlHints } from "../utils/sqlHints"; import { ClusterStatementRowCamelCase, ExplainAnalyzeRow, SlowQueryNormalized } from "./SystemTables"; /** * Core interface for ForgeSQL operations. * Provides access to CRUD operations, schema-level SQL operations, and query analysis capabilities. * * @interface ForgeSqlOperation * @extends {QueryBuilderForgeSql} */ export interface ForgeSqlOperation extends QueryBuilderForgeSql { /** * Provides CRUD (Create, Update, Delete) operations. * @deprecated Use modify() instead for better type safety and consistency * @returns {CRUDForgeSQL} Interface for performing CRUD operations */ crud(): CRUDForgeSQL; /** * Provides modify (Create, Update, Delete) operations with optimistic locking support. * @returns {CRUDForgeSQL} Interface for performing CRUD operations */ modify(): CRUDForgeSQL; /** * Provides schema-level SQL fetch operations with type safety. * @returns {SchemaSqlForgeSql} Interface for executing schema-bound SQL queries */ fetch(): SchemaSqlForgeSql; /** * Provides query analysis capabilities including EXPLAIN ANALYZE and slow query analysis. * @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance */ analyze(): SchemaAnalyzeForgeSql; } /** * Interface for Query Builder operations. * Provides access to the underlying Drizzle ORM query builder with enhanced functionality. * * @interface QueryBuilderForgeSql */ export interface QueryBuilderForgeSql { /** * Creates a new query builder for the given entity. * @returns {MySqlRemoteDatabase<Record<string, unknown>>} The Drizzle database instance for building queries */ getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>>; /** * Creates a select query with unique field aliases to prevent field name collisions in joins. * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables. * * @template TSelection - The type of the selected fields * @param {TSelection} fields - Object containing the fields to select, with table schemas as values * @returns {MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>} A select query builder with unique field aliases * @throws {Error} If fields parameter is empty * @example * ```typescript * await forgeSQL * .select({user: users, order: orders}) * .from(orders) * .innerJoin(users, eq(orders.userId, users.id)); * ``` */ select<TSelection extends SelectedFields>(fields: TSelection): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>; /** * Creates a distinct select query with unique field aliases to prevent field name collisions in joins. * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables. * * @template TSelection - The type of the selected fields * @param {TSelection} fields - Object containing the fields to select, with table schemas as values * @returns {MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>} A distinct select query builder with unique field aliases * @throws {Error} If fields parameter is empty * @example * ```typescript * await forgeSQL * .selectDistinct({user: users, order: orders}) * .from(orders) * .innerJoin(users, eq(orders.userId, users.id)); * ``` */ selectDistinct<TSelection extends SelectedFields>(fields: TSelection): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>; } /** * Interface for Modify (Create, Update, Delete) operations. * Provides methods for basic database operations with support for optimistic locking. * * @interface CRUDForgeSQL */ export interface CRUDForgeSQL { /** * Inserts multiple records into the database. * @template T - The type of the table schema * @param {T} schema - The entity schema * @param {InferInsertModel<T>[]} models - The list of entities to insert * @param {boolean} [updateIfExists] - Whether to update the row if it already exists (default: false) * @returns {Promise<number>} The number of inserted rows * @throws {Error} If the insert operation fails */ insert<T extends AnyMySqlTable>(schema: T, models: InferInsertModel<T>[], updateIfExists?: boolean): Promise<number>; /** * Deletes a record by its ID. * @template T - The type of the table schema * @param {unknown} id - The ID of the record to delete * @param {T} schema - The entity schema * @returns {Promise<number>} The number of rows affected * @throws {Error} If the delete operation fails */ deleteById<T extends AnyMySqlTable>(id: unknown, schema: T): Promise<number>; /** * Updates a record by its ID with optimistic locking support. * If a version field is defined in the schema, versioning is applied: * - the current record version is retrieved * - checked for concurrent modifications * - and then incremented * * @template T - The type of the table schema * @param {Partial<InferInsertModel<T>>} entity - The entity with updated values * @param {T} schema - The entity schema * @returns {Promise<number>} The number of rows affected * @throws {Error} If the primary key is not included in the update fields * @throws {Error} If optimistic locking check fails */ updateById<T extends AnyMySqlTable>(entity: Partial<InferInsertModel<T>>, schema: T): Promise<number>; /** * Updates specified fields of records based on provided conditions. * If the "where" parameter is not provided, the WHERE clause is built from the entity fields * that are not included in the list of fields to update. * * @template T - The type of the table schema * @param {Partial<InferInsertModel<T>>} updateData - The object containing values to update * @param {T} schema - The entity schema * @param {SQL<unknown>} [where] - Optional filtering conditions for the WHERE clause * @returns {Promise<number>} The number of affected rows * @throws {Error} If no filtering criteria are provided * @throws {Error} If the update operation fails */ updateFields<T extends AnyMySqlTable>(updateData: Partial<InferInsertModel<T>>, schema: T, where?: SQL<unknown>): Promise<number>; } /** * Interface for schema analysis operations. * Provides methods for analyzing query performance and execution plans. * * @interface SchemaAnalyzeForgeSql */ export interface SchemaAnalyzeForgeSql { /** * Executes EXPLAIN on a Drizzle query. * @param {{ toSQL: () => Query }} query - The Drizzle query to analyze * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results */ explain(query: { toSQL: () => Query; }): Promise<ExplainAnalyzeRow[]>; /** * Executes EXPLAIN on a raw SQL query. * @param {string} query - The SQL query to analyze * @param {unknown[]} bindParams - The query parameters * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results */ explainRaw(query: string, bindParams: unknown[]): Promise<ExplainAnalyzeRow[]>; /** * Executes EXPLAIN ANALYZE on a Drizzle query. * @param {{ toSQL: () => Query }} query - The Drizzle query to analyze * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results */ explainAnalyze(query: { toSQL: () => Query; }): Promise<ExplainAnalyzeRow[]>; /** * Executes EXPLAIN ANALYZE on a raw SQL query. * @param {string} query - The SQL query to analyze * @param {unknown[]} bindParams - The query parameters * @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results */ explainAnalyzeRaw(query: string, bindParams: unknown[]): Promise<ExplainAnalyzeRow[]>; /** * Analyzes slow queries from the database. * @returns {Promise<SlowQueryNormalized[]>} The normalized slow query data */ analyzeSlowQueries(): Promise<SlowQueryNormalized[]>; /** * Analyzes query history for specific tables using Drizzle table objects. * @param {AnyMySqlTable[]} tables - The Drizzle table objects to analyze * @param {Date} [fromDate] - The start date for the analysis * @param {Date} [toDate] - The end date for the analysis * @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history */ analyzeQueriesHistory(tables: AnyMySqlTable[], fromDate?: Date, toDate?: Date): Promise<ClusterStatementRowCamelCase[]>; /** * Analyzes query history for specific tables using raw table names. * @param {string[]} tables - The table names to analyze * @param {Date} [fromDate] - The start date for the analysis * @param {Date} [toDate] - The end date for the analysis * @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history */ analyzeQueriesHistoryRaw(tables: string[], fromDate?: Date, toDate?: Date): Promise<ClusterStatementRowCamelCase[]>; } /** * Interface for schema-level SQL operations. * Provides methods for executing SQL queries with schema binding and type safety. * * @interface SchemaSqlForgeSql */ export interface SchemaSqlForgeSql { /** * Executes a Drizzle query and returns a single result. * @template T - The type of the query builder * @param {T} query - The Drizzle query to execute * @returns {Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>} A single result object or undefined * @throws {Error} If more than one record is returned * @throws {Error} If the query execution fails */ executeQueryOnlyOne<T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>>(query: T): Promise<Awaited<T> extends Array<any> ? Awaited<T>[number] | undefined : Awaited<T> | undefined>; /** * Executes a raw SQL query and returns the results. * @template T - The type of the result objects * @param {string} query - The raw SQL query * @param {SqlParameters[]} [params] - Optional SQL parameters * @returns {Promise<T[]>} A list of results as objects * @throws {Error} If the query execution fails */ executeRawSQL<T extends object | unknown>(query: string, params?: SqlParameters[]): Promise<T[]>; /** * Executes a raw SQL update query. * @param {string} query - The raw SQL update query * @param {SqlParameters[]} [params] - Optional SQL parameters * @returns {Promise<UpdateQueryResponse>} The update response containing affected rows * @throws {Error} If the update operation fails */ executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse>; } /** * Interface for version field metadata. * Defines the configuration for optimistic locking version fields. * * @interface VersionFieldMetadata */ export interface VersionFieldMetadata { /** Name of the version field */ fieldName: string; } /** * Interface for table metadata. * Defines the configuration for a specific table. * * @interface TableMetadata */ export interface TableMetadata { /** Name of the table */ tableName: string; /** Version field configuration for optimistic locking */ versionField: VersionFieldMetadata; } /** * Type for additional metadata configuration. * Maps table names to their metadata configuration. * * @type {AdditionalMetadata} */ export type AdditionalMetadata = Record<string, TableMetadata>; /** * Interface for ForgeSQL ORM options * * @interface ForgeSqlOrmOptions */ export interface ForgeSqlOrmOptions { /** Whether to log raw SQL queries */ logRawSqlQuery?: boolean; /** Whether to disable optimistic locking */ disableOptimisticLocking?: boolean; /** SQL hints to be applied to queries */ hints?: SqlHints; /** * Additional metadata for table configuration. * Allows specifying table-specific settings and behaviors. * @example * ```typescript * { * users: { * tableName: "users", * versionField: { * fieldName: "updatedAt", * type: "datetime", * nullable: false * } * } * } * ``` */ additionalMetadata?: AdditionalMetadata; } /** * Custom type for MySQL datetime fields. * Handles conversion between JavaScript Date objects and MySQL datetime strings. * * @type {CustomType} */ export declare const forgeDateTimeString: { (): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TConfig extends Record<string, any> & { format?: string; }>(fieldConfig?: TConfig | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TName extends string>(dbName: TName, fieldConfig?: { format?: string; } | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: TName; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; }; /** * Custom type for MySQL timestamp fields. * Handles conversion between JavaScript Date objects and MySQL timestamp strings. * * @type {CustomType} */ export declare const forgeTimestampString: { (): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TConfig extends Record<string, any> & { format?: string; }>(fieldConfig?: TConfig | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TName extends string>(dbName: TName, fieldConfig?: { format?: string; } | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: TName; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; }; /** * Custom type for MySQL date fields. * Handles conversion between JavaScript Date objects and MySQL date strings. * * @type {CustomType} */ export declare const forgeDateString: { (): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TConfig extends Record<string, any> & { format?: string; }>(fieldConfig?: TConfig | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TName extends string>(dbName: TName, fieldConfig?: { format?: string; } | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: TName; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; }; /** * Custom type for MySQL time fields. * Handles conversion between JavaScript Date objects and MySQL time strings. * * @type {CustomType} */ export declare const forgeTimeString: { (): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TConfig extends Record<string, any> & { format?: string; }>(fieldConfig?: TConfig | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: ""; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; <TName extends string>(dbName: TName, fieldConfig?: { format?: string; } | undefined): import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{ name: TName; dataType: "custom"; columnType: "MySqlCustomColumn"; data: Date; driverParam: unknown; enumValues: undefined; }>; }; //# sourceMappingURL=ForgeSQLQueryBuilder.d.ts.map