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