# Les opérations de QueryBuilder, les filtres et le contrat de conducteur

> Inspectez les options DB et NEWDB, les résultats quoudés, les erreurs et les formes de filtre sans confondre un constructeur avec un pilote de données.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: fr
Content-SHA256: 9d1abc156cce639601141611d4cc5f19de1008f1b61362f146464f7bcc844744
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

Cette page couvre le QueryBuilder natif de `total5@0.0.19` (`querybuilder.js`). `DB()` renvoie un contrôleur de file. Chaque opération planifie un appel au pilote ; ajoutez filtres et callbacks de façon synchrone avant son exécution. `NEWDB(name, driver)` enregistre une connexion. `NEWDB(name)` la désenregistre. Il n'y a ni moteur de base de données implicite ni transaction dans cette file.

Le pilote d'exemple retourne les options reçues. Pour exécuter une opération de base de données, implémenter cette opération dans le pilote. [Question-constructeur Sqlite](/en/total5/query-builder-sqlite/).

| Opérations | Le pilote reçoit |
|---|---|
| `find/all(table)`, `read/one(table)`, `list(table)` | `exec`, `table` ; `read` définit `first:true`, `take:1` ; `list` vaut par défaut `take:100`, `skip:0` |
| `check(table)`, `count(table)` | `check` définit `first:1`, `take:1` ; le pilote définit la valeur du résultat |
| `insert/ins(table, data)` | `payload` |
| `update/modify/mod/upd(table, data, upsert)` | `payload`, `upsert` ; un résultat nul déclenche un second `insert` lorsque l'upsert est activé |
| `remove/rem(table)`, `truncate/clear(table)`, `drop(table)` | Le `exec` correspondant ; les opérations destructrices nécessitent la prise en charge du pilote |
| `scalar(table, type, key, key2)` | `scalar:{type,key,key2}` ; un `key` omis devient `*` |
| `command(table, name)` | `command:name` |
| `query(sql, params)` ou `query(connection, sql, params)` | Texte brut dans `query`, valeurs dans `params`, la table est vide ; la liaison SQL relève du pilote |

| Méthodes de requête | Options / comportement |
|---|---|
| `where(name, [comparer], value)`, `equal(object)`, `id(value)`, `userid(value)` | Raccourci d'égalité ; `==` devient `=`, `!=` devient `<>` ; les ID en tableau utilisent `in` |
| `in/notin(name, values, [idField])`, `between(name,a,b)`, `or(fn)` | Filtrent les enregistrements ; `or` regroupe les enregistrements ajoutés dans `fn(builder)` |
| `array(name,[comparer],value)` | Comparateur par défaut `&&` ; l'interprétation revient au pilote |
| `month/day/year/hour/minute(name,[comparer],value)` | Filtres par partie de date ; comparateur par défaut `=` |
| `search(name,value,[where])`, `contains(name)`, `empty(name)` | Filtrent les enregistrements ; la sémantique de correspondance revient au pilote |
| `query(fragment)`, `join(name,table,type,a,b)`, `permit(name,type,values,userid,required)` | Filtres propres au pilote ; les fragments bruts doivent venir de code d'application de confiance |
| `fields(csv)`, `returning(csv)` | Tableaux de noms de champs nettoyés, pas d'échappement SQL ni d'autorisation |
| `sort(name, descending)`, `gridsort(csv,[localized])` | Chaînes de tri ; `true` ou `desc` choisissent le décroissant |
| `take/limit(n)`, `skip(n)`, `page(page,limit)`, `paginate(page,limit,max)` | Décalages/limites ; `paginate` plafonne la limite, `page` non |
| `first()`, `primarykey(name)`, `schema(name)`, `language(value,prefix,skip)`, `debug()` | Métadonnées pour le pilote ; `first` déballe aussi un résultat tableau |
| `gridfilter(name,query,type,[key])`, `autoquery(query,schema,sort,max)` | Convertissent les paramètres de requête de grille en options. `autoquery` restreint les champs demandés et les clés de tri à son schéma déclaré |
| `gridfields(fields,allowed)` | Utilisez `fields()` avec votre propre liste de permis: c'est la façon testée de choisir les colonnes |
| `callback/pipe(fn)`, `promise()`, `done($,fn,param)` | Achèvement ; les promesses sont rejetées sur erreur du pilote |
| `data(fn)`, `fail(fn)`, `error/err(message,reverse)` | Hooks de succès/échec ; `error()` rejette les résultats vides, `reverse:true` rejette les résultats truthy (y compris un tableau vide) |
| `set(name)`, `nobind()` | Nomment le résultat en file, ou ne remplacent pas la sortie de la file |
| `insert(fn,param)` sur un builder d'update | Modifie la charge avant l'insert de repli d'un upsert |
| `audit($,message,type)` | Appelle `variables()` et `audit()` du contexte fourni après une réponse réussie du pilote |

