PRAGMAs, MySQL sql_mode and PostgreSQL's search_path. sql-constants.ts[!NOTE]
These are SQL statements to send. For the TypeScript enums you pass as
option values, such asConstraintType,ReferentialActionandIsolationLevel, see Enums and constants.
import { MYSQL, SQLITE } from 'ts-prorm-orm';
await prorm.query(SQLITE.PRAGMA.journal_mode.WAL);
// PRAGMA journal_mode = WAL
await prorm.query(MYSQL.FOREIGN_KEY_CHECKS.disable);
// SET FOREIGN_KEY_CHECKS = 0SQL is the whole table keyed by dialect (SQL.postgres, SQL.mysql, …), andgetConstantsForDialect(name) picks the right set at runtime:import { getConstantsForDialect } from 'ts-prorm-orm';
const c = getConstantsForDialect(prorm.getDialect());mysql, mariadb, tidb, postgres, sqlite, turso,cockroachdb, timescaledb, greenplum, yugabytedb, redshift, db2,snowflake, clickhouse. The PostgreSQL-derived dialects reuse the PostgreSQLtimescaledb gets session_replication_role, not MySQL's syntax), TiDB[!CAUTION]
Any other name, including'mssql'and'oracle', falls back to the MySQL
set.getConstantsForDialect('mssql').FOREIGN_KEY_CHECKS.disableisSET FOREIGN_KEY_CHECKS = 0, which SQL Server rejects. For foreign-key checks
and isolation levels, use the connection methods below, which resolve per
engine and throw where there is no equivalent.
| MySQL / MariaDB | PostgreSQL | SQLite | |
|---|---|---|---|
ISOLATION_LEVEL | ✓ | ✓ | ✓ (PRAGMA read_uncommitted) |
FOREIGN_KEY_CHECKS | ✓ (SET FOREIGN_KEY_CHECKS) | ✓ (session_replication_role) | via PRAGMA |
UNIQUE_KEY_CHECKS | ✓ | — | — |
AUTOCOMMIT | ✓ | — (removed; see below) | — |
CACHE | MariaDB only (MARIADB.CACHE; see below) | — (removed; see below) | — |
SQL_MODE | ✓ | — | — |
CONSTRAINT_DEFERral | — | ✓ | — |
SEARCH_PATH | — | ✓ | — |
PRAGMA | — | — | ✓ |
The PostgreSQL key really is spelled CONSTRAINT_DEFERral, in mixed case, in
both the interface and the constant. It is written that way here so that a
copy-paste compiles.
[!IMPORTANT]
Three constants that targeted settings current servers no longer have are
removed in 4.9.2:MYSQL.CACHE(query_cache_type; MySQL 8.0 removed the
query cache),POSTGRES.AUTOCOMMIT(SET SESSION autocommit, gone since
PostgreSQL 7.4) andPOSTGRES.CACHE(statement_cache_mode, which is not a
PostgreSQL setting). Reading one of them now throws an error that says what
to use instead, rather than handing the server a statement it rejects:[ORM] MYSQL.CACHE is obsolete: MySQL 8.0 removed the query cache, so `SET SESSION query_cache_type` is an error. Use MARIADB.CACHE on MariaDB, which still has it.The names are not enumerable, so spreading or iterating the tables is
unaffected. MariaDB still has the query cache:MARIADB.CACHE.onisSET SESSION query_cache_type = ON.
import { IsolationLevelEnum } from 'ts-prorm-orm';
prorm.getSetIsolationLevelSQL('REPEATABLE_READ'); // just the SQL, for the connected engine
await prorm.transaction(async (t) => {
await prorm.setIsolationLevel(IsolationLevelEnum.SERIALIZABLE, { transaction: t });
// … the transaction's statements …
});getSetIsolationLevelSQL(level) asks the connected dialect for its statement.'READ_COMMITTED' or'READ COMMITTED'), plus native levels an engine has, such as 'SNAPSHOT' onREAD COMMITTED and SERIALIZABLE; any other level throwsDatabaseError that says so.[!IMPORTANT]
On PostgreSQL,SET TRANSACTIONonly affects the transaction it runs in. Sent
through the pool, it would land on an idle connection and change nothing, soprorm.setIsolationLevel()without a transaction throws instead:TransactionError: postgres: SET TRANSACTION only affects the transaction it runs in. Pass { transaction }, or start the transaction with { isolationLevel }.On MySQL the statement has no SESSIONkeyword either, so it applies to the
next transaction on that connection only. The simplest portable form isprorm.transaction(fn, { isolationLevel: 'SERIALIZABLE' }); see
Transactions.
MYSQL.ISOLATION_LEVEL and POSTGRES.ISOLATION_LEVEL constants differ fromSET SESSION, which| Level | MYSQL.ISOLATION_LEVEL | POSTGRES.ISOLATION_LEVEL |
|---|---|---|
READ_UNCOMMITTED | SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED |
READ_COMMITTED | SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED | SET TRANSACTION ISOLATION LEVEL READ COMMITTED |
REPEATABLE_READ | SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ |
SERIALIZABLE | SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE | SET TRANSACTION ISOLATION LEVEL SERIALIZABLE |
read_uncommitted matters onlyawait prorm.disableForeignKeyChecks();
// … load data in whatever order you like …
await prorm.enableForeignKeyChecks();
await prorm.disableUniqueKeyChecks(); // MySQL/MariaDB only; a no-op elsewhere
await prorm.enableUniqueKeyChecks();UnsupportedForeignKeyChecksError, naming that engine's alternative,UnsupportedForeignKeyChecksError: Session-level foreign key checks are not supported on mssql.
Use ALTER TABLE <table> NOCHECK CONSTRAINT ALL per table instead.| Engine | Why it throws, and what to do instead |
|---|---|
| Oracle | ALTER TABLE <table> DISABLE CONSTRAINT <name> per constraint |
| Db2 | SET INTEGRITY FOR <table> OFF / IMMEDIATE CHECKED per table |
| DuckDB, Spanner | no session switch; drop and recreate the constraint |
| Snowflake, Redshift, Databricks | foreign keys are informational and never enforced, so there is nothing to disable |
| ClickHouse | no foreign keys |
getForeignKeyChecksSQL(dialect, 'disable' | 'enable') is the underlyingsession_replication_role needs superuser, or aSET ON PARAMETER session_replication_role (PostgreSQL 15+).import { getForeignKeyChecksSQL } from 'ts-prorm-orm';
const d = prorm.getDialect();
await prorm.transaction(async (t) => {
await prorm.query(getForeignKeyChecksSQL(d, 'disable'), { transaction: t });
await OrderLine.bulkCreate(lines, { transaction: t }); // children first
await Order.bulkCreate(orders, { transaction: t });
await prorm.query(getForeignKeyChecksSQL(d, 'enable'), { transaction: t });
});SELECT … FROM order_lines l LEFT JOIN orders o ON o.id = l.order_id WHERE o.id IS NULL[!WARNING]
SQLite ignoresPRAGMA foreign_keysinside a transaction, so on SQLite the
pragma has to run beforeBEGIN. Useprorm.disableForeignKeyChecks()
outside the transaction there.
import { SQLITE } from 'ts-prorm-orm';
SQLITE.PRAGMA.foreign_keys.on; // PRAGMA foreign_keys = ON
SQLITE.PRAGMA.journal_mode.WAL; // PRAGMA journal_mode = WAL
SQLITE.PRAGMA.synchronous.NORMAL; // PRAGMA synchronous = NORMAL
SQLITE.PRAGMA.trusted_schema.off; // PRAGMA trusted_schema = OFFjournal_mode accepts WAL, DELETE, TRUNCATE, PERSIST, MEMORY;synchronous accepts OFF, NORMAL, FULL, EXTRA.journal_mode = WAL withsynchronous = NORMAL: readers stop blocking the writer, and you keepFULL buys).import { SQLITE } from 'ts-prorm-orm';
await prorm.query(SQLITE.PRAGMA.journal_mode.WAL); // persistent: stored in the database file
await prorm.query(SQLITE.PRAGMA.synchronous.NORMAL); // per connection
await prorm.query(SQLITE.PRAGMA.foreign_keys.on); // per connection, and off by defaultjournal_mode = WAL is written into the database file and survives restarts.synchronous and foreign_keys are per connection and reset on every new one.sql_modeimport { MYSQL } from 'ts-prorm-orm';
MYSQL.SQL_MODE.STRICT_TRANS_TABLES; // SET @@sql_mode = 'STRICT_TRANS_TABLES'
MYSQL.SQL_MODE.TRADITIONAL; // SET @@sql_mode = 'TRADITIONAL'
MYSQL.SQL_MODE.NO_ZERO_DATE; // SET @@sql_mode = 'NO_ZERO_DATE'STRICT_TRANS_TABLES (or TRADITIONAL) turns silent truncation and0000-00-00.[!WARNING]
These constants assignsql_moderather than appending to it, so a later
one replaces an earlier one.SET @@sql_mode = 'NO_ZERO_DATE'switches strict
mode off, and after it a too-long string is truncated again.ALLis not a mode, so the server rejects it.MYSQL.SQL_MODE.NO_AUTO_CREATE_USER
is removed in 4.9.2 (MySQL 8.0 dropped the mode) and throws when read;MARIADB.SQL_MODE.NO_AUTO_CREATE_USERkeeps it for MariaDB. To combine modes, send your own statement:SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO'.
import { POSTGRES } from 'ts-prorm-orm';
await prorm.query(POSTGRES.SEARCH_PATH.set('reporting')); // SET search_path TO reporting
await prorm.query(POSTGRES.SEARCH_PATH.set('reporting, public')); // SET search_path TO reporting, public
await prorm.query(POSTGRES.SEARCH_PATH.reset); // SET search_path TO DEFAULTSEARCH_PATH.set is a function, not a string, and it interpolates its argumentFindOptions.searchPath andschema option are the declarative alternatives.import { POSTGRES } from 'ts-prorm-orm';
await prorm.transaction(async (t) => {
await prorm.query(POSTGRES.CONSTRAINT_DEFERral.DEFERRED, { transaction: t }); // SET CONSTRAINTS ALL DEFERRED
// insert rows that reference each other, in any order
});POSTGRES.CONSTRAINT_DEFERral.IMMEDIATESET CONSTRAINTS ALL IMMEDIATE) checks them at once. The constraints must haveDEFERRABLE; see Indexes & constraints.