@nodefony/drizzle 10.0.0-alpha.8 → 10.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/README.md +19 -19
- package/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/index.js +9 -6
- package/dist/nodefony/command/migrateShared.js +17 -1
- package/dist/nodefony/command/orm-generate.js +14 -10
- package/dist/nodefony/command/orm-migrate-baseline.js +5 -2
- package/dist/nodefony/command/orm-reset.js +1 -0
- package/dist/nodefony/config/defineModuleConfig.js +23 -7
- package/dist/nodefony/entity/userTable.js +4 -1
- package/dist/nodefony/registerStores.js +4 -28
- package/dist/nodefony/service/DrizzleService.js +42 -16
- package/dist/nodefony/src/DrizzleAuditStore.js +14 -2
- package/dist/nodefony/src/DrizzleIdempotencyStore.js +14 -2
- package/dist/nodefony/src/DrizzleTokenStore.js +13 -1
- package/dist/nodefony/src/DrizzleTotpSecretStore.js +13 -1
- package/dist/nodefony/src/DrizzleWebAuthnCredentialStore.js +13 -1
- package/dist/nodefony/src/DrizzleWebhookStore.js +13 -1
- package/dist/nodefony/src/SessionStorage.js +8 -0
- package/dist/nodefony/src/connectorTarget.js +1 -1
- package/dist/nodefony/src/frameworkConnector.js +29 -0
- package/dist/nodefony/src/memoryDatabase.js +13 -0
- package/dist/nodefony/src/migrator/DrizzleMigrator.js +3 -3
- package/dist/nodefony/src/migrator/adopt.js +1 -1
- package/dist/nodefony/src/migrator/appSchema.js +44 -1
- package/dist/nodefony/src/migrator/destructive.js +2 -3
- package/dist/nodefony/src/migrator/drivers/mysqlDriver.js +1 -1
- package/dist/nodefony/src/migrator/drivers/postgresDriver.js +1 -1
- package/dist/nodefony/src/migrator/drivers/sqliteDriver.js +1 -0
- package/dist/nodefony/src/migrator/explain.js +7 -10
- package/dist/nodefony/src/migrator/history.js +25 -2
- package/dist/nodefony/src/migrator/kit.js +41 -6
- package/dist/nodefony/src/migrator/paths.js +55 -1
- package/dist/nodefony/src/migrator/rebuildCopy.js +6 -6
- package/dist/nodefony/src/migrator/refusals.js +50 -1
- package/dist/nodefony/src/migrator/resolve.js +59 -9
- package/dist/nodefony/src/migrator/sources.js +13 -8
- package/dist/nodefony/src/orm-core/DrizzleOrm.js +51 -30
- package/dist/nodefony/src/orm-core/DrizzleRepository.js +38 -26
- package/dist/nodefony/src/queryKit.js +5 -5
- package/dist/nodefony/src/safeTarget.js +1 -0
- package/dist/types/nodefony/command/migrateShared.d.ts +10 -0
- package/dist/types/nodefony/config/defineModuleConfig.d.ts +5 -1
- package/dist/types/nodefony/entity/userTable.d.ts +46 -3
- package/dist/types/nodefony/registerStores.d.ts +4 -3
- package/dist/types/nodefony/src/DrizzleAuditStore.d.ts +6 -0
- package/dist/types/nodefony/src/DrizzleIdempotencyStore.d.ts +8 -1
- package/dist/types/nodefony/src/DrizzleTokenStore.d.ts +6 -0
- package/dist/types/nodefony/src/DrizzleTotpSecretStore.d.ts +6 -0
- package/dist/types/nodefony/src/DrizzleUserRepository.d.ts +1 -1
- package/dist/types/nodefony/src/DrizzleWebAuthnCredentialStore.d.ts +6 -0
- package/dist/types/nodefony/src/DrizzleWebhookStore.d.ts +6 -0
- package/dist/types/nodefony/src/SessionStorage.d.ts +6 -0
- package/dist/types/nodefony/src/connectorTarget.d.ts +1 -1
- package/dist/types/nodefony/src/frameworkConnector.d.ts +24 -0
- package/dist/types/nodefony/src/memoryDatabase.d.ts +10 -0
- package/dist/types/nodefony/src/migrator/DrizzleMigrator.d.ts +4 -4
- package/dist/types/nodefony/src/migrator/appSchema.d.ts +25 -0
- package/dist/types/nodefony/src/migrator/destructive.d.ts +1 -1
- package/dist/types/nodefony/src/migrator/drivers/index.d.ts +2 -2
- package/dist/types/nodefony/src/migrator/explain.d.ts +9 -9
- package/dist/types/nodefony/src/migrator/kit.d.ts +15 -0
- package/dist/types/nodefony/src/migrator/name.d.ts +1 -1
- package/dist/types/nodefony/src/migrator/paths.d.ts +35 -0
- package/dist/types/nodefony/src/migrator/refusals.d.ts +36 -1
- package/dist/types/nodefony/src/migrator/resolve.d.ts +44 -1
- package/dist/types/nodefony/src/migrator/types.d.ts +2 -2
- package/dist/types/nodefony/src/orm-core/DrizzleOrm.d.ts +13 -2
- package/dist/types/nodefony/src/orm-core/DrizzleRepository.d.ts +1 -1
- package/dist/types/nodefony/src/orm-core/ddlPlan.d.ts +2 -2
- package/dist/types/nodefony/src/queryKit.d.ts +9 -9
- package/dist/types/nodefony/src/safeTarget.d.ts +2 -2
- package/docs/index.md +31 -28
- package/docs/migrations.md +39 -3
- package/package.json +19 -20
|
@@ -108,15 +108,15 @@ export interface IMigrationEntryReport {
|
|
|
108
108
|
/** Où en est cette migration pour CE connecteur. */
|
|
109
109
|
status: "applied" | "pending" | "failed" | "drifted" | "missing";
|
|
110
110
|
/** Début de l'application, en millisecondes — absent si jamais appliquée. */
|
|
111
|
-
appliedAt?: number;
|
|
111
|
+
appliedAt?: number | undefined;
|
|
112
112
|
/** Durée de l'application, en millisecondes. */
|
|
113
|
-
durationMs?: number;
|
|
113
|
+
durationMs?: number | undefined;
|
|
114
114
|
/** Ce qui l'a appliquée, tel que l'historique l'a retenu. */
|
|
115
|
-
appliedBy?: string;
|
|
115
|
+
appliedBy?: string | undefined;
|
|
116
116
|
/** Déploiement qui l'a portée — groupe les migrations d'un même passage. */
|
|
117
|
-
runId?: string;
|
|
117
|
+
runId?: string | undefined;
|
|
118
118
|
/** Motif de l'échec, quand elle a échoué. */
|
|
119
|
-
error?: string;
|
|
119
|
+
error?: string | undefined;
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
122
122
|
* La charge utile figée — cœur NEUTRE au premier niveau, spécifique du pilote
|
|
@@ -155,7 +155,7 @@ export interface IMigrationReport {
|
|
|
155
155
|
* Son ABSENCE est un fait, pas un oubli : sur une base conforme, il n'y a
|
|
156
156
|
* rien à nommer.
|
|
157
157
|
*/
|
|
158
|
-
divergence?: ISchemaComparison;
|
|
158
|
+
divergence?: ISchemaComparison | undefined;
|
|
159
159
|
/**
|
|
160
160
|
* Ce que le passage a DÉTRUIT, nommé — présent au seul run réel qui a
|
|
161
161
|
* appliqué une migration destructive, absent partout ailleurs.
|
|
@@ -166,7 +166,7 @@ export interface IMigrationReport {
|
|
|
166
166
|
* octet de ce qu'il relit ne la mentionne. Son absence est un fait : rien
|
|
167
167
|
* n'a été détruit.
|
|
168
168
|
*/
|
|
169
|
-
destructive?: IDestructiveFinding[];
|
|
169
|
+
destructive?: IDestructiveFinding[] | undefined;
|
|
170
170
|
/** Tout ce qui est propre au pilote SQL vit ici, et nulle part ailleurs. */
|
|
171
171
|
driver: {
|
|
172
172
|
kind: "sql";
|
|
@@ -174,9 +174,9 @@ export interface IMigrationReport {
|
|
|
174
174
|
ddl: string;
|
|
175
175
|
historyTable: string;
|
|
176
176
|
/** La base visée, sans identifiant ni mot de passe. */
|
|
177
|
-
target?: string;
|
|
177
|
+
target?: string | undefined;
|
|
178
178
|
/** `true` quand la cible vient de `NF_MIGRATE_DATABASE_URL`. */
|
|
179
|
-
fromMigrateUrl?: boolean;
|
|
179
|
+
fromMigrateUrl?: boolean | undefined;
|
|
180
180
|
};
|
|
181
181
|
}
|
|
182
182
|
/** Grille des codes de sortie — **figée, jamais réaffectée**. */
|
|
@@ -129,6 +129,21 @@ export declare function auditMigrationSql(sql: string, dialect: SqlDialect): IMi
|
|
|
129
129
|
* @returns `true` si l'échec vient d'une question restée sans terminal.
|
|
130
130
|
*/
|
|
131
131
|
export declare function isInteractivePromptFailure(output: string): boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Reconnaît le refus de l'outil devant un `await` de premier niveau.
|
|
134
|
+
*
|
|
135
|
+
* C'est l'esbuild de `drizzle-kit` qui le détecte, en transpilant le fichier en
|
|
136
|
+
* CommonJS : sa ligne d'erreur nomme le fichier et la position. On la lit plutôt
|
|
137
|
+
* que d'analyser nous-mêmes les sources — l'outil qui refuse est aussi celui qui
|
|
138
|
+
* sait exactement où, sans faux positif. Fonction PURE, éprouvée sans process.
|
|
139
|
+
*
|
|
140
|
+
* @param output - sortie complète de l'outil.
|
|
141
|
+
* @returns le fichier et la ligne, ou `null` si l'échec est d'une autre nature.
|
|
142
|
+
*/
|
|
143
|
+
export declare function topLevelAwaitFailure(output: string): {
|
|
144
|
+
file: string;
|
|
145
|
+
line: number;
|
|
146
|
+
} | null;
|
|
132
147
|
/**
|
|
133
148
|
* Pose le marqueur de format en tête des `.sql` d'un dossier qui ne l'ont pas.
|
|
134
149
|
*
|
|
@@ -34,7 +34,7 @@ export type MigrationNameCheck = {
|
|
|
34
34
|
* geste qui échoue est pire que ne rien proposer, parce qu'il fait perdre
|
|
35
35
|
* un aller-retour ET la confiance dans les autres suggestions.
|
|
36
36
|
*/
|
|
37
|
-
suggestion?: string;
|
|
37
|
+
suggestion?: string | undefined;
|
|
38
38
|
};
|
|
39
39
|
/**
|
|
40
40
|
* Dérive un nom acceptable d'une saisie qui ne l'est pas.
|
|
@@ -12,6 +12,37 @@ export declare const FRAMEWORK_RANK = 0;
|
|
|
12
12
|
* celles des modules ; l'inverse n'arrive jamais.
|
|
13
13
|
*/
|
|
14
14
|
export declare const APP_RANK = 1000000;
|
|
15
|
+
/**
|
|
16
|
+
* Noms qui ne peuvent PAS désigner le dossier d'un connecteur secondaire : ce
|
|
17
|
+
* sont ceux des dossiers de dialecte (et du journal) que le connecteur du
|
|
18
|
+
* framework range déjà sous `migrations/`. Un connecteur `postgres` y lirait les
|
|
19
|
+
* migrations de `default` comme les siennes.
|
|
20
|
+
*/
|
|
21
|
+
export declare const RESERVED_MIGRATION_DIRS: readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* Le nom de ce connecteur collisionne-t-il avec un dossier de dialecte ?
|
|
24
|
+
*
|
|
25
|
+
* @param connector - nom du connecteur (clé de `connectors`).
|
|
26
|
+
* @returns `true` pour un connecteur SECONDAIRE nommé comme un dossier réservé.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isReservedConnectorName(connector: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Dossier des migrations PROPRES à un connecteur — la seule règle qui dit où
|
|
31
|
+
* elles vivent.
|
|
32
|
+
*
|
|
33
|
+
* Le connecteur du framework garde la racine (`migrations/<dialecte>`) : ses
|
|
34
|
+
* migrations décrivent la base du framework et des entités de l'application.
|
|
35
|
+
* Un connecteur secondaire reçoit son sous-dossier (`migrations/<connecteur>/
|
|
36
|
+
* <dialecte>`) : sa base ne reçoit que ce qui y est écrit, et celle du
|
|
37
|
+
* framework n'en voit rien — le dossier de dialecte qu'elle lit n'est pas le
|
|
38
|
+
* même.
|
|
39
|
+
*
|
|
40
|
+
* @param appDir - dossier de migrations de l'application (`appMigrationsDir`).
|
|
41
|
+
* @param connector - nom du connecteur.
|
|
42
|
+
* @returns le dossier parent des sous-dossiers de dialecte, ou `undefined` sans
|
|
43
|
+
* racine d'application, ou pour un nom réservé ({@link isReservedConnectorName}).
|
|
44
|
+
*/
|
|
45
|
+
export declare function connectorMigrationsDir(appDir: string | undefined, connector: string): string | undefined;
|
|
15
46
|
/**
|
|
16
47
|
* Dossier des migrations livrées par ce paquet.
|
|
17
48
|
*
|
|
@@ -47,8 +78,12 @@ export declare function frameworkMigrationsDir(): Promise<string>;
|
|
|
47
78
|
*
|
|
48
79
|
* @param appDir - dossier de migrations de l'application, s'il y en a un.
|
|
49
80
|
* @param options.framework - `false` quand le module est data-only.
|
|
81
|
+
* @param options.connector - connecteur visé ; un connecteur secondaire ne
|
|
82
|
+
* reçoit que SES migrations ({@link connectorMigrationsDir}), jamais celles
|
|
83
|
+
* du framework. Omis : le registre complet (usage direct).
|
|
50
84
|
* @returns le registre, prêt pour l'applicateur.
|
|
51
85
|
*/
|
|
52
86
|
export declare function defaultMigrationSources(appDir?: string, options?: {
|
|
53
87
|
framework?: boolean;
|
|
88
|
+
connector?: string;
|
|
54
89
|
}): Promise<IMigrationSource[]>;
|
|
@@ -37,6 +37,8 @@ export type CommandFailureCode =
|
|
|
37
37
|
| "NF_GENERATE_TOOL_MISSING"
|
|
38
38
|
/** L'outil de génération pose une question, et il n'y a pas de terminal. */
|
|
39
39
|
| "NF_GENERATE_NEEDS_ANSWER"
|
|
40
|
+
/** Un fichier d'entité porte un `await` de premier niveau, que l'outil ne sait pas lire. */
|
|
41
|
+
| "NF_GENERATE_TOP_LEVEL_AWAIT"
|
|
40
42
|
/** L'outil de génération s'est arrêté ; ce qu'il a dit est remonté tel quel. */
|
|
41
43
|
| "NF_GENERATE_TOOL_FAILED"
|
|
42
44
|
/** La lecture du schéma d'une base existante a échoué. */
|
|
@@ -46,7 +48,9 @@ export type CommandFailureCode =
|
|
|
46
48
|
/** L'adoption par lecture de la base, demandée alors qu'il existe déjà des migrations. */
|
|
47
49
|
| "NF_MIGRATE_BASELINE_NOT_EMPTY"
|
|
48
50
|
/** La table d'historique existe, mais ce n'est pas celle du framework. */
|
|
49
|
-
| "NF_MIGRATE_HISTORY_FOREIGN"
|
|
51
|
+
| "NF_MIGRATE_HISTORY_FOREIGN"
|
|
52
|
+
/** Écrire une migration pour un connecteur secondaire au nom réservé (`postgres`…). */
|
|
53
|
+
| "NF_MIGRATE_SECONDARY_CONNECTOR";
|
|
50
54
|
/**
|
|
51
55
|
* Ce que la découverte des entités a VU, au moment où la commande a refusé.
|
|
52
56
|
*
|
|
@@ -157,6 +161,22 @@ export declare function formatToolOutput(output: string, maxLines?: number): str
|
|
|
157
161
|
* @returns le refus, prêt pour la ligne de commande comme pour l'écran.
|
|
158
162
|
*/
|
|
159
163
|
export declare function generationNeedsAnswer(label: string, replay: string): IResolutionRefusal;
|
|
164
|
+
/**
|
|
165
|
+
* Un fichier lu par l'outil de génération porte un `await` de premier niveau.
|
|
166
|
+
*
|
|
167
|
+
* Nodefony est ESM, et l'application démarre très bien avec ce fichier. Mais
|
|
168
|
+
* l'outil qui écrit les migrations (`drizzle-kit`) relit les fichiers de schéma
|
|
169
|
+
* HORS de la chaîne de l'application, en les transpilant en CommonJS — où un
|
|
170
|
+
* `await` de premier niveau n'existe pas. Sans ce refus, l'utilisateur recevait
|
|
171
|
+
* une pile d'appels d'esbuild qui ne nomme ni l'outil ni le remède.
|
|
172
|
+
*
|
|
173
|
+
* @param label - ce qui était généré, tel qu'on le cite à l'utilisateur.
|
|
174
|
+
* @param file - fichier fautif, tel que l'outil l'a nommé.
|
|
175
|
+
* @param line - ligne de l'`await`.
|
|
176
|
+
* @param replay - la commande à relancer une fois le fichier corrigé.
|
|
177
|
+
* @returns le refus, prêt pour la ligne de commande comme pour l'écran.
|
|
178
|
+
*/
|
|
179
|
+
export declare function generationTopLevelAwait(label: string, file: string, line: number, replay: string): IResolutionRefusal;
|
|
160
180
|
/**
|
|
161
181
|
* L'outil de génération s'est arrêté, et ce qu'il a dit est remonté TEL QUEL.
|
|
162
182
|
*
|
|
@@ -218,6 +238,21 @@ export declare function moduleAbsent(): IResolutionRefusal;
|
|
|
218
238
|
* @returns le refus, prêt pour la ligne de commande comme pour l'écran.
|
|
219
239
|
*/
|
|
220
240
|
export declare function notConfigured(connector: string, driver: string): IResolutionRefusal;
|
|
241
|
+
/**
|
|
242
|
+
* Écrire une migration pour un connecteur secondaire dont le NOM est celui d'un
|
|
243
|
+
* dossier de dialecte — refusé.
|
|
244
|
+
*
|
|
245
|
+
* Un connecteur secondaire range ses migrations sous `migrations/<connecteur>/`,
|
|
246
|
+
* à côté des dossiers de dialecte du connecteur du framework. Nommé `postgres`,
|
|
247
|
+
* son dossier SERAIT celui des migrations PostgreSQL du framework : il les
|
|
248
|
+
* lirait comme les siennes, et les siennes seraient appliquées à la base du
|
|
249
|
+
* framework. On le refuse en nommant la collision, plutôt que de le découvrir
|
|
250
|
+
* au premier déploiement.
|
|
251
|
+
*
|
|
252
|
+
* @param connector - connecteur demandé.
|
|
253
|
+
* @returns le refus, prêt pour la ligne de commande comme pour l'écran.
|
|
254
|
+
*/
|
|
255
|
+
export declare function reservedConnectorName(connector: string): IResolutionRefusal;
|
|
221
256
|
/**
|
|
222
257
|
* Traduit une résolution qui n'est PAS `ready` en refus lisible.
|
|
223
258
|
*
|
|
@@ -67,6 +67,8 @@ export declare function resetAllowed(env: IMigrationEnv): boolean;
|
|
|
67
67
|
* @returns `true` si l'enchaînement est recevable.
|
|
68
68
|
*/
|
|
69
69
|
export declare function generateApplyAllowed(env: IMigrationEnv): boolean;
|
|
70
|
+
import { MEMORY_DATABASE } from "../memoryDatabase.js";
|
|
71
|
+
export { MEMORY_DATABASE };
|
|
70
72
|
/**
|
|
71
73
|
* Le mode de schéma qui s'applique à un connecteur.
|
|
72
74
|
*
|
|
@@ -99,10 +101,18 @@ export declare function generateApplyAllowed(env: IMigrationEnv): boolean;
|
|
|
99
101
|
*
|
|
100
102
|
* @param explicit - valeur écrite dans la configuration du connecteur, si elle l'est.
|
|
101
103
|
* @param env - environnement constaté.
|
|
104
|
+
* 🔴 **Une base VOLATILE (`:memory:`) dérive toujours son schéma**, en
|
|
105
|
+
* production comprise. Rien d'autre ne peut la peupler : elle repart vide à
|
|
106
|
+
* chaque démarrage, et une migration appliquée ne survit pas au processus. En
|
|
107
|
+
* `none`, elle restait vide, le verdict de schéma tombait à `divergent` et la
|
|
108
|
+
* sonde de disponibilité retenait la mise en service (vécu en CI : le connecteur
|
|
109
|
+
* d'un module de banc, ouvert en production sous dérogation).
|
|
110
|
+
*
|
|
102
111
|
* @param appHasMigrations - l'application versionne au moins une migration.
|
|
112
|
+
* @param volatile - la base est en mémoire (`:memory:`).
|
|
103
113
|
* @returns le mode effectif.
|
|
104
114
|
*/
|
|
105
|
-
export declare function resolveDdlMode(explicit: DdlMode | undefined, env: IMigrationEnv, appHasMigrations?: boolean): DdlMode;
|
|
115
|
+
export declare function resolveDdlMode(explicit: DdlMode | undefined, env: IMigrationEnv, appHasMigrations?: boolean, volatile?: boolean): DdlMode;
|
|
106
116
|
/**
|
|
107
117
|
* L'application versionne-t-elle au moins une migration ?
|
|
108
118
|
*
|
|
@@ -120,6 +130,21 @@ export declare function resolveDdlMode(explicit: DdlMode | undefined, env: IMigr
|
|
|
120
130
|
* ou sous un sous-dossier de dialecte (`migrations/postgres/0001_x.sql`).
|
|
121
131
|
*/
|
|
122
132
|
export declare function appVersionsMigrations(dir: string | undefined): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Des migrations versionnées CONCERNENT-elles ce connecteur ?
|
|
135
|
+
*
|
|
136
|
+
* C'est la question que pose la bascule `auto` → `migrate`, et elle n'est pas
|
|
137
|
+
* « l'application versionne-t-elle des migrations ? » : celles de la racine
|
|
138
|
+
* décrivent la base du framework. Posée telle quelle, elle faisait basculer en
|
|
139
|
+
* `migrate` un connecteur secondaire qui n'en recevra jamais une — sa base
|
|
140
|
+
* restait alors sans schéma, ni dérivé ni migré. On regarde donc le dossier
|
|
141
|
+
* DU connecteur ({@link connectorMigrationsDir}).
|
|
142
|
+
*
|
|
143
|
+
* @param connector - nom du connecteur.
|
|
144
|
+
* @param dir - dossier de migrations de l'application ({@link appMigrationsDir}).
|
|
145
|
+
* @returns `true` si le dossier propre au connecteur porte au moins un `.sql`.
|
|
146
|
+
*/
|
|
147
|
+
export declare function connectorVersionsMigrations(connector: string, dir: string | undefined): boolean;
|
|
123
148
|
/**
|
|
124
149
|
* La conduite de la sonde de disponibilité face à un schéma en retard.
|
|
125
150
|
*
|
|
@@ -133,6 +158,24 @@ export declare function appVersionsMigrations(dir: string | undefined): boolean;
|
|
|
133
158
|
* @returns la conduite effective.
|
|
134
159
|
*/
|
|
135
160
|
export declare function resolveCheckMode(explicit: MigrationCheckMode | undefined, env: IMigrationEnv): MigrationCheckMode;
|
|
161
|
+
/**
|
|
162
|
+
* En schéma `auto`, faut-il ÉNONCER au démarrage les migrations enregistrées
|
|
163
|
+
* que personne n'a appliquées ?
|
|
164
|
+
*
|
|
165
|
+
* Oui en développement, sauf conduite `off` — c'est ce conseil qui évite de
|
|
166
|
+
* conclure à une base incohérente devant une colonne inconnue. Jamais sur une
|
|
167
|
+
* base `:memory:` : elle repart VIDE à chaque démarrage, son historique aussi,
|
|
168
|
+
* si bien que tout y paraît « à appliquer » à chaque fois — un avertissement
|
|
169
|
+
* permanent qui n'apprend rien (vécu : le connecteur de banc `mediasoup`,
|
|
170
|
+
* une fois déclaré, réclamait à chaque démarrage les migrations du framework
|
|
171
|
+
* et de l'application, qui ne le concernent pas).
|
|
172
|
+
*
|
|
173
|
+
* @param check - conduite résolue ({@link resolveCheckMode}).
|
|
174
|
+
* @param env - environnement constaté.
|
|
175
|
+
* @param filename - fichier sqlite du connecteur, s'il en a un.
|
|
176
|
+
* @returns `true` si le conseil doit être rendu.
|
|
177
|
+
*/
|
|
178
|
+
export declare function adviseMigrations(check: MigrationCheckMode, env: IMigrationEnv, filename: string | undefined): boolean;
|
|
136
179
|
/** Ce qu'un connecteur est, du point de vue des migrations. */
|
|
137
180
|
export type IConnectorResolution = {
|
|
138
181
|
/** Le connecteur existe et son propriétaire sait migrer. */
|
|
@@ -98,9 +98,9 @@ export interface IMigrationVerdict {
|
|
|
98
98
|
/** Connecteur concerné. */
|
|
99
99
|
connector: string;
|
|
100
100
|
/** Source de migrations concernée, quand le refus en désigne une. */
|
|
101
|
-
source?: string;
|
|
101
|
+
source?: string | undefined;
|
|
102
102
|
/** Tag concerné, quand le refus en désigne un. */
|
|
103
|
-
tag?: string;
|
|
103
|
+
tag?: string | undefined;
|
|
104
104
|
/** Faits constatés, sans mise en forme — de quoi rendre la phrase. */
|
|
105
105
|
facts: Record<string, string | number | boolean | readonly string[]>;
|
|
106
106
|
/** Ce qu'il faut faire ensuite, du plus direct au plus assumé. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Container } from "nodefony";
|
|
1
2
|
import { Orm } from "@nodefony/orm-core";
|
|
2
3
|
import type { IOrmMigrationApplyReply, IOrmMigrationPlanReply, IOrmMigrationReply } from "@nodefony/orm-core";
|
|
3
4
|
import { type ISchemaComparison } from "../migrator/schemaDiff.js";
|
|
@@ -12,12 +13,22 @@ export interface DrizzleOrmOptions {
|
|
|
12
13
|
*/
|
|
13
14
|
dialect?: SqlDialect;
|
|
14
15
|
/** Fichier SQLite (`":memory:"` par défaut) — dialecte `sqlite` uniquement. */
|
|
15
|
-
filename?: string;
|
|
16
|
+
filename?: string | undefined;
|
|
16
17
|
/**
|
|
17
18
|
* Chaîne de connexion (`postgres://…`, `mysql://…`) — dialectes `postgres`/
|
|
18
19
|
* `mysql`. Requise pour ces dialectes.
|
|
19
20
|
*/
|
|
20
|
-
url?: string;
|
|
21
|
+
url?: string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Container du service qui construit l'ORM — il porte le `syslog` du kernel.
|
|
24
|
+
*
|
|
25
|
+
* Sans lui, l'ORM se fabrique un container et un journal à lui, que rien ne
|
|
26
|
+
* relie à la sortie du serveur : « connexion perdue » et « connexion
|
|
27
|
+
* rétablie » partaient dans le vide, et l'exploitant ne voyait que les
|
|
28
|
+
* échecs des sondes, jamais le diagnostic de la reprise. Omis en usage
|
|
29
|
+
* direct (bancs de test) : l'ORM reste alors autonome, comme avant.
|
|
30
|
+
*/
|
|
31
|
+
container?: Container | undefined;
|
|
21
32
|
/**
|
|
22
33
|
* Le schéma doit-il être DÉRIVÉ du code à la connexion ?
|
|
23
34
|
*
|
|
@@ -15,7 +15,7 @@ import type { Criteria, IRepository, ITransaction, RepositoryReadOptions, Update
|
|
|
15
15
|
* La surface d'exécution native qui DIVERGE (`db.all` vs `db.execute().rows`)
|
|
16
16
|
* est routée par le `queryKit` — jamais ici.
|
|
17
17
|
*/
|
|
18
|
-
export type DrizzleDb = BetterSQLite3Database
|
|
18
|
+
export type DrizzleDb = BetterSQLite3Database;
|
|
19
19
|
/** Table Drizzle multi-dialecte (l'union honnête des variantes colKit). */
|
|
20
20
|
export type DrizzleTable = SQLiteTable | PgTable | MySqlTable;
|
|
21
21
|
/** Colonne Drizzle dialecte-agnostique (classe de base — acceptée par les
|
|
@@ -24,9 +24,9 @@ export interface IResolvedForeignKey {
|
|
|
24
24
|
/** Colonnes visées, dans le même ordre que {@link columns}. */
|
|
25
25
|
readonly foreignColumns: readonly string[];
|
|
26
26
|
/** Politique d'effacement du parent (`restrict`, `set null`, `cascade`…). */
|
|
27
|
-
readonly onDelete?: string;
|
|
27
|
+
readonly onDelete?: string | undefined;
|
|
28
28
|
/** Politique de mise à jour de la clé du parent. */
|
|
29
|
-
readonly onUpdate?: string;
|
|
29
|
+
readonly onUpdate?: string | undefined;
|
|
30
30
|
}
|
|
31
31
|
/** Une table à créer, et les tables que ses clés étrangères désignent. */
|
|
32
32
|
export interface ITableDependency {
|
|
@@ -66,11 +66,11 @@ export declare function reserveIdempotencyKeyMysql(db: DrizzleDb, args: {
|
|
|
66
66
|
}): Promise<boolean>;
|
|
67
67
|
/** Filtres du listing utilisateur (sous-ensemble non portable de `IUserListQuery`). */
|
|
68
68
|
export interface UserListFilters {
|
|
69
|
-
role?: string;
|
|
70
|
-
enabled?: boolean;
|
|
71
|
-
locked?: boolean;
|
|
72
|
-
hasSocial?: boolean;
|
|
73
|
-
q?: string;
|
|
69
|
+
role?: string | undefined;
|
|
70
|
+
enabled?: boolean | undefined;
|
|
71
|
+
locked?: boolean | undefined;
|
|
72
|
+
hasSocial?: boolean | undefined;
|
|
73
|
+
q?: string | undefined;
|
|
74
74
|
}
|
|
75
75
|
/** Fenêtre + tri résolus (le défaut `identifier ASC` est posé par l'appelant). */
|
|
76
76
|
export interface UserPageWindow {
|
|
@@ -91,10 +91,10 @@ export declare function listUserIdsPage(db: DrizzleDb, dialect: SqlDialect, filt
|
|
|
91
91
|
}>;
|
|
92
92
|
/** Filtres du listing d'endpoints (sous-ensemble non portable d'`IWebhookListQuery`). */
|
|
93
93
|
export interface WebhookListFilters {
|
|
94
|
-
enabled?: boolean;
|
|
95
|
-
event?: string;
|
|
96
|
-
failing?: boolean;
|
|
97
|
-
q?: string;
|
|
94
|
+
enabled?: boolean | undefined;
|
|
95
|
+
event?: string | undefined;
|
|
96
|
+
failing?: boolean | undefined;
|
|
97
|
+
q?: string | undefined;
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
100
100
|
* Sélectionne les `id` d'une **page** d'endpoints webhook (filtres + tri +
|
|
@@ -37,6 +37,6 @@ import type { SqlDialect } from "../config/config.js";
|
|
|
37
37
|
*/
|
|
38
38
|
export declare function describeTargetSafely(target: {
|
|
39
39
|
dialect: SqlDialect;
|
|
40
|
-
filename?: string;
|
|
41
|
-
url?: string;
|
|
40
|
+
filename?: string | undefined;
|
|
41
|
+
url?: string | undefined;
|
|
42
42
|
}, cwd?: string, grammar?: typeof path): string;
|
package/docs/index.md
CHANGED
|
@@ -342,10 +342,10 @@ de drizzle qui sert de modèle. Deux fichiers, mêmes noms partout, aucune quest
|
|
|
342
342
|
| `nodefony/config/config.ts` | **le QUOI** | schéma Zod commenté = source **unique** des défauts, matérialisés `parse({})` |
|
|
343
343
|
| `nodefony/config/defineModuleConfig.ts` | **le COMMENT** | builder **pur** : parse → surcharge d'environnement → gel |
|
|
344
344
|
|
|
345
|
-
Concrètement : `drizzleConfigSchema` (`config.ts:
|
|
345
|
+
Concrètement : `drizzleConfigSchema` (`config.ts:136`) porte chaque `.default()` et chaque
|
|
346
346
|
`.describe()` — changer un défaut du module, c'est éditer **là et nulle part ailleurs**. Le builder
|
|
347
|
-
`defineDrizzleConfig()` (`defineModuleConfig.ts:
|
|
348
|
-
l'environnement, gèle. Et `drizzleConfigJsonSchema()` (`defineModuleConfig.ts:
|
|
347
|
+
`defineDrizzleConfig()` (`defineModuleConfig.ts:81`) ne retape jamais une valeur : il valide, applique
|
|
348
|
+
l'environnement, gèle. Et `drizzleConfigJsonSchema()` (`defineModuleConfig.ts:99`) expose le tout en
|
|
349
349
|
JSON Schema pour l'écran de configuration de Studio.
|
|
350
350
|
|
|
351
351
|
Le schéma reste **pur** : il ne lit ni `process.env` ni le kernel. C'est ce qui rend le module
|
|
@@ -361,11 +361,11 @@ importable et testable sans serveur.
|
|
|
361
361
|
| `connectors.<n>.url` | `string` | — | Chaîne de connexion `postgres://…` / `mysql://…`. **Porte un secret.** |
|
|
362
362
|
| `frameworkEntities` | `boolean` | `true` | Déclare (ou non) le schéma des huit briques durables sur `default`. |
|
|
363
363
|
|
|
364
|
-
Table dérivée de `drizzleConfigSchema` (`config.ts:
|
|
364
|
+
Table dérivée de `drizzleConfigSchema` (`config.ts:136`) et de `SQL_DIALECTS` (`config.ts:37`).
|
|
365
365
|
|
|
366
366
|
**`filename` est volontairement sans défaut.** Le chemin dépend du kernel, qui n'existe pas quand le
|
|
367
367
|
schéma est évalué. Il est résolu **au démarrage** par `DrizzleService.#defaultFilename()`
|
|
368
|
-
(`DrizzleService.ts:
|
|
368
|
+
(`DrizzleService.ts:230`) vers `<app>/var/databases/nodefony-<connecteur>.db` — sous `var/`, le dossier
|
|
369
369
|
commun des données runtime : « où sont mes données ? » a une réponse unique, un seul chemin à
|
|
370
370
|
sauvegarder et à ignorer dans git.
|
|
371
371
|
|
|
@@ -385,9 +385,12 @@ NF_DATABASE_URL=mysql://app:secret@db:3306/prod
|
|
|
385
385
|
NF_DATABASE_URL=sqlite:/var/lib/app/prod.db
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
-
`applyEnvOverrides()` (`defineModuleConfig.ts:
|
|
389
|
-
_scheme_, et pose `filename` ou `url` sur le connecteur primaire. Une URL `mongodb://` est **
|
|
390
|
-
ici** : elle appartient
|
|
388
|
+
`applyEnvOverrides()` (`defineModuleConfig.ts:32`) lit l'infra, en déduit le dialecte depuis le
|
|
389
|
+
_scheme_, et pose `filename` ou `url` sur le connecteur primaire. Une URL `mongodb://` n'est **pas
|
|
390
|
+
lue ici** : elle appartient à `@nodefony/mongoose`. Drizzle en tire aussi la conséquence — il ne crée
|
|
391
|
+
**pas** le connecteur `default` que ses défauts posent, donc aucune base SQLite parallèle et aucun
|
|
392
|
+
schéma du framework en double. Un `default` que l'application écrit elle-même dans
|
|
393
|
+
`use("@nodefony/drizzle", { connectors: { default: … } })` est gardé, comme tout autre connecteur.
|
|
391
394
|
|
|
392
395
|
**Situation 3 — plusieurs bases.** Un connecteur par base. Seul `default` porte le schéma du framework ;
|
|
393
396
|
les autres sont à toi.
|
|
@@ -403,13 +406,13 @@ use("@nodefony/drizzle", {
|
|
|
403
406
|
|
|
404
407
|
> [!WARNING]
|
|
405
408
|
> Une URL de connexion **porte un mot de passe**. Le module ne la journalise jamais telle quelle :
|
|
406
|
-
> `redactUrl()` (`DrizzleService.ts:
|
|
409
|
+
> `redactUrl()` (`DrizzleService.ts:99`) remplace le mot de passe par `***` avant tout log de
|
|
407
410
|
> démarrage, et la sonde d'administration applique la même règle.
|
|
408
411
|
|
|
409
412
|
### Quand la connexion échoue, le démarrage échoue
|
|
410
413
|
|
|
411
414
|
Un connecteur **déclaré** qui ne se connecte pas lève une `BootConfigurationError`
|
|
412
|
-
(`DrizzleService.ts:
|
|
415
|
+
(`DrizzleService.ts:368`) — en développement **comme** en production. Ce n'est pas une sévérité
|
|
413
416
|
gratuite : une infrastructure déclarée mais injoignable ne se répare pas en continuant. Un serveur qui
|
|
414
417
|
démarrerait « vivant » avec ses stores morts accepterait des requêtes pour échouer plus tard, la cause
|
|
415
418
|
noyée dans un avertissement. Le message d'erreur nomme le connecteur, le dialecte, la cible rédigée et
|
|
@@ -417,7 +420,7 @@ la piste à vérifier.
|
|
|
417
420
|
|
|
418
421
|
Pour les dialectes réseau, la connexion fait un **ping réel** au démarrage : les pools `pg` et `mysql2`
|
|
419
422
|
sont paresseux, sans ce `SELECT 1` une base morte « se connecterait » et n'échouerait qu'à la première
|
|
420
|
-
requête métier (`#connectPostgres()`, `DrizzleOrm.ts:
|
|
423
|
+
requête métier (`#connectPostgres()`, `DrizzleOrm.ts:1193` · `#connectMysql()`, `DrizzleOrm.ts:1514`).
|
|
421
424
|
|
|
422
425
|
## Dialectes — une base par déploiement, un seul code
|
|
423
426
|
|
|
@@ -464,7 +467,7 @@ En MySQL, les verbes « qui rendent la ligne écrite » (`create`, `updateOne`,
|
|
|
464
467
|
`findOneAndDelete`) se décomposent en sélection de la cible → mutation bornée par la clé primaire **avec
|
|
465
468
|
le critère revérifié dans le `WHERE`** → relecture. Deux à trois allers-retours au lieu d'un : c'est le
|
|
466
469
|
prix du dialecte, payé **uniquement** en MySQL. Une course perdue rend `null`, jamais une mutation hors
|
|
467
|
-
critère (`#mysqlInsertReturning()`, `DrizzleRepository.ts:
|
|
470
|
+
critère (`#mysqlInsertReturning()`, `DrizzleRepository.ts:1105`).
|
|
468
471
|
|
|
469
472
|
Le SQL brut nécessaire aux entités du framework est lui aussi routé par dialecte, dans un seul fichier
|
|
470
473
|
(`queryKit.ts`) : recherche dans une colonne JSON (`findUserIdBySocialProvider()`, `queryKit.ts:76`),
|
|
@@ -504,7 +507,7 @@ connexion**, donc leurs tables sont créées au moment où l'ORM s'ouvre.
|
|
|
504
507
|
| Pièce | Rôle | Ancre |
|
|
505
508
|
| ---------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
506
509
|
| `Drizzle` (le module) | valide la config, déclare le schéma framework, monte le data plane | `index.ts` du module |
|
|
507
|
-
| `DrizzleService` | ouvre un ORM par connecteur au boot, ferme tout à l'arrêt | `connectAll()`, `DrizzleService.ts:
|
|
510
|
+
| `DrizzleService` | ouvre un ORM par connecteur au boot, ferme tout à l'arrêt | `connectAll()`, `DrizzleService.ts:214` |
|
|
508
511
|
| `DrizzleOrm` | la connexion : DDL dérivé, repositories, transactions, sonde | `DrizzleOrm.ts:214` |
|
|
509
512
|
| `DrizzleRepository<T>` | le CRUD portable, les opérateurs riches, l'eager-load | `DrizzleRepository.ts:146` |
|
|
510
513
|
| `DrizzleTransaction` | `BEGIN`/`COMMIT`/`ROLLBACK` pilotés à la main, sur les trois dialectes | `DrizzleTransaction.ts:70` |
|
|
@@ -515,7 +518,7 @@ connexion**, donc leurs tables sont créées au moment où l'ORM s'ouvre.
|
|
|
515
518
|
### Le DDL dérivé — comment les tables apparaissent
|
|
516
519
|
|
|
517
520
|
Drizzle ne « synchronise » pas un schéma. L'adapter dérive lui-même un `CREATE TABLE IF NOT EXISTS`
|
|
518
|
-
depuis chaque table déclarée (`#buildCreateTable()`, `DrizzleOrm.ts:
|
|
521
|
+
depuis chaque table déclarée (`#buildCreateTable()`, `DrizzleOrm.ts:509`) et l'exécute à la connexion.
|
|
519
522
|
Trois conséquences à connaître **avant** de dépendre de ce mécanisme :
|
|
520
523
|
|
|
521
524
|
1. il **crée**, il ne **modifie** pas — aucun `ALTER` n'est émis ;
|
|
@@ -556,7 +559,7 @@ await posts.count({ views: { $gte: 10 } });
|
|
|
556
559
|
|
|
557
560
|
Les opérateurs (`$eq $ne $gt $gte $lt $lte $in $nin $like`) sont **ceux d'orm-core**, identiques sur
|
|
558
561
|
tous les drivers ; la traduction en `eq()`/`inArray()` se fait dans `#where()`
|
|
559
|
-
(`DrizzleRepository.ts:
|
|
562
|
+
(`DrizzleRepository.ts:445`). Leur référence complète est dans
|
|
560
563
|
[la page d'orm-core](../../orm-core/docs/index.md).
|
|
561
564
|
|
|
562
565
|
`$like` est émis avec sa clause `ESCAPE '\'` (`likeSql.ts`), ce qui rend un `%` ou un `_` **littéral**
|
|
@@ -568,10 +571,10 @@ Deux points de comportement qui évitent des surprises :
|
|
|
568
571
|
|
|
569
572
|
- **« au plus une ligne »** est garanti par construction pour `updateOne`/`deleteOne`/`increment` :
|
|
570
573
|
la mutation est bornée par la clé primaire découverte de la table, jamais par un `LIMIT` sur un
|
|
571
|
-
`UPDATE` (`#pickOne()`, `DrizzleRepository.ts:
|
|
574
|
+
`UPDATE` (`#pickOne()`, `DrizzleRepository.ts:284`). C'est ce qui rend ces verbes portables — MySQL
|
|
572
575
|
interdit la forme naïve.
|
|
573
576
|
- **l'eager-load est manuel** : une requête `IN (…)` par relation déclarée, puis regroupement en
|
|
574
|
-
mémoire (`#populate()`, `DrizzleRepository.ts:
|
|
577
|
+
mémoire (`#populate()`, `DrizzleRepository.ts:694`). Choix assumé — pas de couche de relations à
|
|
575
578
|
déclarer une seconde fois, et le comportement est le même sur les trois dialectes.
|
|
576
579
|
|
|
577
580
|
### Transactions — une connexion dédiée, jamais le pool
|
|
@@ -600,7 +603,7 @@ Le mécanisme diffère par dialecte, sans que ton code le voie : en PostgreSQL/M
|
|
|
600
603
|
emprunte une connexion **dédiée** au pool, rendue au commit — et **détruite** si celui-ci échoue,
|
|
601
604
|
jamais recyclée dans un état inconnu. En SQLite la connexion est unique, donc c'est un pool de taille 1 :
|
|
602
605
|
les transactions concurrentes sont **sérialisées par une file d'attente** (`#sqliteTxGate`,
|
|
603
|
-
`DrizzleOrm.ts:
|
|
606
|
+
`DrizzleOrm.ts:360`), sinon deux requêtes HTTP simultanées émettraient deux `BEGIN` sur la même
|
|
604
607
|
connexion et la seconde échouerait.
|
|
605
608
|
|
|
606
609
|
Les points de sauvegarde sont disponibles (`savepoint()`, `DrizzleTransaction.ts:123`) ; le nom est
|
|
@@ -624,7 +627,7 @@ const rows = await db.all(sql`
|
|
|
624
627
|
`);
|
|
625
628
|
```
|
|
626
629
|
|
|
627
|
-
C'est l'**anti-blocage** du modèle Repository (`getNativeConnection()`, `DrizzleOrm.ts:
|
|
630
|
+
C'est l'**anti-blocage** du modèle Repository (`getNativeConnection()`, `DrizzleOrm.ts:1783`) : CTE,
|
|
628
631
|
fonctions de fenêtre, sous-requêtes corrélées, jointures arbitraires. Deux contreparties assumées :
|
|
629
632
|
ce SQL n'est plus portable entre dialectes, et il **ne passe pas** par la sonde de profilage des
|
|
630
633
|
requêtes.
|
|
@@ -653,7 +656,7 @@ ou l'idempotence (`createIdempotencyTable`, `idempotencyEntity.ts:85`).
|
|
|
653
656
|
### Comment ça s'active — la réponse est : tout seul
|
|
654
657
|
|
|
655
658
|
Chaque brique choisit son backend par une option `store`, dont le **défaut est `"auto"`**. La
|
|
656
|
-
résolution automatique (`resolveAutoStore()`, `infra.ts:
|
|
659
|
+
résolution automatique (`resolveAutoStore()`, `infra.ts:297`) applique cette préférence :
|
|
657
660
|
|
|
658
661
|
1. une infra `database` déclarée (`NF_DATABASE_URL`) → **`drizzle`** (ou `mongoose` si l'URL est Mongo) ;
|
|
659
662
|
2. sinon, un backend local persistant réellement chargé → **`drizzle`**, c'est-à-dire SQLite ;
|
|
@@ -714,8 +717,8 @@ construction : ils la résolvent à chaque appel. C'est nécessaire parce que l'
|
|
|
714
717
|
le framework résout ses stores avant que l'ORM ne soit connecté — et parce que l'ORM se **déconnecte à
|
|
715
718
|
l'arrêt** avant que les serveurs HTTP n'aient fini de vider leurs requêtes en vol. Handle absent =
|
|
716
719
|
dégradation annoncée, pas un plantage : le `SessionStorage` rend une session vide et ignore les
|
|
717
|
-
écritures (`#repo()`, `SessionStorage.ts:
|
|
718
|
-
dédup (`begin()`, `DrizzleIdempotencyStore.ts:
|
|
720
|
+
écritures (`#repo()`, `SessionStorage.ts:86`), le store d'idempotence laisse passer la mutation sans
|
|
721
|
+
dédup (`begin()`, `DrizzleIdempotencyStore.ts:225`).
|
|
719
722
|
|
|
720
723
|
**SQL n'a pas de TTL.** Contrairement à Redis, rien n'expire tout seul : chaque store expose un `gc()`
|
|
721
724
|
applicatif qui supprime les lignes échues, déclenché par un minuteur hors du chemin chaud —
|
|
@@ -732,7 +735,7 @@ c'est ce qui interdit de conclure « nouvelle mutation » hors d'une réservatio
|
|
|
732
735
|
en deux instructions au verdict non ambigu (`reserveIdempotencyKeyMysql()`, `queryKit.ts:152`).
|
|
733
736
|
|
|
734
737
|
**Le journal d'audit** pagine par un curseur **composite auto-portant** `<horodatage>:<id>` sur un ordre
|
|
735
|
-
total, plutôt que par un identifiant seul (`listPage()`, `DrizzleAuditStore.ts:
|
|
738
|
+
total, plutôt que par un identifiant seul (`listPage()`, `DrizzleAuditStore.ts:175`). Deux gains : plus
|
|
736
739
|
d'aller-retour pour résoudre le curseur, et une pagination qui ne rembobine pas à la première page si
|
|
737
740
|
l'événement de référence a été purgé entre deux appels.
|
|
738
741
|
|
|
@@ -772,8 +775,8 @@ entités que le DDL dérivé, et un banc vérifie sur les trois dialectes qu'une
|
|
|
772
775
|
identique à une base **dérivée** — colonne par colonne, index compris. Sans cette preuve, les deux
|
|
773
776
|
chemins divergeraient en silence.
|
|
774
777
|
|
|
775
|
-
Les appliquer, les adopter, les réparer
|
|
776
|
-
`
|
|
778
|
+
Les écrire, les appliquer, les adopter, les réparer, surveiller leur état et repartir d'une base
|
|
779
|
+
vide est le travail de six commandes — `orm:generate`, les quatre `orm:migrate*` et `orm:reset` — avec leur verrou, leur historique et leur branchement sur la sonde de
|
|
777
780
|
disponibilité. Tout est dans **[Migrations de schéma](migrations.md)**, qui porte aussi le patron de
|
|
778
781
|
déploiement sans interruption et les droits du compte qui migre.
|
|
779
782
|
|
|
@@ -831,7 +834,7 @@ faire lui-même).
|
|
|
831
834
|
Côté écrans : **Database**, **ORM (vue d'ensemble et par entité)** et **Stores** — ce dernier répond à
|
|
832
835
|
la question « où sont écrites mes données ? » pour chaque brique.
|
|
833
836
|
|
|
834
|
-
La sonde d'un connecteur s'adapte au dialecte (`probe()`, `DrizzleOrm.ts:
|
|
837
|
+
La sonde d'un connecteur s'adapte au dialecte (`probe()`, `DrizzleOrm.ts:1873`) :
|
|
835
838
|
|
|
836
839
|
- **SQLite** → `storage` : taille du fichier, mode de journal, pages libres (lus par `PRAGMA`) ;
|
|
837
840
|
- **PostgreSQL / MySQL** → `pool` : taille, connexions libres, empruntées, en attente — **compteurs en
|
|
@@ -843,12 +846,12 @@ que promettre en silence — c'est le principe « superviser sans peser sur la p
|
|
|
843
846
|
|
|
844
847
|
Chaque store expose aussi son **emplacement physique** pour l'écran Stores : le chemin du fichier
|
|
845
848
|
SQLite, relativisé (anti-fuite d'information), et `undefined` pour un backend réseau — dont
|
|
846
|
-
l'emplacement **est** l'infra déclarée, déjà affichée ailleurs (`location`, `DrizzleOrm.ts:
|
|
849
|
+
l'emplacement **est** l'infra déclarée, déjà affichée ailleurs (`location`, `DrizzleOrm.ts:481`).
|
|
847
850
|
|
|
848
851
|
## ⚡ Performance & mémoire
|
|
849
852
|
|
|
850
853
|
**La sonde de requêtes ne coûte rien quand elle est éteinte.** Chaque exécution passe par un point de
|
|
851
|
-
mesure unique (`#prof()`, `DrizzleRepository.ts:
|
|
854
|
+
mesure unique (`#prof()`, `DrizzleRepository.ts:355`) qui alimente deux consommateurs — le profileur
|
|
852
855
|
par requête (barre de debug) et l'agrégat de flux. Les deux sont gardés par un drapeau : si aucun n'est
|
|
853
856
|
actif, la fonction rend le constructeur de requête tel quel, sans allocation. Le flux est **désactivé
|
|
854
857
|
en production** par défaut.
|