QueryInterface is the imperative schema API: create and alter tables, manageconst qi = prorm.getQueryInterface();QueryInterfaceOptions:| Option | Effect |
|---|---|
transaction | Run inside a transaction — thread this through a migration so a failure rolls the whole thing back. |
logging | Per-call logging override (false, true, or a function). |
benchmark | Report elapsed time. |
module.exports = {
async up(queryInterface, DataTypes) {
await queryInterface.createTable('users', {
id: { type: DataTypes.INTEGER(), primaryKey: true, autoIncrement: true },
email: { type: DataTypes.STRING(255), allowNull: false, unique: true },
createdAt: { type: DataTypes.DATE(), allowNull: false },
});
await queryInterface.addIndex('users', ['email'], { name: 'idx_users_email', unique: true });
},
async down(queryInterface) {
await queryInterface.removeIndex('users', 'idx_users_email');
await queryInterface.dropTable('users');
},
};order_items join table of the shop schema, with aCHECK, aimport { DataTypes, Op } from 'ts-prorm-orm';
import type { CreateQueryInterface } from 'ts-prorm-orm';
export async function up(qi: CreateQueryInterface): Promise<void> {
await qi.createTable('order_items', {
id: { type: DataTypes.INTEGER(), primaryKey: true, autoIncrement: true },
orderId: {
type: DataTypes.INTEGER(),
allowNull: false,
references: { model: 'orders', key: 'id', onDelete: 'CASCADE' },
},
productId: { type: DataTypes.INTEGER(), allowNull: false },
quantity: { type: DataTypes.INTEGER(), allowNull: false, defaultValue: 1 },
unitPrice: { type: DataTypes.DECIMAL(10, 2), allowNull: false },
});
await qi.addConstraint('order_items', {
type: 'FOREIGN KEY',
name: 'fk_items_product',
fields: ['productId'],
references: { table: 'products', fields: ['id'] },
onDelete: 'RESTRICT',
});
await qi.addConstraint('order_items', {
type: 'CHECK',
name: 'chk_items_quantity',
check: { quantity: { [Op.gt]: 0 } },
});
await qi.addConstraint('order_items', {
type: 'UNIQUE',
name: 'uq_items_order_product',
fields: ['orderId', 'productId'],
});
await qi.addIndex('order_items', ['productId'], { name: 'idx_items_product' });
}
export async function down(qi: CreateQueryInterface): Promise<void> {
await qi.dropTable('order_items');
}addConstraint() handles each type differently:type | On SQLite |
|---|---|
'UNIQUE' | Emulated with CREATE UNIQUE INDEX IF NOT EXISTS, which enforces the same rule. |
'PRIMARY KEY', 'FOREIGN KEY', 'CHECK' | Returns without doing anything. |
[!WARNING]
AFOREIGN KEYorCHECKadded withaddConstraint()does not exist on
SQLite, and no error says so. If SQLite is a target — including as the test
database for a PostgreSQL app — declare foreign keys increateTable()
(references, asorderIddoes above) and put checks in the model, so the
rule exists everywhere.
| Call | PostgreSQL | MySQL | SQLite | SQL Server |
|---|---|---|---|---|
createEnum('order_status', [...]) | CREATE TYPE … AS ENUM | throws: declare ENUM on the column | throws: use a CHECK | throws: use a CHECK |
createSequence('invoice_no', { start: 1000 }) | CREATE SEQUENCE … START WITH 1000 | throws: use AUTO_INCREMENT | throws: use AUTOINCREMENT | CREATE SEQUENCE … START WITH 1000 |
commentOnColumn('orders', 'total', '…') | COMMENT ON COLUMN | throws: pass comment to changeColumn() | throws | throws |
addIndex(…, { where: { status: 'pending' } }) | partial index | throws: use a generated column | partial index | filtered index |
analyze('orders') | ANALYZE "orders" | ANALYZE TABLE `orders` | ANALYZE "orders" | UPDATE STATISTICS [orders] |
await qi.addIndex('orders', ['userId'], {
name: 'idx_open_orders',
unique: true,
where: { status: 'pending' },
});MySQL does not support partial/filtered indexes (CREATE INDEX ... WHERE ...). This is a
PostgreSQL/SQL Server/SQLite-only feature. Consider a generated column plus a regular
index, or a CHECK constraint, as a workaround.renameColumn copies the columnrenameColumn() does not issue RENAME COLUMN. It reads the column'sdescribeTable(), then adds the new column, copies the dataawait qi.renameColumn('orders', 'total', 'amount');[!CAUTION]
ThatUPDATErewrites every row, and whatever hung off the old column — its
indexes, constraints, comments and any view that selects it — goes with theDROP. On a large or busy table, write the engine's ownALTER TABLE … RENAME COLUMNthroughqi.query()instead, inside the
migration's transaction.
| Method | Does |
|---|---|
createTable(tableName, columns, options?) | Create a new table. |
dropTable(tableName, options?) | Drop a table. |
dropAllTables(options?) | Drop all tables (dialect-specific). |
renameTable(oldName, newName, options?) | Rename a table. |
describeTable(tableName) | Describe a table (get column information). |
tableExists(tableName) | Check if a table exists. |
showTables() | Show all tables in the database. |
getTableNames(schema?) | Get all table names with schema (for PostgreSQL, MySQL, etc.). |
createDatabase(databaseName, options?) | Create a database (for databases that support it). |
dropDatabase(databaseName, options?) | Drop a database (for databases that support it). |
| Method | Does |
|---|---|
addColumn(tableName, columnName, definition, options?) | Add a column to a table. |
removeColumn(tableName, columnName, options?) | Remove a column from a table. |
changeColumn(tableName, columnName, definition, options?) | Change a column definition. |
renameColumn(tableName, oldColumnName, newColumnName, options?) | Rename a column. |
| Method | Does |
|---|---|
addIndex(tableName, indexNameOrFields, fieldsOrOptions?, options?) | Add an index to a table. |
removeIndex(tableName, indexName, options?) | Remove an index from a table. |
showIndexes(tableName) | Show all indexes for a table. |
indexExists(tableName, indexName) | Check if an index exists on a table. |
createFullTextIndex(options) | Create a full-text index. |
| Method | Does |
|---|---|
addConstraint(tableName, constraintNameOrOptions, constraintOrOptions?, options?) | Add a constraint to a table. |
removeConstraint(tableName, constraintName, typeOrOptions?) | Remove a constraint from a table. |
getConstraints(tableName) | Get constraints for a table. |
getForeignKeysForTable(tableName) | Get foreign keys for a table. |
| Method | Does |
|---|---|
createView(viewName, definition, options?) | Create a database view. |
dropView(viewName, options?) | Drop a database view. |
showViews() | Show all views in the database. |
viewExists(viewName) | Check if a view exists. |
createMaterializedView(options) | Create a materialized view. |
dropMaterializedView(viewName, options?) | Drop a materialized view. |
refreshMaterializedView(viewName, options?) | Refresh a materialized view. |
showMaterializedViews() | Show all materialized views in the database. |
materializedViewExists(viewName) | Check if a materialized view exists. |
| Method | Does |
|---|---|
createTrigger(trigger) | Create a trigger. |
dropTrigger(name, table, options?) | Drop a trigger. |
createExternalFunction(options) | Register a function written in a language other than SQL. |
dropExternalFunction(name, options?) | Drop an external function. |
| Method | Does |
|---|---|
createSequence(name, options) | Create a sequence. |
dropSequence(name, options?) | Drop a sequence. |
setSequenceValue(sequence, value, isCalled = true) | Set a sequence's current value. |
restartSequence(sequence, value?) | Restart a sequence, optionally at a given value. |
nextSequenceValue(sequence) | Take the next value from a sequence, consuming it. |
| Method | Does |
|---|---|
createExtension(name, options?) | Install a database extension. |
dropExtension(name, options?) | Remove an extension. |
createEnum(name, values, options?) | Create a named enum type. |
addEnumValue(name, value, options?) | Add a value to an existing enum type. |
renameEnumValue(name, from, to) | Rename one member of an enum type, leaving the rows using it alone. |
dropEnum(name, options?) | Drop an enum type. |
createDomain(name, options) | Create a domain — a named type carrying its own constraints. |
dropDomain(name, options?) | Drop a domain. |
| Method | Does |
|---|---|
commentOnTable(tableName, comment) | Comment on a table. null removes the comment. |
commentOnColumn(tableName, column, comment) | Comment on a column. null removes the comment. |
| Method | Does |
|---|---|
enableRowLevelSecurity(table) | Enable row-level security on a table (PostgreSQL family). |
disableRowLevelSecurity(table) | Disable row-level security on a table (PostgreSQL family). |
createPolicy(options) | Create a row-level security policy. |
dropPolicy(name, table, options?) | Drop a row-level security policy. |
| Method | Does |
|---|---|
createPartitionedTable(tableName, columns, options?) | Create a partitioned table (PostgreSQL 10+). |
createPartition(options) | Create a partition for an existing partitioned table (PostgreSQL 10+). |
attachPartition(options) | Attach a partition to a partitioned table (PostgreSQL 11+). |
detachPartition(options) | Detach a partition from a partitioned table (PostgreSQL 11+). |
dropPartition(partitionName, options?) | Drop a partition (PostgreSQL 10+). |
| Method | Does |
|---|---|
analyze(tableName?, options?) | Refresh the planner's statistics. |
vacuum(tableName?, options?) | Reclaim storage occupied by dead rows. |
reindex(target, options?) | Rebuild indexes, which drift as rows are updated and deleted. |
optimizeTable(tableName) | Rebuild a table, defragmenting it and returning space. MySQL family. |
checkTable(tableName, level?) | Check a table for corruption. Returns whatever the engine reports. |
repairTable(tableName, options?) | Attempt an in-place repair of a corrupted table. MySQL family. |
checksumTable(tableName) | A checksum over a table's contents, for comparing two copies. |
cluster(tableName, index?) | Rewrite a table in the physical order of one index. PostgreSQL only. |
| Method | Does |
|---|---|
bulkInsert(tableName, records, options?) | Bulk insert records. |
bulkUpdate(tableName, values, where, options?) | Bulk update records. |
bulkDelete(tableName, where, options?) | Bulk delete records. |
bulkInsert sends oneINSERT per record:await qi.bulkInsert('products', [
{ sku: 'KB-01', name: 'Keyboard', price: 49 },
{ sku: 'MS-01', name: 'Mouse', price: 19.5 },
]);
await qi.bulkUpdate('products', { price: 45 }, { sku: 'KB-01' });
await qi.bulkDelete('products', { sku: { [Op.in]: ['OLD-1', 'OLD-2'] } });[!TIP]
For seeding thousands of rows, pass atransactionso the inserts commit
once, or use the model-level paths in
Bulk operations.
| Method | Does |
|---|---|
query(sql, options?) | Execute a raw query. |
query()qi.quoteIdentifier('user table'); // "user table" · `user table` · [user table]
qi.getDialect(); // the underlying Dialect
// Only for DDL with no method behind it — an engine-specific statement:
await qi.query('ALTER SYSTEM SET wal_compression = on');query() is the way to run DDL the interface has no method for while stayingcreateExtension('uuid-ossp'), an enum is createEnum(), a comment iscommentOnTable(), and a CHECK is a where object on addConstraint() —createQueryInterfaceimport { createQueryInterface } from 'ts-prorm-orm';
const qi = createQueryInterface(prorm.getDialectInstance()!);Prorm instance — in a test, or in