import { DataTypeMap, MappedType } from './dataTypeMap.js'; /** * Canonical database-platform value used across MJ. Single source of truth — * config validation, env-var parsing, and runtime branching all compare * against these literals. Aliases (`mssql`, `postgres`, `pg`) are not * recognized. * * Lives in `@memberjunction/sql-dialect` (not `core` or `global`) because * this is the package that owns SQL dialect semantics; every other package * imports it from here (or from core, which re-exports for back-compat). */ export type DatabasePlatform = 'sqlserver' | 'postgresql'; /** * Abstract field type used by SchemaEngine to describe columns * in a platform-agnostic way before DDL generation. */ export type SchemaFieldType = 'string' | 'text' | 'integer' | 'bigint' | 'decimal' | 'boolean' | 'datetime' | 'date' | 'uuid' | 'json' | 'float' | 'time'; /** * Options for resolving an abstract schema type to a concrete SQL type. */ export interface ResolveTypeOptions { /** Abstract type (e.g., 'string', 'integer', 'boolean'). */ type: SchemaFieldType; /** Max length for string types. */ maxLength?: number; /** Precision for decimal types. */ precision?: number; /** Scale for decimal types. */ scale?: number; } /** * Result from limitClause() — SQL Server uses a prefix (TOP n) while * PostgreSQL uses a suffix (LIMIT n OFFSET m). */ export interface LimitClauseResult { /** SQL placed between SELECT and the column list (e.g., "TOP 10") */ prefix: string; /** SQL placed after the ORDER BY / WHERE clause (e.g., "LIMIT 10 OFFSET 20") */ suffix: string; } /** * Schema introspection queries for a given database platform. * Each dialect provides platform-specific catalog queries. */ export interface SchemaIntrospectionSQL { /** Query that returns all user tables in a schema */ listTables: string; /** Query that returns all columns for a given table */ listColumns: string; /** Query that returns constraints (PK, UNIQUE, CHECK) */ listConstraints: string; /** Query that returns foreign key relationships */ listForeignKeys: string; /** Query that returns indexes */ listIndexes: string; /** Template for checking if a database object exists */ objectExists: string; } /** * Options for generating a column definition in DDL. */ export interface ColumnDDLOptions { /** Column name (unquoted — the dialect will quote it). */ name: string; /** Full SQL type string (e.g., "NVARCHAR(255)", "INTEGER", "TIMESTAMPTZ"). */ sqlType: string; /** Whether the column allows NULL values. */ nullable: boolean; /** Optional default value expression (e.g., "'Active'", "GETUTCDATE()"). */ defaultValue?: string; } /** * Options for ALTER TABLE column modification. */ export interface AlterColumnOptions { /** Column name (unquoted). */ columnName: string; /** New SQL type string. */ newType: string; /** New nullability. */ newNullable: boolean; } /** * Options for generating trigger DDL. */ export interface TriggerOptions { /** Schema name */ schema: string; /** Table name the trigger is on */ tableName: string; /** Trigger name */ triggerName: string; /** Timing: BEFORE, AFTER, or INSTEAD OF */ timing: 'BEFORE' | 'AFTER' | 'INSTEAD OF'; /** Events that fire the trigger */ events: ('INSERT' | 'UPDATE' | 'DELETE')[]; /** The trigger body SQL */ body: string; /** For PostgreSQL: name of the trigger function */ functionName?: string; /** Whether the trigger fires FOR EACH ROW or FOR EACH STATEMENT */ forEach?: 'ROW' | 'STATEMENT'; } /** * Options for generating index DDL. */ export interface IndexOptions { /** Schema name */ schema: string; /** Table name */ tableName: string; /** Index name */ indexName: string; /** Columns to index */ columns: string[]; /** Whether this is a unique index */ unique?: boolean; /** Index method (btree, gin, gist, hash — PostgreSQL specific, ignored for SQL Server) */ method?: string; /** WHERE clause for partial indexes (PostgreSQL only) */ where?: string; /** INCLUDE columns (SQL Server covering index) */ includeColumns?: string[]; } /** * Minimal dialect interface consumed by `@memberjunction/sql-parser`. * * SQLParser needs only these properties to be dialect-aware. The full * {@link SQLDialect} class implements this interface plus 80+ additional * methods for DDL/DML generation, data type mapping, etc. * * When adding a new database platform, implement at minimum this interface * for parser support. Implement the full `SQLDialect` for complete MJ support. */ export interface SQLParserDialect { /** node-sql-parser dialect string (e.g., 'TransactSQL', 'PostgresQL', 'MySQL') */ ParserDialect: string; /** Quotes a database identifier. SQL Server: [name], PostgreSQL: "name", MySQL: `name` */ QuoteIdentifier(name: string): string; /** Whether ORDER BY is legal inside CTE definitions on this platform */ AllowsOrderByInCTE: boolean; /** Default ORDER BY expression for paging when no ORDER BY exists. * SQL Server: '(SELECT NULL)', PostgreSQL: '1' */ DefaultPagingOrderBy: string; } /** * Abstract base class for SQL dialect implementations. * * Encapsulates ALL database-specific SQL syntax patterns into a single, * testable abstraction. This is a pure string/logic layer with zero * database driver dependencies. */ export declare abstract class SQLDialect implements SQLParserDialect { /** * The platform key identifying this dialect. */ abstract get PlatformKey(): DatabasePlatform; /** * Returns the dialect name used by node-sql-parser for AST parsing. * SQL Server: 'TransactSQL', PostgreSQL: 'PostgresQL', etc. */ abstract get ParserDialect(): string; /** * Quotes a database identifier (table name, column name, etc.). * SQL Server: [name], PostgreSQL: "name" */ abstract QuoteIdentifier(name: string): string; /** * Produces a schema-qualified object reference. * SQL Server: [schema].[object], PostgreSQL: schema."object" */ abstract QuoteSchema(schema: string, object: string): string; /** * Quotes a column alias used in `SELECT ... AS `. SQL Server is * case-insensitive and accepts a bare identifier; PostgreSQL folds * unquoted identifiers to lowercase, so we must quote the alias when the * caller cares about preserving case (e.g. matching a TypeScript property * name in the result row). */ abstract QuoteColumnAlias(aliasName: string): string; /** * Canonicalizes a SCHEMA name to the form the platform actually stores when * the name appears UNQUOTED in DDL. PostgreSQL folds unquoted identifiers to * lowercase, so `__mj_BizAppsCommon` physically becomes `__mj_bizappscommon`; * SQL Server is case-insensitive and stores the name as-given. Routing every * schema CREATE/DROP/USE through this keeps the engine's (quoted) operations * aligned with what unquoted migration DDL produces — so a mixed-case schema * name can't split into two physical schemas (one quoted-mixed, one folded-lowercase). */ abstract CanonicalSchemaName(name: string): string; /** * Quotes a value as a SQL string literal. Both SQL Server and PostgreSQL * use single quotes with `''` doubling to escape internal apostrophes — * this is concrete in the base class so callers don't reinvent the * `value.replace(/'/g, "''")` pattern. Subclasses may override if a * future dialect needs a different escape rule. */ QuoteStringLiteral(value: string): string; /** * Returns pagination SQL fragments. * SQL Server uses TOP (prefix) or OFFSET/FETCH (suffix). * PostgreSQL uses LIMIT/OFFSET (suffix). */ abstract LimitClause(limit: number, offset?: number): LimitClauseResult; /** * Returns a boolean literal for the platform. * SQL Server: "1"/"0", PostgreSQL: "true"/"false" */ abstract BooleanLiteral(value: boolean): string; /** * Returns the SQL type token for a boolean parameter in a stored-procedure / * function signature. Used by codegen when emitting tolerant-SP `_Clear` * companion parameters and other boolean-typed params. * * SQL Server: `bit` (BIT type, 0/1) * PostgreSQL: `boolean` (BOOLEAN type, TRUE/FALSE) * * Hardcoding `bit` everywhere worked on SQL Server but produced sprocs * that PG rejected as `operator does not exist: boolean = integer` when * the generated CASE compared a `bit`-declared parameter with `= 1`. */ abstract BooleanParameterType(): string; /** * Returns the current UTC timestamp expression. * SQL Server: GETUTCDATE(), PostgreSQL: NOW() AT TIME ZONE 'UTC' */ abstract CurrentTimestampUTC(): string; /** * Wraps an expression in the dialect's lowercase function — used for * case-insensitive comparison when authoring filters that must work on * both SS (default case-insensitive collation) and PG (case-sensitive). * * Both SQL Server and PostgreSQL implement `LOWER()` per the ANSI SQL * standard, so the default returns `LOWER(${expr})`. A subclass would * override only for an exotic dialect (e.g. one that exposes `lc()` or * needs a CAST first). * * Use this instead of hardcoding `LOWER(...)` in callers — keeps the * dialect-aware SQL surface in one place per the SQLDialect contract. */ LowerCase(expr: string): string; /** SQL type names this dialect uses for boolean columns. */ abstract get BooleanTypeNames(): readonly string[]; /** SQL type names this dialect uses for variable-length character / text columns. */ abstract get StringTypeNames(): readonly string[]; /** * Subset of {@link StringTypeNames} that represents **fixed-width** / * space-padded character types. SQL Server `char`/`nchar` and PostgreSQL * `char`/`bpchar`/`character` (without `varying`) all right-pad stored * values with spaces up to the declared length and return that padding * in result sets. Variable-width types (`varchar`, `nvarchar`, `text`, * etc.) do not. * * Used by `BaseEntity` to rtrim padding on load so dirty-checks and * downstream consumers see the logical value, not the storage form. */ abstract get FixedWidthStringTypeNames(): readonly string[]; /** * Maximum string length usable in an INDEX KEY column (PRIMARY KEY / UNIQUE constraint) on this * dialect. A PK string column wider than this can't be indexed, so callers (e.g. the integration * schema builder) cap PK string columns at this value. Default: no practical declare-time cap — a * dialect overrides it where one exists. SQL Server's 900-byte index-key limit = 450 NVARCHAR chars; * PostgreSQL enforces its (larger) btree limit on the stored value at write time, not the declared * length, so it keeps the no-cap default. */ get MaxKeyStringLength(): number; /** * Maximum bytes that can be stored in-row for a single row, or `null` when the dialect has no * in-row size limit. SQL Server enforces a hard ~8060-byte in-row limit; PostgreSQL has none * (TOAST stores oversized variable-length values out-of-line). Consumed by schema materialization * to avoid emitting a table whose minimum in-row footprint can never satisfy an INSERT. * Default: `null` (no in-row size limit). */ get MaxInRowSizeBytes(): number | null; /** * Hard maximum number of columns per table, or `null` when effectively unbounded for our purposes. * SQL Server: 1024. PostgreSQL: 1600. Default: `null`. */ get MaxColumnCount(): number | null; /** * Minimum in-row byte footprint of a column of the given raw SQL type. Off-row-capable * variable-length / LOB types contribute only their in-row pointer; fixed-length types contribute * their full size. Only meaningful for dialects that report a {@link MaxInRowSizeBytes}. * Default: 24 (a conservative off-row-pointer floor). */ EstimateInRowBytes(_rawSqlType: string): number; /** SQL type names this dialect uses for date / time / timestamp columns. */ abstract get DateTypeNames(): readonly string[]; /** SQL type names this dialect uses for integer columns (int, bigint, smallint, …). */ abstract get IntegerTypeNames(): readonly string[]; /** SQL type names this dialect uses for floating-point / decimal columns. */ abstract get FloatTypeNames(): readonly string[]; /** SQL type names this dialect uses for UUID / uniqueidentifier columns. */ abstract get UuidTypeNames(): readonly string[]; /** SQL type names this dialect uses for binary blob columns (image, bytea, varbinary). */ abstract get BinaryTypeNames(): readonly string[]; /** SQL type names this dialect uses for JSON / XML structured columns. */ abstract get JsonTypeNames(): readonly string[]; /** SQL type names this dialect uses for fixed-precision currency columns. */ abstract get CurrencyTypeNames(): readonly string[]; /** SQL type names this dialect uses for interval / duration columns. */ abstract get IntervalTypeNames(): readonly string[]; /** SQL type names this dialect uses for network address columns (inet, cidr, …). */ abstract get NetworkTypeNames(): readonly string[]; /** * Returns a new UUID generation expression. * SQL Server: NEWID(), PostgreSQL: gen_random_uuid() */ abstract NewUUID(): string; /** * Returns the platform's n-ary null-coalescing expression. SQL Server and * PostgreSQL both spell this `COALESCE(...)`, but a future dialect could * use a different keyword — abstract on purpose so each dialect must * declare its own form rather than inheriting an opinionated default. */ abstract Coalesce(expr: string, fallback: string): string; /** * Returns the dialect's literal representation of NULL as it would * appear in generated SQL (e.g. as the result of a default-value * formatter). Both SQL Server and PostgreSQL use the bare keyword * `NULL`, but a future dialect could differ — codegen comparisons * should route through this rather than hard-coding the string. */ get NullLiteral(): string; /** * Returns true if `value` is the dialect's representation of a NULL * literal in generated SQL. Comparison is case-insensitive after * trimming whitespace. Subclasses may override if a dialect uses a * non-keyword form (none currently do). */ IsNullLiteral(value: string): boolean; /** * Returns the parameter-reference syntax used by this dialect's * stored-procedure / function bodies. * SQL Server: `@MyName`, PostgreSQL functions: `p_my_name`. * Codegen should call this rather than hard-coding `'@' + name`. */ abstract ParameterRef(name: string): string; /** * Returns the default-value clause appended to a parameter declaration. * SQL Server: ` = NULL` (or ` = 0`, etc.), PostgreSQL: ` DEFAULT NULL`. * `value` should be a SQL literal already formatted by the caller (e.g. * the dialect's NullLiteral, a quoted string, a numeric literal). */ abstract ParameterDefault(value: string): string; /** * Returns a CAST-to-text expression. * SQL Server: CAST(expr AS NVARCHAR(MAX)), PostgreSQL: CAST(expr AS TEXT) */ abstract CastToText(expr: string): string; /** * Returns a CAST to a bounded-width string type. Used when the result * needs to be comparable against an indexed column (SQL Server cannot * compare/index `NVARCHAR(MAX)`) or against a fixed-width text column * such as MJ's `RecordID` (NVARCHAR(450) on SQL Server). * * Implemented by composing `ResolveAbstractType({ type: 'string', maxLength })`, * which dialects already supply — SQL Server emits `NVARCHAR(N)` and * PostgreSQL emits `VARCHAR(N)`. Defaults to MJ's standard 450-char * width to match the cap on indexable string columns in SQL Server. */ CastToBoundedString(expr: string, maxLength?: number): string; /** * Returns a CAST-to-UUID expression. * SQL Server: CAST(expr AS UNIQUEIDENTIFIER), PostgreSQL: CAST(expr AS UUID) */ abstract CastToUUID(expr: string): string; /** * Returns the empty-GUID sentinel literal * (`00000000-0000-0000-0000-000000000000`) formatted for use in a * CASE-comparison expression. The base class returns the literal as a * plain quoted string — SQL Server's implicit conversion accepts that * directly. Dialects with strict typing (PostgreSQL) override to add * the explicit cast their grammar requires. */ EmptyUUIDLiteral(): string; /** * Returns the clause used to get inserted values back. * SQL Server: OUTPUT INSERTED.col1, INSERTED.col2 * PostgreSQL: RETURNING col1, col2 */ abstract ReturnInsertedClause(columns?: string[]): string; /** * Returns the auto-increment PK expression for DDL. * SQL Server: IDENTITY(1,1), PostgreSQL: GENERATED ALWAYS AS IDENTITY */ abstract AutoIncrementPKExpression(): string; /** * Returns the default expression for a UUID primary key. * SQL Server: NEWSEQUENTIALID(), PostgreSQL: gen_random_uuid() */ abstract UUIDPKDefault(): string; /** * Returns the expression to get the last inserted identity value. * SQL Server: SCOPE_IDENTITY(), PostgreSQL: lastval() */ abstract ScopeIdentityExpression(): string; /** * Returns the row count variable/expression for the last statement. * SQL Server: @@ROWCOUNT, PostgreSQL: (via GET DIAGNOSTICS or FOUND) */ abstract RowCountExpression(): string; /** * Returns the batch separator for the platform. * SQL Server: "GO", PostgreSQL: "" (none needed) */ abstract BatchSeparator(): string; /** * Splits an oversized SQL batch into individual statements on `;`+EOL * boundaries so a caller (e.g. the RSU migration executor) can re-group * them into smaller chunks that each fit under a client request timeout. * * Base implementation = the naive `split(/;\s*\n/g)` semantics: split on a * `;` followed by optional inline whitespace and a newline, trim each * fragment, drop empties, and ensure each returned statement ends with `;`. * This is correct for SQL Server (no dollar-quoted blocks). * * PostgreSQL overrides this with a dollar-quote-aware split that never * tears apart `DO $$ … $$` / `$tag$ … $tag$` blocks whose bodies * legitimately contain `;`+newline. */ SplitStatements(batch: string): string[]; /** * Returns SQL to check if a database object exists. * @param objectType - "TABLE", "VIEW", "FUNCTION", "PROCEDURE", "TRIGGER" * @param schema - Schema name * @param name - Object name */ abstract ExistenceCheckSQL(objectType: string, schema: string, name: string): string; /** * Whether the platform supports CREATE OR REPLACE for a given object type. * PostgreSQL supports it for FUNCTION, VIEW. SQL Server does not. */ abstract CreateOrReplaceSupported(objectType: string): boolean; /** * Returns a full-text search predicate expression. * SQL Server: CONTAINS(column, searchTerm) * PostgreSQL: column @@ plainto_tsquery('english', searchTerm) */ abstract FullTextSearchPredicate(column: string, searchTerm: string): string; /** * Returns DDL to create a full-text index. * SQL Server: FULLTEXT CATALOG + FULLTEXT INDEX * PostgreSQL: tsvector column + GIN index */ abstract FullTextIndexDDL(table: string, columns: string[], catalog?: string): string; /** * Returns the recursive CTE syntax keyword. * SQL Server: "WITH", PostgreSQL: "WITH RECURSIVE" */ abstract RecursiveCTESyntax(): string; /** * Whether the platform allows ORDER BY inside CTE definitions without * TOP, OFFSET, or FOR XML. * SQL Server: false (ORDER BY in CTEs is illegal without TOP/OFFSET/FOR XML) * PostgreSQL: true (ORDER BY in CTEs is always legal) */ abstract get AllowsOrderByInCTE(): boolean; /** * Default ORDER BY expression for paging when no user-specified ORDER BY exists. * SQL Server: '(SELECT NULL)', PostgreSQL: '1' */ abstract get DefaultPagingOrderBy(): string; /** * Returns the data type mapping for this dialect. */ abstract get TypeMap(): DataTypeMap; /** * Convenience: maps a SQL Server type to this dialect's equivalent. */ MapDataType(sqlServerType: string, length?: number, precision?: number, scale?: number): MappedType; /** * Convenience: maps a SQL Server type to a full type string. */ MapDataTypeToString(sqlServerType: string, length?: number, precision?: number, scale?: number): string; /** * Returns a parameter placeholder for the given index. * SQL Server: @p0, @p1, ... PostgreSQL: $1, $2, ... */ abstract ParameterPlaceholder(index: number): string; /** * Returns the string concatenation operator. * SQL Server: "+", PostgreSQL: "||" */ abstract ConcatOperator(): string; /** * Returns a STRING_SPLIT or equivalent expression. * SQL Server: STRING_SPLIT(value, delimiter) * PostgreSQL: string_to_array(value, delimiter) or regexp_split_to_table */ abstract StringSplitFunction(value: string, delimiter: string): string; /** * Returns a JSON value extraction expression. * SQL Server: JSON_VALUE(column, path) * PostgreSQL: column->>'path' or jsonb_extract_path_text */ abstract JsonExtract(column: string, path: string): string; /** * Splits `${...}` inside SQL string literals so Flyway doesn't treat * them as placeholders. Each `${name}` becomes a concat-split that * round-trips back to `${name}` at execution but contains no adjacent * `${` in the file text. Form is platform-specific (concat operator, * truncation rules) — see each dialect's implementation. */ abstract EscapeFlywayStringInterpolation(sql: string): string; /** * Returns the SQL syntax for calling a stored procedure or function. * SQL Server: EXEC [schema].[name] @p0, @p1 * PostgreSQL: SELECT * FROM schema.name($1, $2) */ abstract ProcedureCallSyntax(schema: string, name: string, params: string[]): string; /** * Returns CREATE SCHEMA IF NOT EXISTS SQL. * SQL Server: IF NOT EXISTS (...) EXEC('CREATE SCHEMA [name]'); GO * PostgreSQL: CREATE SCHEMA IF NOT EXISTS "name"; */ abstract CreateSchemaDDL(schemaName: string): string; /** * Cap a column type if it cannot be used in a UNIQUE/index constraint. * SQL Server: NVARCHAR(MAX) → NVARCHAR(450) (MAX columns cannot be indexed). * PostgreSQL: no-op (TEXT can be indexed). * Override in platform-specific dialects. */ CapIndexableType(rawSqlType: string): string; /** * Returns the ADD COLUMN clause for ALTER TABLE. * SQL Server: ADD [colName] type NULL DEFAULT ... * PostgreSQL: ADD COLUMN "colName" type NULL DEFAULT ... */ abstract AddColumnClause(col: ColumnDDLOptions): string; /** * Returns ALTER COLUMN clause(s) for type/nullability changes. * SQL Server: ALTER TABLE t ALTER COLUMN [col] newType NULL/NOT NULL; * PostgreSQL: ALTER TABLE t ALTER COLUMN "col" TYPE newType, ALTER COLUMN "col" SET/DROP NOT NULL; */ abstract AlterColumnDDL(quotedTable: string, options: AlterColumnOptions): string; /** * Returns description metadata SQL for a column. * SQL Server: EXEC sp_addextendedproperty with @level2type = 'COLUMN' * PostgreSQL: COMMENT ON COLUMN schema."table"."column" IS '...'; * * This extends CommentOnObject to support the 3-part column reference * that CommentOnObject doesn't handle. */ abstract CommentOnColumn(schema: string, table: string, column: string, comment: string): string; /** * Returns the platform's fallback type for unknown/unmapped abstract types. * SQL Server: NVARCHAR(MAX) * PostgreSQL: TEXT */ abstract FallbackType(): string; /** * Resolves an abstract schema field type to a concrete SQL type string. * Used by SchemaEngine for DDL generation from platform-agnostic definitions. * SQL Server: 'string' -> 'NVARCHAR(255)', 'boolean' -> 'BIT' * PostgreSQL: 'string' -> 'VARCHAR(255)', 'boolean' -> 'BOOLEAN' */ abstract ResolveAbstractType(options: ResolveTypeOptions): string; /** * Returns a date/time arithmetic expression. * SQL Server: DATEADD(MINUTE, 30, GETUTCDATE()) * PostgreSQL: (NOW() AT TIME ZONE 'UTC') + INTERVAL '30 minutes' * * @param unit - Time unit * @param amount - Number of units to add (can be negative) * @param baseExpr - Base timestamp expression (e.g., from CurrentTimestampUTC()) */ abstract DateAddExpression(unit: 'MINUTE' | 'HOUR' | 'DAY', amount: number, baseExpr: string): string; /** * Returns a full CREATE TABLE wrapped in a "create if not exists" guard. * SQL Server: IF NOT EXISTS (sys.tables check) BEGIN CREATE TABLE ... END; * PostgreSQL: CREATE TABLE IF NOT EXISTS ...; * * @param schema - Schema name * @param tableName - Table name * @param columnsDDL - The column definitions (everything between the parentheses) */ abstract CreateTableIfNotExistsDDL(schema: string, tableName: string, columnsDDL: string): string; /** * Returns a conditional IF/ELSE block in platform-appropriate procedural SQL. * SQL Server: IF (condition) BEGIN thenSQL END ELSE BEGIN elseSQL END * PostgreSQL: DO $$ BEGIN IF condition THEN thenSQL; ELSE elseSQL; END IF; END $$; * * @param condition - SQL boolean condition * @param thenSQL - SQL to execute when condition is true * @param elseSQL - Optional SQL to execute when condition is false */ abstract ConditionalBlock(condition: string, thenSQL: string, elseSQL?: string): string; /** * Returns a non-fatal signal/notice statement detectable in CLI output. * Used for signaling conditions (e.g., "lock held") without aborting the script. * SQL Server: RAISERROR('message', 16, 1) — appears in sqlcmd stdout * PostgreSQL: RAISE NOTICE 'message' — appears in psql stderr * * Note: For PostgreSQL, this must be used inside a ConditionalBlock (DO $$ context). * * @param message - Signal message to emit (used for detection in CLI output) */ abstract RaiseSignalSQL(message: string): string; /** * Generates trigger DDL for the platform. */ abstract TriggerDDL(options: TriggerOptions): string; /** * Generates index DDL for the platform. */ abstract IndexDDL(options: IndexOptions): string; /** * Returns a GRANT statement for the platform. */ abstract GrantPermission(permission: string, objectType: string, schema: string, object: string, role: string): string; /** * Returns a COMMENT ON statement (PostgreSQL) or sp_addextendedproperty (SQL Server). */ abstract CommentOnObject(objectType: string, schema: string, name: string, comment: string): string; /** * A full CREATE TABLE that runs only if the table is absent, as a SINGLE statement. * Default (PostgreSQL et al.): `CREATE TABLE IF NOT EXISTS (...);` * SQL Server overrides with an `IF OBJECT_ID(...) IS NULL` guard (it has no native * CREATE TABLE IF NOT EXISTS). * @param fullTable - Already-quoted `schema.table` identifier * @param columnsBody - The column/constraint lines that go between the parentheses */ CreateTableIfAbsent(fullTable: string, columnsBody: string): string; /** * CommentOnObject that is safe to re-run (no error if the description already exists). * Default returns the standard statement terminated with ';' — adequate where the * comment statement is inherently idempotent (PostgreSQL COMMENT ON replaces in place). * SQL Server overrides to guard sp_addextendedproperty with a fn_listextendedproperty check. */ CommentOnObjectIfAbsent(objectType: string, schema: string, name: string, comment: string): string; /** * CommentOnColumn that is safe to re-run. Default returns the standard statement * (PostgreSQL COMMENT ON COLUMN already includes its terminator and is idempotent). * SQL Server overrides to guard sp_addextendedproperty. */ CommentOnColumnIfAbsent(schema: string, table: string, column: string, comment: string): string; /** * Returns platform-specific schema introspection queries. */ abstract SchemaIntrospectionQueries(): SchemaIntrospectionSQL; /** * Returns a ready-to-run (no bind parameters) query that enumerates the foreign-key graph * of a single schema, for FK-cascade planning (e.g. Open-App metadata teardown). * * Unlike {@link SchemaIntrospectionQueries}.`listForeignKeys` (a placeholder template), this * embeds the schema literal directly (via {@link QuoteStringLiteral}) so it can be executed * with `ExecuteSQL(sql)` on any provider without a dialect-specific bind convention. It also * returns two extra columns the cascade planner needs: * * - `childNullable` — whether the referencing (child) column allows NULL, which decides * `UPDATE … SET NULL` (nullable) vs. `DELETE` + recurse (NOT NULL). * - `colCount` — the number of columns in the FK constraint, so a caller can exclude * composite FKs (`colCount > 1`). * * Every row is one FK column. Column aliases are IDENTICAL across dialects: * `parentTable, parentRefCol, childTable, childCol, childNullable, fkName, colCount` * (both the referenced/parent and referencing/child tables are within `schema`). * * @param schema the schema whose intra-schema FK edges to enumerate (e.g. `__mj`) */ abstract ForeignKeyGraphSQL(schema: string): string; /** * Wraps a list of statements in ONE all-or-nothing transaction batch for this platform, ready to * run as a single `ExecuteSQL(script)` call. Owns the platform-specific session/transaction setup * so callers don't sniff `PlatformKey` themselves: * * - **SQL Server**: `SET QUOTED_IDENTIFIER ON` / `SET ANSI_NULLS ON` (required for UPDATE/DELETE * against tables with filtered / computed-column indexes or indexed views — Msg 1934 otherwise) * + `SET XACT_ABORT ON` (any failure rolls the whole batch back) + `BEGIN/COMMIT TRANSACTION`. * - **PostgreSQL**: plain `BEGIN … COMMIT` — no session pragmas (`QUOTED_IDENTIFIER`/`ANSI_NULLS` * are SQL-Server concepts) and PostgreSQL already aborts the whole transaction on any error. * * Returns an empty string for an empty statement list (nothing to run). * * @param statements individual SQL statements (each WITHOUT a trailing `;`) */ abstract AtomicBatchScript(statements: string[]): string; /** * Returns the platform's two-argument null-coalescing expression. * SQL Server: `ISNULL(expr, fallback)`, PostgreSQL: `COALESCE(expr, fallback)`. * Abstract because each dialect must declare its own keyword — there is no * safe default. A future dialect that has neither `ISNULL` nor `COALESCE` * would silently emit invalid SQL if this fell through to a base * implementation. */ abstract IsNull(expr: string, fallback: string): string; /** * Returns true if the given error represents an infrastructure-level * connection failure (timeout, refused, pool closed, etc.) as opposed to * a query-level error (bad SQL, constraint violation). * * Each dialect implements this using its driver's structured error types: * - SQL Server (mssql): `error.name === 'ConnectionError'` * - PostgreSQL (pg): Node.js network error codes on plain `Error` * * Used by GenericDatabaseProvider to re-throw connection errors from * RunView/RunQuery instead of swallowing them into `{ Success: false }`. */ abstract IsConnectionError(e: unknown): boolean; /** * Returns an IIF/CASE equivalent expression. * SQL Server: IIF(condition, trueVal, falseVal) * PostgreSQL: CASE WHEN condition THEN trueVal ELSE falseVal END */ abstract IIF(condition: string, trueVal: string, falseVal: string): string; } //# sourceMappingURL=sqlDialect.d.ts.map