FFC Database Module
ffc-database is an npm module developed by DEFRA, providing a structured utility layer for database interactions within FFC services. It is built upon the Sequelize ORM, abstracting common setup and model loading patterns. The module simplifies connecting to SQL databases (e.g., PostgreSQL, as shown in examples) by taking a configuration object, dynamically loading Sequelize models from a specified filesystem path, and exposing the connected Sequelize instance and loaded models. The current stable version is 1.0.24. While specific release cadence is not provided, its versioning and association with government services suggest a focus on stability and compatibility within its ecosystem. Its key differentiator lies in its opinionated, service-centric wrapper around Sequelize, streamlining database access for specific internal FFC applications.
Common errors
-
SequelizeConnectionError: connect ECONNREFUSED
cause The database server is not running, is inaccessible from the host, or the connection parameters (host, port, username, password) are incorrect.fixVerify the database server is running and accessible. Double-check `host`, `port`, `username`, `password`, and `database` in your `config` object. Ensure no firewall rules are blocking the connection. -
Error: Cannot find module 'pg'
cause The necessary database driver (e.g., `pg` for PostgreSQL) is not installed as a dependency in your project.fixInstall the required database dialect package: `npm install --save pg` for PostgreSQL, `npm install --save mysql2` for MySQL, etc. -
TypeError: db.YourModelName.findAll is not a function
cause The model `YourModelName` was not correctly loaded or defined, possibly due to an incorrect `modelPath` or an error in the model's file structure.fixConfirm that `config.modelPath` points to the correct directory. Check the model file (`yourmodelname.js`) for syntax errors, ensure it exports a function, and that `sequelize.define` is correctly used within it.
Warnings
- gotcha The module's examples and internal structure primarily use CommonJS (`require`). Integrating into a pure ES module (ESM) Node.js project may require specific `package.json` configurations (`'type': 'commonjs'`) or transpilation to avoid `SyntaxError: Named export 'X' not found` or `require() of ES modules is not supported` errors.
- gotcha The `modelPath` configuration expects a filesystem path to a directory containing JavaScript files that define Sequelize models. These files must adhere to the `module.exports = (sequelize, DataTypes) => { ... }` pattern. Incorrect paths or malformed model files will prevent models from being loaded.
- gotcha The `sequelize.close()` method should be called when your application is shutting down to release database connections. Once called, the `sequelize` instance cannot re-establish connections, requiring a new instance if further database operations are needed.
Install
-
npm install ffc-database -
yarn add ffc-database -
pnpm add ffc-database
Imports
- Base
import Base from 'ffc-database'
const Base = require('ffc-database') - db.sequelize
const dbBase = new Base(config); const db = dbBase.connect(); // Access sequelize instance: db.sequelize.authenticate();
- db.ModelName
const dbBase = new Base(config); const db = dbBase.connect(); // Access models by their defined name (e.g., 'Payment'): await db.Payment.findAll();
Quickstart
const Base = require('ffc-database');
const config = {
dialect: 'postgres',
host: process.env.DB_HOST ?? 'localhost',
port: parseInt(process.env.DB_PORT ?? '5432', 10),
database: process.env.DB_NAME ?? 'ffc_pay',
username: process.env.DB_USER ?? 'ffc_user',
password: process.env.DB_PASSWORD ?? 'ffc_password',
modelPath: './models', // Assuming models directory exists in CWD
ssl: process.env.DB_SSL === 'true' ?? false,
logging: process.env.NODE_ENV !== 'production'
};
// Minimal model file example (./models/payment.js):
// module.exports = (sequelize, DataTypes) => {
// const Payment = sequelize.define('Payment', {
// amount: { type: DataTypes.DECIMAL },
// status: { type: DataTypes.STRING }
// });
// Payment.associate = (models) => {}; // Define associations here
// return Payment;
// };
async function runDbOperations() {
let dbBase;
let db;
try {
dbBase = new Base(config);
db = await dbBase.connect();
console.log('Database connected successfully.');
// Example: Run a raw query
const [results, metadata] = await db.sequelize.query(
'SELECT 1 + 1 as solution;',
{ type: db.sequelize.QueryTypes.SELECT }
);
console.log('Query result:', results);
// Assuming a 'Payment' model exists and is defined in './models/payment.js'
// const payments = await db.Payment.findAll();
// console.log('Found payments:', payments);
} catch (error) {
console.error('Database operation failed:', error);
} finally {
if (db && db.sequelize) {
await db.sequelize.close();
console.log('Database connection closed.');
}
}
}
runDbOperations();