Gérez vos migrations DB avec Knex
Introduction
Avant de commencer, précisions que cet article est un sous-post de Les lives queries pour une application web réactive - Partie 1. Soyez certain d'avoir un serveur PostgreSQL en cours d'exécution sur votre ordinateur.
Knex.js est un constructeur de requêtes pour PostgreSQL, MSSQL, MySQL, MariaDB, SQLite3, Oracle et Amazon Redshift. C'est flexible, portable et fun à utiliser. Nous allons l'utiliser pour maintenir notre schéma de base de données.
Knex-migrate
garde un oeil sur vos changements de schémas et données, ce qui est très utile lors de migration de base de données. Knex-migrate
dispose de tous les fichiers et logs. Nous n'avons donc qu'à exécuter une commande et knex-migrate
prendra soin de construire tous les schémas et les entrées de données statiques dans la base de données.
Un avantage majeur est que nous pouvons cloner notre projet dans un nouvel environnement pour ensuite exécuter les scripts knex migrations. Knex prendra soin de tout le reste.
Démarrons donc avec notre création de schéma à l'aide de knex-migrate
. Nous devons être certain d'avoir knex
et knex-migrate
installés dans notre projet. Si pas, nous devons exécuter la commande suivante :
npm install knex knex-migrate
Lançons ensuite l'initialisation avec :
npx knex init
Cette commande a pour effet de générer le fichier knexfile.js
. C'est un fichier auto-généré par knex
, lequel inclus toutes les configurations pour se connecter à la base de données selon l'environnement tel que développement, recette, pré-production, production. J'ai mis à jour la section développement. Le fichier doit donc ressembler à ceci :
require('dotenv').config()
const { CLIENT, DATABASE, PG_USER, PASSWORD, HOST, PG_PORT } = process.env
module.exports = {
development: {
client: CLIENT,
connection: {
database: DATABASE,
user: PG_USER,
password: PASSWORD,
host: HOST,
port: PG_PORT,
},
migrations: {
directory: __dirname + '/db/migrations',
},
seeds: {
directory: __dirname + '/db/seeds',
},
},
staging: {
client: 'postgresql',
connection: {
database: 'my_db',
user: 'username',
password: 'password',
},
pool: {
min: 2,
max: 10,
},
migrations: {
tableName: 'knex_migrations',
},
},
production: {
client: 'postgresql',
connection: {
database: 'my_db',
user: 'username',
password: 'password',
},
pool: {
min: 2,
max: 10,
},
migrations: {
tableName: 'knex_migrations',
},
},
}
Voici également le fichier .env
faisant référence.
CLIENT=pg
PORT=8080
ROOT_DATABASE_URL=postgres://postgres:changeme@0.0.0.0/securify
DATABASE=securify
PG_USER=postgres
PASSWORD=changeme
HOST=0.0.0.0
PG_PORT=5432
Mettez à jour ces valeurs selon la configuration de votre base de données et de votre environnement. Suivant ce fichier de configuration, vous devez créer les dossiers migrations
et seeds
sous le dossier db
que vous devez également créer.
migrations
contiendra les fichiers déterminants notre schéma. seeds
contiendra les fichiers contenant nos données à mettre à jour dans la base de données.
A présent, pour utiliser la configuration de connexion avec knex
, nous devons créer le fichier knex.js
dans db
. Ce fichier exportera un module de connexions basé sur l'environnement.
const environment = process.env.NODE_ENV || 'development'
const config = require('../knexfile')[environment]
module.exports = require('knex')(config)
A présent, notre arborécense devrait ressemble à ceci :
- server
- db
- migrations
- seeds
knex.js
- src
- index.js
.env
knexfile.js
A ce stade, nous allons créer les tables dans notre base de données en utilisant knex-migrate
. Les données seront également insérées. Pour plus d'informations concernant knex schema
, rendez-vous sur : http://knexjs.org/#Schema
Afin de créer la migration de schéma, nous avons besoin de lancer la commande qui créera un fichier auto-généré sous la dossier migration avec un date timestamp dans le nom de fichier.
Par exemple : 20201031221921migrationcreate_table.js
Voici la commande en question :
knex migrate:make migration_create_table
Voici le fichier 20201031221921_migration_create_table.js
avec les détails du schéma attendu.
exports.up = function(knex) {
return knex.schema
.createTable('users', function(table) {
table.increments().primary()
table.string('name', 255).notNullable()
table.string('email', 255).notNullable()
table.string('password', 255).notNullable()
table
.boolean('account_verified')
.notNullable()
.defaultTo(false)
table.timestamp('created_at').defaultTo(knex.fn.now())
table.timestamp('updated_at').defaultTo(knex.fn.now())
})
.createTable('posts', function(table) {
table.increments().primary()
table.string('title', 255).notNullable()
table.string('body', 255).notNullable()
table.timestamp('created_at').defaultTo(knex.fn.now())
table.timestamp('updated_at').defaultTo(knex.fn.now())
table
.integer('user_id')
.references('id')
.inTable('users')
})
.createTable('comments', function(table) {
table.increments().primary()
table.string('comment', 255).notNullable()
table.timestamp('created_at').defaultTo(knex.fn.now())
table.timestamp('updated_at').defaultTo(knex.fn.now())
table
.integer('user_id')
.references('id')
.inTable('users')
table.string('user_name', 255).notNullable()
table
.integer('post_id')
.references('id')
.inTable('posts')
})
}
exports.down = function(knex) {
return knex.schema.dropTable('posts').dropTable('users').dropTable('comments')
}
Afin de mettre à jour ce schéma vers notre base de données PostgreSQL
, nous devons exécuter la commande suivante :
npx knex migrate:latest
Retournons dans PgAdmin
afin de voir que la commande knex-migrate
a correctement créé les tables en accord avec le schéma configuré.
Maintenant que nos tables sont prêtes, nous pouvons y insérer des données en utilisant seeds
. Nous allons créer deux fichier seeds ; un pour l'utilisateur et un autre pour le post. Voici les commandes et fichiers d'exemples créés.
npx knex seed:make 01_users
npx knex seed:make 02_posts
Contrairement à la commande migration
, ces commandes vont créer des fichiers auto-générés dans seeds
.
Dans notre cas : 01_users.js
et 02_posts.js
Une chose importante à retenir est que le nom des fichiers seeds
doivent démarrer avec un nombre incrémental. Plus de détails ici : http://knexjs.org/#Seeds-CLI.
Voici les fichiers seeds
d'exemple créés pour insérer des utilisateurs avec un blog lui étant associé.
exports.seed = function(knex) {
// Deletes ALL existing entries
return knex('users')
.del()
.then(function() {
// Inserts seed entries
return knex('users').insert([
{
id: 1,
name: 'Bertrand Deweer',
email: 'bertrand.deweer@gmail.com',
password: 'bertrand',
},
])
})
}
exports.seed = function(knex) {
// Deletes ALL existing entries
return knex('posts')
.del()
.then(function() {
// Inserts seed entries
return knex('posts').insert([
{
id: 1,
title: 'Sample blog',
body:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec elementum mi purus, dignissim faucibus lectus pulvinar vitae.',
user_id: 1,
},
])
})
}
J'utilise la fonction del()
afin de supprimer les entrées existantes. Vous pouvez supprimer cette instruction lors d'un script de mise à jour.
Lançons à présent la commande suivante pour exécuter les fichiers seeds :
npx knex seed:run
J'espère que cet article vous aura donné une idée de ce que pouvez faire avec knex-migrate
pour la construction de vos schémas et pour vous permettre de suivre leurs évolutions.
Merci!