Méthodes du contrôleur : `callback/pipe`, `promise`, `done`, `debug`, `language`, `load(connection, options)` et `exec(options, callback)`. `load` copie un sous-ensemble défini d'options sérialisées ; `exec` distribue les noms d'opération pris en charge. `next/free` sont des éléments internes du cycle de vie. Une file s'arrête après une erreur du pilote ; elle n'annule pas les écritures précédentes.

```js definitions/contract.js
NEWDB('contract', function(options, callback) {
	if (options.table === 'failure')
		return callback(new Error('driver failed'));
	if (options.table === 'empty')
		return callback(null, []);
	if (options.table === 'upsert') {
		MAIN.upsert.push(JSON.parse(JSON.stringify(options)));
		return callback(null, options.exec === 'update' ? 0 : options.payload);
	}
	if (options.exec === 'list')
		return callback(null, { items: [], count: 12 });
	callback(null, options.first ? [options] : options);
});
MAIN.upsert = [];
```

```js controllers/contract.js
exports.install = function() {
	ROUTE('GET /contract/', contract);
};

async function contract($) {
	try {
		var out = {};
		var methods = ['find', 'all', 'read', 'one', 'list', 'check', 'count', 'insert', 'ins', 'update', 'modify', 'mod', 'upd', 'remove', 'rem', 'truncate', 'clear', 'drop'];
		out.operations = {};
		for (var method of methods)
			out.operations[method] = await DB()[method]('contract/items', { name: 'Ann' }).promise();
		out.scalar = await DB().scalar('contract/items', 'sum', 'amount', 'group').promise();
		out.command = await DB().command('contract/items', 'vacuum').promise();
		out.raw = await DB().query('contract', 'SELECT ?', [7]).promise();
		out.filters = await DB().find('contract/items').id([1, 2]).userid({ id: 'u1' }).equal({ active: true }).where('age', '!=', 0).in('team', [{ id: 'a' }], 'id').notin('team', 'b').between('age', 18, 65).or(function(q) { q.where('role', 'a').where('role', 'b'); }).array('tags', ['x']).month('created', 1).day('created', 2).year('created', '>=', 2020).hour('created', 3).minute('created', 4).search('name', 'ann', 'beg').contains('email').empty('deleted').query('trusted_fragment').join('team', 'teams', 'left', 'a.id', 'b.id').permit('permissions', 'RW', ['team'], 'u1', false).promise();
		out.options = await DB().find('contract/items').fields('id, name').returning('id, name').sort('name', true).gridsort('id_asc').limit(5).skip(2).primarykey('uid').schema('public').language({ language: 'es' }, '_').debug().promise();
		out.page = await DB().list('contract/items').paginate('2', '500', 10).promise();
		out.grid = await DB().find('contract/items').autoquery({ fields: 'id,password', sort: 'password_desc,name_desc', page: '2', limit: '500', age: '>18' }, 'id:String,name:String,age:Number', 'id_asc', 10).promise();
		out.gridfields = await DB().find('contract/items').gridfields('id', 'id,name').promise();
		var queue = DB();
		queue.read('contract/items').set('one');
		queue.count('contract/items').set('count');
		queue.find('contract/items').nobind();
		out.queue = await queue.promise();
		var hooks = [];
		await DB().read('contract/empty').data(function(v) { hooks.push(v === null ? 'null' : 'value'); }).promise();
		try { await DB().read('contract/empty').error('missing').fail(function() { hooks.push('fail'); }).promise(); } catch (e) { out.missing = String(e); }
		try { await DB().find('contract/failure').promise(); } catch (e) { out.failure = String(e); }
		out.hooks = hooks;
		out.upsert = await DB().update('contract/upsert', { name: 'new' }, true).where('id', 7).insert(function(payload, role) { payload.role = role; }, 'member').promise();
		out.upsertCalls = MAIN.upsert;
		out.load = await DB().load('contract', { table: 'items', exec: 'find', take: 2, filter: [] }).promise();
		$.json(out);
	} catch (e) { $.invalid(e); }
}
```
