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, ouundefined.findOneById(id): la ligne d'identifiantid, ouundefined.count()etcountBy(where): le nombre de lignes.new(): une nouvelle instance vide du modèle, équivalent denew 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()etupdate()renvoient la ligne relue depuis la base.update()etdelete()ciblent la ligne dont l'idvautgetId().
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.