Aller au contenu principal

Requêtes

Lire​

Les méthodes de lecture sont statiques et renvoient des instances du modèle :

const users = await User.findAll();
const active = await User.findAllBy({active: true});
const user = await User.findOneById(1);
const alice = await User.findOneBy({email: 'alice@example.com'});
const total = await User.count();
const actives = await User.countBy({active: true});
  • findAll(options?) : toutes les lignes.
  • findAllBy(where, options?) : les lignes qui correspondent aux conditions. search() est un alias.
  • findOneBy(where) : la première ligne qui correspond, ou undefined.
  • findOneById(id) : la ligne d'identifiant id, ou undefined.
  • count() et countBy(where) : le nombre de lignes.
  • new() : une nouvelle instance vide du modèle, équivalent de new User().

Conditions​

Une condition associe une colonne à une valeur (égalité) ou à un couple [opérateur, valeur] :

await User.findAllBy({
active: true,
name: ['LIKE', 'A%'],
id: ['IN', [1, 2, 3]],
email: ['IS NOT NULL'],
});

Opérateurs disponibles : =, >, <, >=, <=, LIKE, NOT LIKE, IN, NOT IN, ainsi que IS NULL et IS NOT NULL, qui s'écrivent sans valeur. Toutes les conditions sont combinées avec AND.

Options​

findAll() et findAllBy() acceptent des options de pagination et de tri :

await User.findAll({
limit: 20,
offset: 40,
orderBy: {name: 'asc', createdAt: ['desc', 'last']},
});

Le tri prend 'asc' ou 'desc', ou un couple [ordre, nulls] pour placer les valeurs nulles en premier ('first') ou en dernier ('last').

Créer, modifier, supprimer​

const user = User.new().setName('Alice').setEmail('alice@example.com');

const created = await user.create(); // insère, puis relit la ligne
await created?.setName('Alice B.').update();
await created?.createOrUpdate(); // update() si getId() est défini, create() sinon
await created?.delete(); // true si la requête a réussi
  • create() et update() renvoient la ligne relue depuis la base.
  • update() et delete() ciblent la ligne dont l'id vaut getId().

Erreurs​

Les méthodes de requête ne lèvent pas d'erreur quand une requête SQL échoue : l'erreur est écrite dans les logs, préfixée par [ORM] et le nom de la table, et la promesse se résout avec undefined. Vérifiez donc le résultat :

const user = await User.findOneById(1);
if (!user) {
// introuvable, ou requête en échec (voir les logs)
}

Requêtes personnalisées​

Pour tout ce que les méthodes ne couvrent pas, KnexInstance.get() donne accès à Knex. Rangez ces requêtes dans des méthodes statiques du modèle :

import {KnexInstance, QueryRow, Table} from '@fca.gg/orm';

@Table('users')
export class User extends QueryRow {
// ... colonnes ...

public static async countSignupsSince(date: Date): Promise<number> {
const [row] = await KnexInstance.get()('users').where('created_at', '>=', date).count('* as count');
return Number(row.count);
}
}

C'est aussi le moyen d'utiliser une transaction, que l'ORM ne gère pas encore lui-même :

await KnexInstance.get().transaction(async (trx) => {
await trx('users').where('id', 1).update({active: false});
await trx('posts').where('user_id', 1).delete();
});

Les méthodes du modèle (create(), update()…) n'acceptent pas de transaction : dans une transaction, écrivez les requêtes avec trx.