Knex
Knex est un query-builder : il permet de réaliser des requêtes vers une base de données en Javascript de façon normalisée et sûre.
- knex abstrait les petites différences entre les dialectes SQL
- knex “sanitize” les requêtes, protégeant contre les attaques par injection SQL
- knex fournit un service de migration pour gérer les évolutions de la structure des données d’un projet
Installation
cd project
npm init
npm i knex sqlite3 pg
Initialisation
npx knex init
Créé un fichier de configuration knexfile.js. Par défaut il fait référence à une base de données sqlite3 ; il faut l’éditer pour choisir un autre SGBD, un autre nom de base de données, etc.
Migrations
Knex a un système de migrations complet qui permet de gérer :
- la création initiale des tables et de leur structure
- la gestion des modifications ultérieures de structure
- la gestion des ajouts de données (seed)
Migration initiale de création des tables
npx knex migrate:make migration_initiale
Un répertoire migrations est créé contenant un fichier <date>_migration_initiale.js. Il faut l’éditer avec la description de la structure des tables :
exports.up = function(knex) {
return knex.schema
.createTable('users', table => {
table.increments('id').unsigned().primary()
table.string('email').unique().notNullable()
table.string('password')
table.timestamp('created_at').defaultTo(knex.fn.now())
table.string('fullname').notNull()
})
.createTable('pictures', table => {
table.increments('id').unsigned().primary()
table.integer('user_id').references('id').inTable('users').notNull().onDelete('cascade')
table.timestamp('created_at').defaultTo(knex.fn.now())
table.string('path').notNull()
})
}
exports.down = function(knex) {
return knex.schema
.dropTable('users')
.dropTable('pictures')
}
La partie up doit réaliser la mise à jour souhaitée (ici la création de deux tables) ; la partie down doit défaire ce qu’à fait la partie up, au cas ou on souhaiterait ‘défaire’ une migration.
Application de la migration :
npx knex migrate:latest
Un fichier de base de données sqlite3 est créé dans le répertoire courant, avec les deux tables users et pictures.
Ajout d’une migration de structure
On souhaite ajouter une colonne à users et un index à pictures :
npx knex migrate:make add_role_index_path
Un fichier vide migrations/<date>_add_role_index_path.js est créé, qu’il faut éditer :
exports.up = function(knex) {
return knex.schema
.table('users', table => {
table.enum('role', ['user', 'admin']).notNull()
})
.table('pictures', table => {
table.index([ 'path' ])
})
}
exports.down = function(knex) {
return knex.schema
.table('users', table => {
table.dropColumn('role')
})
.table('pictures', table => {
table.dropIndex([ 'path' ])
})
}
Application de la migration :
npx knex migrate:latest
Accès programmatique à la base de données avec knex
Pour un accès à la base de données en javascript, à un niveau proche du SQL.
const knex = require('knex')
const config = require('./knexfile.js')
const database = knex(config.development)
async function main() {
const [{ id: jcId }] = await database
.into('users')
.insert({email: 'jc@n7.fr', fullname: "JCB", role: 'admin'}, 'id')
console.log('jcId', jcId)
await database
.into('users')
.update({email: "jc@mail.fr"})
.where({id: jcId})
const [user] = await database
.select('*')
.from('users')
.where({id: jcId})
console.log('user', user)
process.exit(0)
}
main()
Sanitizing
knex.raw('select * from foo where id = ?', [1]) // OK
knex.raw(`select * from foo where id = ${id}`) // Danger ! Injection SQL possible
