@navette-js/tables 0.0.0-stage → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +8 -2
- package/lib/index.d.ts +786 -0
- package/lib/index.js +1307 -0
- package/lib/query-builder.d.ts +302 -0
- package/lib/query-builder.js +875 -0
- package/package.json +50 -4
- package/views/asset.ejs +1 -0
- package/views/column-manager.ejs +146 -0
- package/views/index.ejs +791 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import type { ListQuery } from '@navette-js/database';
|
|
2
|
+
import { Block, Builder } from '@navette-js/forms/builder';
|
|
3
|
+
import { Component } from '@navette-js/schemas';
|
|
4
|
+
import type { FilterIndicator, FilterState, TableFilter, TableHost } from './index.ts';
|
|
5
|
+
/** Plafonds appliqués à l'arbre de règles reçu du navigateur. */
|
|
6
|
+
export declare const MAX_RULES = 100;
|
|
7
|
+
export declare const MAX_NESTING_DEPTH = 3;
|
|
8
|
+
/** Nombre maximal de valeurs d'une sélection multiple. */
|
|
9
|
+
export declare const MAX_LIST_VALUES = 100;
|
|
10
|
+
type Comparison = '=' | '!=' | '<' | '<=' | '>' | '>=';
|
|
11
|
+
type Key = string | number;
|
|
12
|
+
export type Condition = {
|
|
13
|
+
kind: 'like';
|
|
14
|
+
column: string;
|
|
15
|
+
pattern: string;
|
|
16
|
+
negate: boolean;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'compare';
|
|
19
|
+
column: string;
|
|
20
|
+
operator: Comparison;
|
|
21
|
+
value: string | number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'boolean';
|
|
24
|
+
column: string;
|
|
25
|
+
value: boolean;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'date' | 'month' | 'year';
|
|
28
|
+
column: string;
|
|
29
|
+
operator: Comparison;
|
|
30
|
+
value: string | number;
|
|
31
|
+
}
|
|
32
|
+
/** Valeur renseignée (ni nulle, ni chaîne vide), ou l'inverse. */
|
|
33
|
+
| {
|
|
34
|
+
kind: 'filled';
|
|
35
|
+
column: string;
|
|
36
|
+
negate: boolean;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'in';
|
|
39
|
+
column: string;
|
|
40
|
+
values: Key[];
|
|
41
|
+
negate: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Nombre d'enregistrements liés comparé à une valeur. */
|
|
44
|
+
| {
|
|
45
|
+
kind: 'relationCount';
|
|
46
|
+
relationship: string;
|
|
47
|
+
operator: Comparison;
|
|
48
|
+
value: number;
|
|
49
|
+
modify?: RelationshipQueryModifier;
|
|
50
|
+
}
|
|
51
|
+
/** Au moins un enregistrement lié (parmi `keys` si la liste est donnée), ou aucun (`negate`). */
|
|
52
|
+
| {
|
|
53
|
+
kind: 'related';
|
|
54
|
+
relationship: string;
|
|
55
|
+
keys: Key[] | null;
|
|
56
|
+
negate: boolean;
|
|
57
|
+
modify?: RelationshipQueryModifier;
|
|
58
|
+
};
|
|
59
|
+
/** `whereHas` : les conditions s'appliquent aux enregistrements liés par la relation. */
|
|
60
|
+
export type ConditionNode = Condition | {
|
|
61
|
+
or: ConditionNode[][];
|
|
62
|
+
} | {
|
|
63
|
+
relationship: string;
|
|
64
|
+
nodes: ConditionNode[];
|
|
65
|
+
modify?: RelationshipQueryModifier;
|
|
66
|
+
};
|
|
67
|
+
type Settings = Record<string, unknown>;
|
|
68
|
+
type Resolved = {
|
|
69
|
+
condition: Condition;
|
|
70
|
+
summary: string;
|
|
71
|
+
};
|
|
72
|
+
/** Opérateur d'une contrainte : son formulaire de réglages et sa traduction en condition. */
|
|
73
|
+
type Operator = {
|
|
74
|
+
name: string;
|
|
75
|
+
label: (inverse: boolean) => string;
|
|
76
|
+
/** Réglages par défaut (null : l'opérateur n'a pas de formulaire). */
|
|
77
|
+
defaults: () => Settings | null;
|
|
78
|
+
fields: () => Component[];
|
|
79
|
+
/** Null quand les réglages ne passent pas la validation du formulaire : la règle est alors sans effet, comme dans Filament. */
|
|
80
|
+
resolve: (settings: Settings, inverse: boolean, constraint: Constraint) => Resolved | null;
|
|
81
|
+
/** Condition posée sur la requête principale, même quand la contrainte vise une relation (opérateurs de RelationshipConstraint). */
|
|
82
|
+
onBaseQuery?: boolean;
|
|
83
|
+
};
|
|
84
|
+
/** Date (ou date et heure, avec `hasTime`) visée par les réglages d'un opérateur « après / avant ». */
|
|
85
|
+
export declare function resolveRuleDate(settings: Settings, now?: Date, hasTime?: boolean): string | null;
|
|
86
|
+
declare const OPERATORS: Record<'text' | 'number' | 'boolean' | 'date', Operator[]>;
|
|
87
|
+
type ConstraintType = keyof typeof OPERATORS | 'select' | 'relationship';
|
|
88
|
+
/** Modification de la requête des enregistrements liés (knex / objection), posée par l'application. */
|
|
89
|
+
export type RelationshipQueryModifier = (query: any) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Attribut filtrable par le constructeur de requêtes (port de Constraint). La colonne et la relation interrogées sont celles déclarées
|
|
92
|
+
* ici, jamais des valeurs du navigateur : celui-ci ne choisit qu'une contrainte (par son nom) et un opérateur de sa liste.
|
|
93
|
+
*/
|
|
94
|
+
export declare class Constraint {
|
|
95
|
+
readonly name: string;
|
|
96
|
+
readonly type: ConstraintType;
|
|
97
|
+
private _label;
|
|
98
|
+
private _attributeLabel;
|
|
99
|
+
private _icon;
|
|
100
|
+
private _column;
|
|
101
|
+
protected _relationship: string | null;
|
|
102
|
+
protected _modifyRelationshipQuery: RelationshipQueryModifier | null;
|
|
103
|
+
protected _nullable: boolean;
|
|
104
|
+
/** Modèle Objection interrogé (enregistrements de la table), pour les listes d'enregistrements liés. */
|
|
105
|
+
protected _model: any;
|
|
106
|
+
constructor(name: string, type: ConstraintType, icon: string);
|
|
107
|
+
label(label: string): this;
|
|
108
|
+
/** Nom de l'attribut dans les résumés des règles (par défaut, le libellé). */
|
|
109
|
+
attributeLabel(label: string | null): this;
|
|
110
|
+
icon(name: string): this;
|
|
111
|
+
/** Colonne (ou alias de la requête) interrogée quand elle diffère du nom. */
|
|
112
|
+
attribute(column: string): this;
|
|
113
|
+
/**
|
|
114
|
+
* La contrainte porte sur un attribut d'enregistrements liés (`whereHas`) : `relationship('author', 'name')` filtre sur le nom de
|
|
115
|
+
* l'auteur. La relation doit être déclarée par le modèle Objection (`relationMappings`).
|
|
116
|
+
*/
|
|
117
|
+
relationship(name: string, titleAttribute: string, modifyQueryUsing?: RelationshipQueryModifier | null): this;
|
|
118
|
+
modifyRelationshipQueryUsing(callback: RelationshipQueryModifier | null): this;
|
|
119
|
+
/** Ajoute l'opérateur « Is filled » / « Is blank » (port de `nullable()`). */
|
|
120
|
+
nullable(condition?: boolean): this;
|
|
121
|
+
isNullable(): boolean;
|
|
122
|
+
model(model: any): this;
|
|
123
|
+
getModel(): any;
|
|
124
|
+
getLabel(): string;
|
|
125
|
+
getAttributeLabel(): string;
|
|
126
|
+
getIcon(): string;
|
|
127
|
+
getColumn(): string;
|
|
128
|
+
/** Relation dont les enregistrements portent l'attribut, ou `null` pour une colonne de la table. */
|
|
129
|
+
getRelationshipName(): string | null;
|
|
130
|
+
getModifyRelationshipQueryUsing(): RelationshipQueryModifier | null;
|
|
131
|
+
getOperators(): Operator[];
|
|
132
|
+
/** `contains` ou `contains.inverse` → opérateur et sens ; null si la contrainte ne le déclare pas. */
|
|
133
|
+
parseOperator(value: unknown): {
|
|
134
|
+
operator: Operator;
|
|
135
|
+
inverse: boolean;
|
|
136
|
+
} | null;
|
|
137
|
+
getOperatorOptions(): [string, string][];
|
|
138
|
+
/** Noms de réglages connus de la contrainte, tous opérateurs confondus (un changement d'opérateur conserve les anciens, comme Filament). */
|
|
139
|
+
getSettingNames(): string[];
|
|
140
|
+
/** Réglages dont la valeur est une liste (sélection multiple). */
|
|
141
|
+
getListSettingNames(): string[];
|
|
142
|
+
getDefaultData(): Record<string, unknown>;
|
|
143
|
+
}
|
|
144
|
+
export declare class TextConstraint extends Constraint {
|
|
145
|
+
static make(name: string): TextConstraint;
|
|
146
|
+
}
|
|
147
|
+
export declare class NumberConstraint extends Constraint {
|
|
148
|
+
static make(name: string): NumberConstraint;
|
|
149
|
+
}
|
|
150
|
+
export declare class BooleanConstraint extends Constraint {
|
|
151
|
+
static make(name: string): BooleanConstraint;
|
|
152
|
+
}
|
|
153
|
+
/** Date ; avec `time()`, la date et l'heure (sélecteur date-heure, préréglages et unités à la minute ou à l'heure). */
|
|
154
|
+
export declare class DateConstraint extends Constraint {
|
|
155
|
+
private _time;
|
|
156
|
+
static make(name: string): DateConstraint;
|
|
157
|
+
time(condition?: boolean): this;
|
|
158
|
+
hasTime(): boolean;
|
|
159
|
+
getOperators(): Operator[];
|
|
160
|
+
}
|
|
161
|
+
/** Valeur choisie dans une liste fixe (port de SelectConstraint) ; `multiple()` : l'une des valeurs choisies. */
|
|
162
|
+
export declare class SelectConstraint extends Constraint {
|
|
163
|
+
private _options;
|
|
164
|
+
private _multiple;
|
|
165
|
+
private _searchable;
|
|
166
|
+
static make(name: string): SelectConstraint;
|
|
167
|
+
/** Options `[valeur, libellé]` ou `{ valeur: libellé }` ; seules ces valeurs filtrent. */
|
|
168
|
+
options(options: [string | number, string][] | Record<string, string>): this;
|
|
169
|
+
getOptions(): [string, string][];
|
|
170
|
+
multiple(condition?: boolean): this;
|
|
171
|
+
isMultiple(): boolean;
|
|
172
|
+
searchable(condition?: boolean): this;
|
|
173
|
+
getOperators(): Operator[];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Opérateur « Is » / « Contains » d'une RelationshipConstraint (port de IsRelatedToOperator) : les enregistrements liés sont choisis dans
|
|
177
|
+
* une liste tirée du modèle lié, par leur clé ; `titleAttribute` est la colonne affichée.
|
|
178
|
+
*/
|
|
179
|
+
export declare class IsRelatedToOperator {
|
|
180
|
+
private _titleAttribute;
|
|
181
|
+
private _multiple;
|
|
182
|
+
private _searchable;
|
|
183
|
+
private _preload;
|
|
184
|
+
private _optionsLimit;
|
|
185
|
+
private _modifyQuery;
|
|
186
|
+
static make(): IsRelatedToOperator;
|
|
187
|
+
titleAttribute(attribute: string | null): this;
|
|
188
|
+
getTitleAttribute(): string | null;
|
|
189
|
+
multiple(condition?: boolean): this;
|
|
190
|
+
isMultiple(): boolean;
|
|
191
|
+
searchable(condition?: boolean): this;
|
|
192
|
+
preload(condition?: boolean): this;
|
|
193
|
+
optionsLimit(limit: number): this;
|
|
194
|
+
modifyRelationshipQueryUsing(callback: RelationshipQueryModifier | null): this;
|
|
195
|
+
getModifyRelationshipQueryUsing(): RelationshipQueryModifier | null;
|
|
196
|
+
/** Opérateur du constructeur pour la contrainte donnée. */
|
|
197
|
+
toOperator(constraint: RelationshipConstraint): Operator;
|
|
198
|
+
getOptionsLimit(): number;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Enregistrements liés (port de RelationshipConstraint) : nombre minimal, maximal ou exact (`multiple()`), relation vide (`emptyable()`,
|
|
202
|
+
* par défaut avec `multiple()`), ou liés à des enregistrements choisis (`selectable(IsRelatedToOperator.make()…)`).
|
|
203
|
+
*/
|
|
204
|
+
export declare class RelationshipConstraint extends Constraint {
|
|
205
|
+
private _multiple;
|
|
206
|
+
private _emptyable;
|
|
207
|
+
private _selectable;
|
|
208
|
+
/** Libellés des enregistrements liés cités par les règles, chargés avant le calcul des indicateurs. */
|
|
209
|
+
private _relatedLabels;
|
|
210
|
+
static make(name: string): RelationshipConstraint;
|
|
211
|
+
multiple(condition?: boolean): this;
|
|
212
|
+
isMultiple(): boolean;
|
|
213
|
+
emptyable(condition?: boolean | null): this;
|
|
214
|
+
canBeEmpty(): boolean;
|
|
215
|
+
selectable(operator: IsRelatedToOperator): this;
|
|
216
|
+
getSelectableOperator(): IsRelatedToOperator | null;
|
|
217
|
+
/** Relation interrogée : celle de `relationship()`, sinon `attribute()`, sinon le nom de la contrainte. */
|
|
218
|
+
getRelationshipName(): string;
|
|
219
|
+
getOperators(): Operator[];
|
|
220
|
+
getRelatedLabel(key: Key): string | null;
|
|
221
|
+
/** Modèle lié, retrouvé par la relation du modèle de la table (déclaré, ou celui de l'adaptateur Objection de l'hôte). */
|
|
222
|
+
private relatedModel;
|
|
223
|
+
private relatedQuery;
|
|
224
|
+
/** Options de la liste : enregistrements du modèle lié, triés par leur titre. */
|
|
225
|
+
loadRelatedOptions(operator: IsRelatedToOperator, host: unknown): Promise<[string, string][]>;
|
|
226
|
+
/** Charge les libellés des clés citées par des règles (indicateurs « Author is Ada or Linus »). */
|
|
227
|
+
loadRelatedLabels(keys: Key[], host: unknown): Promise<void>;
|
|
228
|
+
}
|
|
229
|
+
type Rule = {
|
|
230
|
+
type: string;
|
|
231
|
+
data: Record<string, any>;
|
|
232
|
+
};
|
|
233
|
+
type Rules = Record<string, Rule>;
|
|
234
|
+
/**
|
|
235
|
+
* Arbre de règles reçu du navigateur → arbre ne contenant que ce que le filtre déclare : types de blocs connus, opérateurs de la contrainte,
|
|
236
|
+
* réglages scalaires aux noms connus, profondeur et nombre de règles bornés. Un opérateur inconnu est remis à vide (règle sans effet).
|
|
237
|
+
*/
|
|
238
|
+
export declare function sanitizeRules(constraints: Constraint[], raw: unknown, depth?: number, budget?: {
|
|
239
|
+
rules: number;
|
|
240
|
+
}): Rules;
|
|
241
|
+
/** Règles nettoyées → conditions et libellés d'indicateurs (une entrée par règle de premier niveau qui a un effet). */
|
|
242
|
+
export declare function compileRules(constraints: Constraint[], rules: Rules, iteration?: number): {
|
|
243
|
+
nodes: ConditionNode[];
|
|
244
|
+
summaries: Record<string, string>;
|
|
245
|
+
};
|
|
246
|
+
/** Famille de SQL de la connexion knex de la requête. */
|
|
247
|
+
export type SqlDialect = 'sqlite' | 'mysql' | 'pg' | 'mssql';
|
|
248
|
+
/** Dialecte lu dans le client knex (`query.client.config.client`, ou celui de la connexion du modèle Objection) ; SQLite par défaut. */
|
|
249
|
+
export declare function sqlDialectOf(query: any): SqlDialect;
|
|
250
|
+
/**
|
|
251
|
+
* Applique des conditions à une requête knex / objection. Colonnes passées en identifiants, valeurs en paramètres liés ; les opérateurs
|
|
252
|
+
* de comparaison viennent d'une liste fermée. Le SQL de date et de recherche suit le dialecte de la connexion.
|
|
253
|
+
*/
|
|
254
|
+
export declare function applyConditions(query: any, nodes: ConditionNode[], dialect?: SqlDialect): void;
|
|
255
|
+
/** Constructeur de règles (port de RuleBuilder) : un Builder dont les blocs sont les contraintes du filtre, plus le bloc « OR ». */
|
|
256
|
+
export declare class RuleBuilder extends Builder {
|
|
257
|
+
readonly filter: QueryBuilder;
|
|
258
|
+
readonly depth: number;
|
|
259
|
+
constructor(name: string, filter: QueryBuilder, depth?: number);
|
|
260
|
+
/** Le bloc « OR » n'est plus proposé (ni accepté) quand il dépasserait la profondeur autorisée ; rien ne l'est une fois le plafond de règles atteint. */
|
|
261
|
+
getBlockPickerBlocks(): Block[];
|
|
262
|
+
getBlock(name: unknown): Block | undefined;
|
|
263
|
+
protected canAdd(): boolean;
|
|
264
|
+
/** Nombre de règles de l'arbre entier (les blocs « OR » ne comptent pas), lu dans l'état différé de l'hôte. */
|
|
265
|
+
isAtRuleLimit(): boolean;
|
|
266
|
+
/** Action de composant sans modale (utilisée aussi par les groupes « OR »). */
|
|
267
|
+
makeAction(name: string, handler: (args: Record<string, unknown>) => void): any;
|
|
268
|
+
}
|
|
269
|
+
/** Filtre « constructeur de requêtes » d'une table. */
|
|
270
|
+
export declare class QueryBuilder implements TableFilter {
|
|
271
|
+
readonly name = "queryBuilder";
|
|
272
|
+
private _constraints;
|
|
273
|
+
private _pickerColumns;
|
|
274
|
+
private _model;
|
|
275
|
+
static make(): QueryBuilder;
|
|
276
|
+
constraints(constraints: Constraint[]): this;
|
|
277
|
+
/** Modèle Objection de la table, transmis aux contraintes de relation (listes d'enregistrements liés). */
|
|
278
|
+
model(model: any): this;
|
|
279
|
+
/** Avant les indicateurs : charge les libellés des enregistrements liés que citent les règles (`RelationshipConstraint.selectable`). */
|
|
280
|
+
loadIndicatorData(state: FilterState, host: TableHost): Promise<void>;
|
|
281
|
+
constraintPickerColumns(columns?: number | null): this;
|
|
282
|
+
getConstraints(): Constraint[];
|
|
283
|
+
getConstraintPickerColumns(): number | null;
|
|
284
|
+
getLabel(): string;
|
|
285
|
+
getDefaultState(): FilterState;
|
|
286
|
+
getFormDefinition(): {
|
|
287
|
+
placeholder: string;
|
|
288
|
+
options: [string, string][];
|
|
289
|
+
};
|
|
290
|
+
/** Le filtre occupe toute la largeur du formulaire des filtres. */
|
|
291
|
+
getColumnSpan(): Record<string, number | string>;
|
|
292
|
+
getFormComponents(): Component[];
|
|
293
|
+
sanitizeState(state: unknown): FilterState;
|
|
294
|
+
countRules(state: unknown): number;
|
|
295
|
+
private compile;
|
|
296
|
+
isActive(state: FilterState): boolean;
|
|
297
|
+
getIndicators(state: FilterState): FilterIndicator[];
|
|
298
|
+
/** Retrait d'un indicateur : la règle de premier niveau correspondante disparaît. */
|
|
299
|
+
removeIndicator(state: FilterState, field: string): FilterState;
|
|
300
|
+
apply(query: Omit<ListQuery, 'page' | 'perPage'>, state: FilterState): void;
|
|
301
|
+
}
|
|
302
|
+
export {};
|