@nodefony/orm-core 10.0.0-beta.2 → 10.0.0-beta.4

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.
@@ -1,4 +1,4 @@
1
- //#region nodefony/interfaces/IOrmMigrations.ts
1
+ // nodefony/interfaces/IOrmMigrations.ts
2
2
  /**
3
3
  * Y a-t-il un empêchement plutôt qu'un état ?
4
4
  *
@@ -8,5 +8,4 @@
8
8
  function isMigrationFailure(reply) {
9
9
  return "error" in reply;
10
10
  }
11
- //#endregion
12
11
  export { isMigrationFailure };
@@ -1,7 +1,7 @@
1
1
  import { omitUndefined } from "./omitUndefined.js";
2
2
  import { paginate } from "./paginate.js";
3
3
  import { Service } from "nodefony";
4
- //#region nodefony/src/AbstractCrudService.ts
4
+ // nodefony/src/AbstractCrudService.ts
5
5
  /**
6
6
  * Service CRUD **générique** — socle réutilisable au-dessus d'un {@link IRepository}.
7
7
  *
@@ -199,5 +199,4 @@ var AbstractCrudService = class extends Service {
199
199
  /** Effet de bord après suppression (ex. nettoyer un cache). */
200
200
  afterDelete(_criteria, _removed) {}
201
201
  };
202
- //#endregion
203
202
  export { AbstractCrudService };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/ConnectionMonitor.ts
1
+ // nodefony/src/ConnectionMonitor.ts
2
2
  /** Taille max du ring d'erreurs récentes (borne mémoire). */
3
3
  const MAX_RECENT_ERRORS = 12;
4
4
  /** Taille max de la chronologie pertes/reprises (borne mémoire). */
@@ -209,5 +209,4 @@ var ConnectionMonitor = class {
209
209
  };
210
210
  /** Singleton process-wide du moniteur de connexions. */
211
211
  const connectionMonitor = new ConnectionMonitor();
212
- //#endregion
213
212
  export { connectionMonitor };
@@ -1,5 +1,5 @@
1
1
  import { entityRegistry } from "./EntityRegistry.js";
2
- //#region nodefony/src/Entity.ts
2
+ // nodefony/src/Entity.ts
3
3
  /**
4
4
  * Classe de base abstraite d'une entité, indépendante du driver ORM.
5
5
  *
@@ -38,5 +38,4 @@ var Entity = class {
38
38
  return this;
39
39
  }
40
40
  };
41
- //#endregion
42
41
  export { Entity };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/EntityRegistry.ts
1
+ // nodefony/src/EntityRegistry.ts
2
2
  /**
3
3
  * Registre cross-ORM des entités, indexé par nom logique puis par connecteur.
4
4
  *
@@ -111,5 +111,4 @@ var EntityRegistry = class {
111
111
  * (tests).
112
112
  */
113
113
  const entityRegistry = new EntityRegistry();
114
- //#endregion
115
114
  export { EntityRegistry, entityRegistry };
@@ -2,7 +2,7 @@ import { ormRegistry } from "./OrmRegistry.js";
2
2
  import { connectionMonitor } from "./ConnectionMonitor.js";
3
3
  import { Service } from "nodefony";
4
4
  import { performance } from "node:perf_hooks";
5
- //#region nodefony/src/Orm.ts
5
+ // nodefony/src/Orm.ts
6
6
  /**
7
7
  * Période du battement, réglable par l'environnement (`0` le désactive).
8
8
  *
@@ -309,5 +309,4 @@ var Orm = class extends Service {
309
309
  return { driver: "" };
310
310
  }
311
311
  };
312
- //#endregion
313
312
  export { Orm };
@@ -4,7 +4,7 @@ import { connectionMonitor } from "./ConnectionMonitor.js";
4
4
  import { queryFlowMonitor } from "./QueryFlowMonitor.js";
5
5
  import { Nodefony } from "nodefony";
6
6
  import { performance } from "node:perf_hooks";
7
- //#region nodefony/src/OrmAdminApi.ts
7
+ // nodefony/src/OrmAdminApi.ts
8
8
  /**
9
9
  * Producteur `IAdminApi` du **modèle de données ORM** — exposé sous
10
10
  * `/nodefony/orm/api/*`. Fondation « IA-first » : construit le graphe canonique
@@ -109,7 +109,7 @@ function buildOrmSummaries() {
109
109
  const names = ormRegistry.list();
110
110
  const carrier = storeCarrier(Nodefony.getKernel()?.storeResolutions ?? [], names);
111
111
  return names.map((name) => {
112
- let connected = false;
112
+ let connected;
113
113
  let vendor = "";
114
114
  let connection;
115
115
  try {
@@ -136,7 +136,7 @@ function buildOrmSummaries() {
136
136
  */
