Knex.js Database Cleaner
knex-cleaner is a helper library designed to programmatically clear database tables for Knex.js-based applications, primarily used in testing environments. It provides functionalities to truncate or delete all tables (or a specified subset) within a given Knex database instance. It supports PostgreSQL, MySQL, and SQLite3 databases. The current stable version is 1.3.1, with its last release in 2020, primarily focusing on dependency updates and minor feature enhancements like handling schemas other than 'public' for PostgreSQL. Its key differentiation lies in its direct integration with Knex instances, offering granular control over the cleaning process, including the ability to ignore specific tables and reset identity counters for PostgreSQL. This makes it a suitable tool for ensuring a clean and consistent database state before or after running integration tests, abstracting away manual SQL commands for table clearing. While it can be used with Bookshelf.js, it operates directly on the underlying Knex instance.
Common errors
-
TypeError: knexCleaner is not a function
cause Attempting to call `knexCleaner()` directly instead of `knexCleaner.clean()` or an incorrect import for ESM.fixEnsure you are calling the `clean` method: `knexCleaner.clean(knex, options)`. If using ESM, `import knexCleaner from 'knex-cleaner';` then `knexCleaner.clean(...)`. -
Error: insert into "TableName" ("id", ...) values (...) - SQLITE_CONSTRAINT: UNIQUE constraint failed: TableName.idcause When using SQLite or similar, if `mode: 'delete'` is used, auto-incrementing IDs are not reset, leading to primary key collisions if new rows are inserted with the same ID range.fixFor SQLite, consider manually resetting the sequence or using a different cleaning strategy. For PostgreSQL, ensure `restartIdentity: true` is set in the options when `mode: 'delete'` is used. For databases where `TRUNCATE` resets IDs, use `mode: 'truncate'` if feasible. -
SQLITE_CONSTRAINT: FOREIGN KEY constraint failed
cause Attempting to `TRUNCATE` tables that have foreign key constraints referencing other tables, without the database being configured to cascade truncation (which most do not by default).fixSwitch the `mode` option to `'delete'`. While slower, `DELETE` statements typically handle foreign key constraints more gracefully. Alternatively, temporarily disable foreign key checks if your database supports it and you understand the implications (not recommended for production). Or, ensure your `ignoreTables` list includes tables with critical parent data.
Warnings
- gotcha When using PostgreSQL, `restartIdentity: true` should be enabled in the options to reset auto-incrementing primary key sequences. Failing to do so can lead to primary key constraint violations on subsequent inserts if the IDs are not manually managed.
- gotcha The `mode` option ('truncate' vs 'delete') behaves differently. 'truncate' is generally faster and resets auto-incrementing IDs in most databases (except SQLite), but may not work if tables have foreign key constraints referencing other tables without `CASCADE` actions. 'delete' is slower but more robust against foreign key constraints.
- deprecated This library has not seen significant feature development or major version updates since 2020. While it remains functional for its core purpose, compatibility with very recent Knex.js versions or advanced database features might not be fully tested or supported.
Install
-
npm install knex-cleaner -
yarn add knex-cleaner -
pnpm add knex-cleaner
Imports
- clean
import { clean } from 'knex-cleaner';import knexCleaner from 'knex-cleaner'; knexCleaner.clean(knex, options)
- knexCleaner
const { clean } = require('knex-cleaner');const knexCleaner = require('knex-cleaner'); - Knex.js instance
knexCleaner.clean(config);
import knexCleaner from 'knex-cleaner'; const knex = require('knex')(config); knexCleaner.clean(knex);
Quickstart
import knexCleaner from 'knex-cleaner';
import knex from 'knex'; // Assume knex is installed
const dbConfig = {
client: 'sqlite3',
connection: {
filename: './mydb_test.sqlite'
},
useNullAsDefault: true
};
const myKnexInstance = knex(dbConfig);
async function setupDatabase() {
// For SQLite, create a dummy table to ensure the database file exists
await myKnexInstance.schema.hasTable('users').then(exists => {
if (!exists) {
return myKnexInstance.schema.createTable('users', table => {
table.increments('id');
table.string('name');
table.string('email');
});
}
});
await myKnexInstance.schema.hasTable('products').then(exists => {
if (!exists) {
return myKnexInstance.schema.createTable('products', table => {
table.increments('id');
table.string('name');
table.decimal('price', 8, 2);
});
}
});
// Insert some data
await myKnexInstance('users').insert([{ name: 'Alice', email: 'alice@example.com' }]);
await myKnexInstance('products').insert([{ name: 'Widget', price: 19.99 }]);
console.log('Database initialized and populated.');
}
async function cleanAndVerify() {
await setupDatabase();
console.log('Tables before clean:', await myKnexInstance.raw("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"));
const options = {
mode: 'delete', // Or 'truncate' for faster clearing on supported DBs
restartIdentity: true, // Useful for PostgreSQL
ignoreTables: ['knex_migrations', 'knex_migrations_lock'] // Ignore Knex migration tables
};
try {
await knexCleaner.clean(myKnexInstance, options);
console.log('Database tables successfully cleaned!');
console.log('Users table count after clean:', (await myKnexInstance('users').count('id as count'))[0].count);
console.log('Products table count after clean:', (await myKnexInstance('products').count('id as count'))[0].count);
} catch (error) {
console.error('Error cleaning database:', error);
} finally {
await myKnexInstance.destroy();
}
}
cleanAndVerify();