137
137
  function buildEntityNode(connector, name) {
138
138
  const entity = entityRegistry.get(name, connector);
139
- let columns = [];
139
+ let columns;
140
140
  try {
141
141
  columns = ormRegistry.get(connector).describeEntity?.(name) ?? [];
142
142
  } catch {
@@ -275,7 +275,7 @@ async function buildConnectionHealth(filter) {
275
275
  */
276
276
  function buildOrmFlow(filter) {
277
277
  const connectors = ormRegistry.list().filter((n) => !filter || n === filter).map((name) => {
278
- let vendor = "";
278
+ let vendor;
279
279
  try {
280
280
  vendor = vendorOf(ormRegistry.get(name));
281
281
  } catch {
@@ -529,5 +529,4 @@ function registerOrmAdminApi(registry) {
529
529
  if (registry.has("orm")) return;
530
530
  registry.register(createOrmAdminApi());
531
531
  }
532
- //#endregion
533
532
  export { buildConnectionHealth, buildOrmFlow, buildOrmGraph, createOrmAdminApi, registerOrmAdminApi, storeCarrier, toDbml, toJsonSchema };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/OrmRegistry.ts
1
+ // nodefony/src/OrmRegistry.ts
2
2
  /**
3
3
  * Registre process-wide des instances ORM enregistrées sous un nom unique.
4
4
  *
@@ -71,5 +71,4 @@ var OrmRegistry = class {
71
71
  * instanciable séparément pour des registres isolés (tests).
72
72
  */
73
73
  const ormRegistry = new OrmRegistry();
74
- //#endregion
75
74
  export { OrmRegistry, ormRegistry };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/QueryFlowMonitor.ts
1
+ // nodefony/src/QueryFlowMonitor.ts
2
2
  /** Taille max du ring de requêtes lentes (borne mémoire). */
3
3
  const MAX_SLOW = 20;
4
4
  /** Facteur de lissage EWMA (0–1) : plus haut = suit plus vite les variations. */
@@ -124,5 +124,4 @@ var QueryFlowMonitor = class {
124
124
  };
125
125
  /** Singleton process-wide de la sonde de flux ORM. */
126
126
  const queryFlowMonitor = new QueryFlowMonitor();
127
- //#endregion
128
127
  export { queryFlowMonitor };
@@ -1,7 +1,7 @@
1
1
  import { ormRegistry } from "./OrmRegistry.js";
2
2
  import { connectionMonitor } from "./ConnectionMonitor.js";
3
3
  import { queryFlowMonitor } from "./QueryFlowMonitor.js";
4
- //#region nodefony/src/buildOrmLeanHealth.ts
4
+ // nodefony/src/buildOrmLeanHealth.ts
5
5
  /**
6
6
  * **Santé ORM lean per-instance** — somme process-wide de tous les connecteurs enregistrés,
7
7
  * destinée à voyager dans le report de sonde cluster (« ORM par worker »). C'est la fonction
@@ -50,5 +50,4 @@ function buildOrmLeanHealth() {
50
50
  maxEwmaMs
51
51
  };
52
52
  }
53
- //#endregion
54
53
  export { buildOrmLeanHealth, buildOrmLeanHealth as default };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/connectDeadline.ts
1
+ // nodefony/src/connectDeadline.ts
2
2
  /**
3
3
  * Le DÉLAI DE GARDE d'une connexion à une base — une commande n'attend jamais
4
4
  * sans fin.
@@ -63,5 +63,4 @@ async function withConnectDeadline(work, what, ms = CONNECT_TIMEOUT_MS) {
63
63
  if (timer !== void 0) clearTimeout(timer);
64
64
  }
65
65
  }
66
- //#endregion
67
66
  export { CONNECT_TIMEOUT_MS, withConnectDeadline };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/connectionDiagnosis.ts
1
+ // nodefony/src/connectionDiagnosis.ts
2
2
  /**
3
3
  * Personne n'écoute : la couche transport a refusé ou n'a trouvé personne.
4
4
  * Ces codes viennent du système, pas du serveur de base de données.
@@ -68,29 +68,78 @@ function readCode(error) {
68
68
  return typeof carrier.code === "number" ? String(carrier.code) : null;
69
69
  }
70
70
  /**
71
- * Extrait l'hôte et le port d'une URL de connexion, sans son secret.
71
+ * Extrait l'hôte, le port, la base et le compte d'une URL de connexion, sans
72
+ * son secret.
72
73
  *
73
74
  * @param url - URL de connexion (`postgres://…`, `mysql://…`, `mongodb://…`).
74
75
  * @returns l'adresse visée ; champs à `null` si l'URL est absente ou illisible.
75
76
  */
76
77
  function parseConnectionTarget(url) {
77
- if (!url) return {
78
+ const none = {
78
79
  host: null,
79
- port: null
80
+ port: null,
81
+ database: null,
82
+ user: null
80
83
  };
84
+ if (!url) return none;
81
85
  try {
82
86
  const parsed = new URL(url);
83
87
  const port = parsed.port ? Number(parsed.port) : null;
88
+ const database = decodeURIComponent(parsed.pathname.slice(1));
89
+ const user = decodeURIComponent(parsed.username);
84
90
  return {
85
91
  host: parsed.hostname || null,
86
- port: Number.isFinite(port) ? port : null
92
+ port: Number.isFinite(port) ? port : null,
93
+ database: database || null,
94
+ user: user || null
87
95
  };
88
96
  } catch {
89
- return {
90
- host: null,
91
- port: null
92
- };
97
+ return none;
98
+ }
99
+ }
100
+ /**
101
+ * Identifiant PostgreSQL entre guillemets — un nom de base peut porter un
102
+ * tiret ou une majuscule, que PostgreSQL plierait ou refuserait nu.
103
+ */
104
+ function quotePgIdent(name) {
105
+ return `"${name.replaceAll("\"", "\"\"")}"`;
106
+ }
107
+ /** Identifiant MySQL/MariaDB entre accents graves. */
108
+ function quoteMysqlIdent(name) {
109
+ return `\`${name.replaceAll("`", "``")}\``;
110
+ }
111
+ /** Chaîne SQL MySQL/MariaDB entre apostrophes (nom de compte d'un `GRANT`). */
112
+ function quoteMysqlString(value) {
113
+ return `'${value.replaceAll("'", "''")}'`;
114
+ }
115
+ /**
116
+ * La base désignée manque — ou, sous MySQL/MariaDB, le compte n'y a aucun
117
+ * droit, ce que le serveur ne distingue pas.
118
+ *
119
+ * Les trois codes ne sortent qu'APRÈS l'acceptation du mot de passe (constaté :
120
+ * un mauvais mot de passe rend `28P01` ou `ER_ACCESS_DENIED_ERROR`, même sur
121
+ * une base absente). Vérifier les identifiants n'est donc pas le geste : il
122
+ * faut créer la base, avec un compte qui en a le droit — l'application ne la
123
+ * crée jamais, un compte capable de créer des bases l'est aussi d'en supprimer.
124
+ *
125
+ * @returns l'explication rédigée, ou `null` si le code n'est pas celui d'une
126
+ * base absente ou si l'URL ne nomme pas la base.
127
+ */
128
+ function describeMissingDatabase(code, target, where, portHint) {
129
+ const database = target.database;
130
+ if (!database) return null;
131
+ const account = target.user ? ` « ${target.user} »` : "";
132
+ const how = "La créer avec un compte qui en a le droit (administrateur du serveur, ou celui du conteneur dans le décor docker), puis relancer : ";
133
+ const elsewhere = portHint ? ` Si cette base devrait déjà exister, vérifier que ce port est bien tenu par VOTRE serveur.${portHint}` : "";
134
+ if (code === "3D000") {
135
+ const owner = target.user ? ` OWNER ${quotePgIdent(target.user)}` : "";
136
+ return `la base « ${database} » n'existe pas sur le serveur ${where} (${code}) — le serveur a répondu et accepté le compte${account}, mais l'application ne crée jamais sa base (CREATE DATABASE est un privilège d'administration). ${how}CREATE DATABASE ${quotePgIdent(database)}${owner};${elsewhere}`;
93
137
  }
138
+ if (code === "ER_BAD_DB_ERROR" || code === "ER_DBACCESS_DENIED_ERROR") {
139
+ const grant = target.user ? ` GRANT ALL PRIVILEGES ON ${quoteMysqlIdent(database)}.* TO ${quoteMysqlString(target.user)}@'%';` : "";
140
+ return `${code === "ER_DBACCESS_DENIED_ERROR" ? `le compte${account} n'a accès à aucune base « ${database} » sur le serveur ${where} (${code}) : soit elle n'existe pas, soit elle existe sans droit pour ce compte — MySQL ne dit pas lequel. ` : `la base « ${database} » n'existe pas sur le serveur ${where} (${code}). `}Le mot de passe a été accepté, et l'application ne crée jamais sa base (privilège d'administration). ${how}CREATE DATABASE IF NOT EXISTS ${quoteMysqlIdent(database)};${grant}` + elsewhere;
141
+ }
142
+ return null;
94
143
  }
95
144
  /**
96
145
  * La commande qui nomme QUI tient un port, sur la plateforme visée.
@@ -123,11 +172,20 @@ function diagnoseConnectionFailure(error, target = {
123
172
  code,
124
173
  explanation: `personne n'écoute sur ${where} (${code}) — la base n'est pas démarrée, ou l'adresse configurée n'est pas la sienne.`
125
174
  };
126
- if (code !== null && ANSWERED_CODES.has(code)) return {
127
- verdict: "answered",
128
- code,
129
- explanation: `un serveur a RÉPONDU sur ${where} puis a refusé (${code}) — donc quelque chose tient bien ce port. Ce peut être la base attendue avec de mauvais identifiants, mais aussi UN AUTRE SERVEUR (le conteneur d'un autre projet, par exemple) : le refus vient alors d'une base qui n'est pas la vôtre, et vérifier les identifiants ne mène nulle part.${target.port !== null ? ` Pour savoir qui tient ce port : « docker ps --filter publish=${target.port} », ou « ${whoHoldsPort(target.port, platform)} ».` : ""}`
130
- };
175
+ if (code !== null && ANSWERED_CODES.has(code)) {
176
+ const portHint = target.port !== null ? ` Pour savoir qui tient ce port : « docker ps --filter publish=${target.port} », ou « ${whoHoldsPort(target.port, platform)} ».` : "";
177
+ const missing = describeMissingDatabase(code, target, where, portHint);
178
+ if (missing !== null) return {
179
+ verdict: "answered",
180
+ code,
181
+ explanation: missing
182
+ };
183
+ return {
184
+ verdict: "answered",
185
+ code,
186
+ explanation: `un serveur a RÉPONDU sur ${where} puis a refusé (${code}) — donc quelque chose tient bien ce port. Ce peut être la base attendue avec de mauvais identifiants, mais aussi UN AUTRE SERVEUR (le conteneur d'un autre projet, par exemple) : le refus vient alors d'une base qui n'est pas la vôtre, et vérifier les identifiants ne mène nulle part.${portHint}`
187
+ };
188
+ }
131
189
  if (code !== null && provesEstablished(code)) return {
132
190
  verdict: "rejected",
133
191
  code,
@@ -168,5 +226,4 @@ function describeConnectFailure(subject, diagnosis, cause, advice = "") {
168
226
  }
169
227
  return `${subject} n'a pas pu se connecter — ${diagnosis.explanation}${advice} Cause : ${cause}`;
170
228
  }
171
- //#endregion
172
229
  export { REJECTED_MARKER, describeConnectFailure, diagnoseConnectionFailure, parseConnectionTarget };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/criteria.ts
1
+ // nodefony/src/criteria.ts
2
2
  /**
3
3
  * Liste figée des opérateurs riches reconnus dans un critère portable.
4
4
  *
@@ -173,5 +173,4 @@ function searchCriteria(q, fields) {
173
173
  if (only !== void 0) return { [only]: { $like: likePattern } };
174
174
  return { $or: fields.map((f) => ({ [f]: { $like: likePattern } })) };
175
175
  }
176
- //#endregion
177
176
  export { LIKE_ESCAPE_CHAR, OPERATOR_KEYS, UPDATE_OPERATOR_KEYS, escapeLikeTerm, isFieldOperators, isUpdateOperators, likePatternToRegExp, searchCriteria };
@@ -1,5 +1,5 @@
1
1
  import { entityRegistry } from "../EntityRegistry.js";
2
- //#region nodefony/src/decorators/entitiesDecorator.ts
2
+ // nodefony/src/decorators/entitiesDecorator.ts
3
3
  /** Connecteur retenu quand ni l'entité ni le décorateur n'en nomment un. */
4
4
  const DEFAULT_CONNECTOR = "default";
5
5
  /**
@@ -63,5 +63,4 @@ function entities(list, options = {}) {
63
63
  return NewConstructorEntities;
64
64
  };
65
65
  }
66
- //#endregion
67
66
  export { DEFAULT_CONNECTOR, entities };
@@ -1,6 +1,6 @@
1
1
  import { entityRegistry } from "../EntityRegistry.js";
2
2
  import { setEntityMeta } from "./metadataStore.js";
3
- //#region nodefony/src/decorators/entityDecorator.ts
3
+ // nodefony/src/decorators/entityDecorator.ts
4
4
  /**
5
5
  * Décore une classe comme entité multi-ORM et l'enregistre au chargement.
6
6
  *
@@ -47,5 +47,4 @@ function entity(options) {
47
47
  return target;
48
48
  };
49
49
  }
50
- //#endregion
51
50
  export { entity };
@@ -1,10 +1,10 @@
1
- //#region nodefony/src/decorators/metadataStore.ts
1
+ // nodefony/src/decorators/metadataStore.ts
2
2
  /**
3
3
  * Stockage des métadonnées de décorateurs SANS `reflect-metadata`.
4
4
  *
5
5
  * orm-core est une lib pure : aucune dépendance runtime hors `nodefony`. Les
6
- * décorateurs `@entity`/`@repository` ne lisent jamais les types émis par TS
7
- * (`design:paramtypes`), donc un `WeakMap<classe, métadonnée>` process-wide
6
+ * décorateurs `@entity`/`@repository` ne lisent jamais les métadonnées de type
7
+ * émises par le compilateur, donc un `WeakMap<classe, métadonnée>` process-wide
8
8
  * suffit — clé = constructeur, GC-friendly (pas de fuite si la classe est
9
9
  * déréférencée). Aucun polyfill Reflect requis.
10
10
  */
@@ -34,5 +34,4 @@ function getRepositoryMeta(target) {
34
34
  function hasRepositoryMeta(target) {
35
35
  return REPOSITORY_META.has(target);
36
36
  }
37
- //#endregion
38
37
  export { getEntityMeta, getRepositoryMeta, hasEntityMeta, hasRepositoryMeta, setEntityMeta, setRepositoryMeta };
@@ -1,5 +1,5 @@
1
1
  import { setRepositoryMeta } from "./metadataStore.js";
2
- //#region nodefony/src/decorators/repositoryDecorator.ts
2
+ // nodefony/src/decorators/repositoryDecorator.ts
3
3
  /**
4
4
  * Décore une classe comme repository d'une entité (tag métadonnée pur).
5
5
  *
@@ -31,5 +31,4 @@ function repository(name, options) {
31
31
  return target;
32
32
  };
33
33
  }
34
- //#endregion
35
34
  export { repository };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/defineEntity.ts
1
+ // nodefony/src/defineEntity.ts
2
2
  /**
3
3
  * Déclare une entité applicative. Fonction d'**identité typée** : elle ne fait
4
4
  * qu'attacher le type — aucun effet de bord, aucun enregistrement.
@@ -23,5 +23,4 @@
23
23
  function defineEntity(definition) {
24
24
  return definition;
25
25
  }
26
- //#endregion
27
26
  export { defineEntity };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/errors.ts
1
+ // nodefony/src/errors.ts
2
2
  /**
3
3
  * Erreurs typées du socle ORM — **data-level uniquement** (aucun couplage à une
4
4
  * couche API/transport : ces erreurs décrivent des fautes sur les données, pas
@@ -130,5 +130,4 @@ var SavepointNotSupportedError = class extends Error {
130
130
  this.driver = driver;
131
131
  }
132
132
  };
133
- //#endregion
134
133
  export { InvalidOrderOption, ReferencedEntityError, SavepointNotSupportedError, UnknownCriteriaField };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/omitUndefined.ts
1
+ // nodefony/src/omitUndefined.ts
2
2
  /**
3
3
  * Retire les clés qui valent `undefined` d'une donnée d'écriture partielle.
4
4
  *
@@ -26,5 +26,4 @@ function omitUndefined(data) {
26
26
  }
27
27
  return data;
28
28
  }
29
- //#endregion
30
29
  export { omitUndefined };
@@ -2,7 +2,7 @@ import { ormRegistry } from "./OrmRegistry.js";
2
2
  import { buildConnectionHealth, buildOrmFlow, registerOrmAdminApi } from "./OrmAdminApi.js";
3
3
  import { buildOrmLeanHealth } from "./buildOrmLeanHealth.js";
4
4
  import { setOrmHealthProvider, setOrmRichProvider } from "nodefony";
5
- //#region nodefony/src/ormWiring.ts
5
+ // nodefony/src/ormWiring.ts
6
6
  /**
7
7
  * Branche le « plan d'administration » ORM dans le kernel — montage **idempotent**
8
8
  * appelé par CHAQUE driver à son `onKernelBoot`. Factorise la dette C5 : le bloc
@@ -74,5 +74,4 @@ function resolveOrmFlowEnabled(kernel) {
74
74
  const flag = process.env.NF_ORM_FLOW;
75
75
  return flag !== void 0 ? flag === "1" || flag === "true" : kernel?.environment !== "production";
76
76
  }
77
- //#endregion
78
77
  export { reportOrmBootLines, resolveOrmFlowEnabled, wireOrmAdminPlane };
@@ -1,6 +1,6 @@
1
1
  import { ormRegistry } from "./OrmRegistry.js";
2
2
  import { entityRegistry } from "./EntityRegistry.js";
3
- //#region nodefony/src/orphanEntities.ts
3
+ // nodefony/src/orphanEntities.ts
4
4
  /**
5
5
  * Entités inscrites sur un connecteur qu'aucun ORM n'a ouvert.
6
6
  *
@@ -59,5 +59,4 @@ function reportOrphanEntities(log, owner, declared = []) {
59
59
  if (message !== null) log(message, "WARNING");
60
60
  return message;
61
61
  }
62
- //#endregion
63
62
  export { describeOrphanEntities, findOrphanEntities, reportOrphanEntities };
@@ -1,6 +1,6 @@
1
1
  import { searchCriteria } from "./criteria.js";
2
2
  import { PageQueryError } from "nodefony";
3
- //#region nodefony/src/paginate.ts
3
+ // nodefony/src/paginate.ts
4
4
  /**
5
5
  * Pagine un {@link IRepository} de façon **portable** — au-dessus des primitives
6
6
  * natives `find(criteria, { limit, offset, order })` et `count(criteria)` que tout
@@ -51,5 +51,4 @@ async function paginate(repo, page, options = {}) {
51
51
  total: withTotal ? await repo.count(criteria) : void 0
52
52
  };
53
53
  }
54
- //#endregion
55
54
  export { paginate };
@@ -1,5 +1,5 @@
1
1
  import { InvalidOrderOption } from "./errors.js";
2
- //#region nodefony/src/readOptions.ts
2
+ // nodefony/src/readOptions.ts
3
3
  /**
4
4
  * Décrit la FORME d'une valeur reçue, sans jamais en révéler le contenu.
5
5
  *
@@ -48,5 +48,4 @@ function assertOrderOption(order, entity) {
48
48
  }
49
49
  }
50
50
  }
51
- //#endregion
52
51
  export { assertOrderOption };
@@ -44,9 +44,17 @@ export interface IConnectionDiagnosis {
44
44
  export interface IConnectionTarget {
45
45
  host: string | null;
46
46
  port: number | null;
47
+ /**
48
+ * Nom de la base désignée par l'URL — de quoi NOMMER une base absente et
49
+ * écrire la commande qui la crée. Absent : la phrase n'en parle pas.
50
+ */
51
+ database?: string | null;
52
+ /** Compte de connexion (jamais son mot de passe) — propriétaire de la base à créer. */
53
+ user?: string | null;
47
54
  }
48
55
  /**
49
- * Extrait l'hôte et le port d'une URL de connexion, sans son secret.
56
+ * Extrait l'hôte, le port, la base et le compte d'une URL de connexion, sans
57
+ * son secret.
50
58
  *
51
59
  * @param url - URL de connexion (`postgres://…`, `mysql://…`, `mongodb://…`).
52
60
  * @returns l'adresse visée ; champs à `null` si l'URL est absente ou illisible.