@villedemontreal/utils-knex 7.0.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.
Files changed (66) hide show
  1. package/README.md +236 -0
  2. package/dist/src/config/configs.d.ts +19 -0
  3. package/dist/src/config/configs.d.ts.map +1 -0
  4. package/dist/src/config/configs.js +27 -0
  5. package/dist/src/config/configs.js.map +1 -0
  6. package/dist/src/config/constants.d.ts +21 -0
  7. package/dist/src/config/constants.d.ts.map +1 -0
  8. package/dist/src/config/constants.js +21 -0
  9. package/dist/src/config/constants.js.map +1 -0
  10. package/dist/src/config/init.d.ts +16 -0
  11. package/dist/src/config/init.d.ts.map +1 -0
  12. package/dist/src/config/init.js +33 -0
  13. package/dist/src/config/init.js.map +1 -0
  14. package/dist/src/databaseContext.d.ts +9 -0
  15. package/dist/src/databaseContext.d.ts.map +1 -0
  16. package/dist/src/databaseContext.js +3 -0
  17. package/dist/src/databaseContext.js.map +1 -0
  18. package/dist/src/index.d.ts +5 -0
  19. package/dist/src/index.d.ts.map +1 -0
  20. package/dist/src/index.js +26 -0
  21. package/dist/src/index.js.map +1 -0
  22. package/dist/src/knexUtils.d.ts +134 -0
  23. package/dist/src/knexUtils.d.ts.map +1 -0
  24. package/dist/src/knexUtils.js +349 -0
  25. package/dist/src/knexUtils.js.map +1 -0
  26. package/dist/src/knexUtils.test.d.ts +2 -0
  27. package/dist/src/knexUtils.test.d.ts.map +1 -0
  28. package/dist/src/knexUtils.test.js +897 -0
  29. package/dist/src/knexUtils.test.js.map +1 -0
  30. package/dist/src/transactionManager.d.ts +34 -0
  31. package/dist/src/transactionManager.d.ts.map +1 -0
  32. package/dist/src/transactionManager.js +75 -0
  33. package/dist/src/transactionManager.js.map +1 -0
  34. package/dist/src/transactionManager.test.d.ts +10 -0
  35. package/dist/src/transactionManager.test.d.ts.map +1 -0
  36. package/dist/src/transactionManager.test.js +255 -0
  37. package/dist/src/transactionManager.test.js.map +1 -0
  38. package/dist/src/utils/logger.d.ts +12 -0
  39. package/dist/src/utils/logger.d.ts.map +1 -0
  40. package/dist/src/utils/logger.js +53 -0
  41. package/dist/src/utils/logger.js.map +1 -0
  42. package/dist/src/utils/testingConfigurations.d.ts +9 -0
  43. package/dist/src/utils/testingConfigurations.d.ts.map +1 -0
  44. package/dist/src/utils/testingConfigurations.js +16 -0
  45. package/dist/src/utils/testingConfigurations.js.map +1 -0
  46. package/dist/testing/testClient.d.ts +15 -0
  47. package/dist/testing/testClient.d.ts.map +1 -0
  48. package/dist/testing/testClient.js +55 -0
  49. package/dist/testing/testClient.js.map +1 -0
  50. package/dist/testing/testRepo.d.ts +8 -0
  51. package/dist/testing/testRepo.d.ts.map +1 -0
  52. package/dist/testing/testRepo.js +31 -0
  53. package/dist/testing/testRepo.js.map +1 -0
  54. package/dist/tsconfig.tsbuildinfo +1 -0
  55. package/package.json +76 -0
  56. package/src/config/configs.ts +34 -0
  57. package/src/config/constants.ts +33 -0
  58. package/src/config/init.ts +33 -0
  59. package/src/databaseContext.ts +9 -0
  60. package/src/index.ts +9 -0
  61. package/src/knexUtils.test.ts +1526 -0
  62. package/src/knexUtils.ts +459 -0
  63. package/src/transactionManager.test.ts +302 -0
  64. package/src/transactionManager.ts +94 -0
  65. package/src/utils/logger.ts +60 -0
  66. package/src/utils/testingConfigurations.ts +13 -0
package/README.md ADDED
@@ -0,0 +1,236 @@
1
+ # @villemontreal/core-utils-knex-nodejs-lib
2
+
3
+ Module d'utilitaires pour la librairie Knex.
4
+
5
+ ## Availabililty
6
+
7
+ https://bitbucket.org/villemontreal/core-utils-knex-nodejs-lib
8
+
9
+ ## Installation
10
+
11
+ Installer la bibliothèque:
12
+
13
+ ```shell
14
+ npm install --save @villemontreal/test-core-utils-knex-nodejs-lib
15
+ ```
16
+
17
+ ## Utilisation
18
+
19
+ # Configurations
20
+
21
+ Un code utilisant cette librarie doit premièrement la configurer en appellant la fonction
22
+ "`ìnit(...)`" exportée par le fichier "`src/config/init.ts`".
23
+
24
+ La configuration "`loggerCreator`" est _requise_ par cette librairie. Cela signifie qu'un code utilisant la librairie
25
+ (que ce soit du code d'un projet d'API ou d'une autre librairie) _doit_ setter cette configuration _avant_ que les composants
26
+ de la librairie ne soient utilisés.
27
+
28
+ Par exemple, dans un projet d'API basé sur le générateur
29
+ [generator-mtl-node-api](https://bitbucket.org/villemontreal/generator-mtl-node-api), ceci sera effectué dans le
30
+ fichier "`src/init.ts`", au début de la fonction `initComponents()` :
31
+
32
+ ```typescript
33
+ import { init as initKnexUtilsLib } from '@villemontreal/core-utils-knex-nodejs-lib';
34
+ import { createLogger } from './utils/logger';
35
+
36
+ export async function initComponents() {
37
+ initKnexUtilsLib(createLogger);
38
+
39
+ //...
40
+ }
41
+ ```
42
+
43
+ Si vous configurez la librairie depuis _une autre librairie_, vous aurez à passer
44
+ le "`Logger Creator`" que vous aurez _vous-même_ reçu comme configurations! :
45
+
46
+ ```typescript
47
+ import { init as initKnexUtilsLib } from '@villemontreal/core-utils-knex-nodejs-lib';
48
+ import { configs } from './configs';
49
+
50
+ export async function initComponents() {
51
+ initKnexUtilsLib(configs.loggerCreator);
52
+
53
+ //...
54
+ }
55
+ ```
56
+
57
+ Le but étant que toutes les librairies utilisées dans un projet d'API, ainsi que leurs propres librairies
58
+ transitives, puissent logger de la même manière et aient accès aux bons Correlation Ids.
59
+
60
+ Finalement, notez qu'une fonction "`isInited()`" est exportée et permet au code appelant de valider que la librairie a été
61
+ configurée correctement!
62
+
63
+ # Builder le projet
64
+
65
+ **Note**: Sur Linux/Mac assurz-vous que le fichier `run` est exécutable. Autrement, lancez `chmod +x ./run`.
66
+
67
+ Pour lancer le build :
68
+
69
+ - > `run compile` ou `./run compile` (sur Linux/Mac)
70
+
71
+ Pour lancer les tests :
72
+
73
+ - > `run test` ou `./run test` (sur Linux/Mac)
74
+
75
+ # Mode Watch
76
+
77
+ Lors du développement, il est possible de lancer `run watch` (ou `./run watch` sur Linux/mac) dans un terminal
78
+ externe pour démarrer la compilation incrémentale. Il est alors possible de lancer certaines _launch configuration_
79
+ comme `Debug current tests file - fast` dans VsCode et ainsi déboguer le fichier de tests présentement ouvert sans
80
+ avoir à (re)compiler au préalable (la compilation incrémentale s'en sera chargé).
81
+
82
+ Notez que, par défaut, des _notifications desktop_ sont activées pour indiquer visuellement si la compilation
83
+ incrémentale est un succès ou si une erreur a été trouvée. Vous pouvez désactiver ces notifications en utilisant
84
+ `run watch --dn` (`d`isable `n`otifications).
85
+
86
+ # Déboguer le projet
87
+
88
+ Trois "_launch configurations_" sont founies pour déboguer le projet dans VSCode :
89
+
90
+ - "`Debug all tests`", la launch configuration par défaut. Lance les tests en mode debug. Vous pouvez mettre
91
+ des breakpoints et ils seront respectés.
92
+
93
+ - "`Debug a test file`". Lance _un_ fichier de tests en mode debug. Vous pouvez mettre
94
+ des breakpoints et ils seront respectés. Pour changer le fichier de tests à être exécuté, vous devez modifier la ligne appropriée dans le fichier "`.vscode/launch.json`".
95
+
96
+ - "`Debug current tests file`". Lance le fichier de tests _présentement ouvert_ dans VSCode en mode debug. Effectue la compîlation au préalable.
97
+
98
+ - "`Debug current tests file - fast`". Lance le fichier de tests _présentement ouvert_ dans VSCode en mode debug. Aucune compilation
99
+ n'est effectuée au préalable. Cette launch configuration doit être utilisée lorsque la compilation incrémentale roule (voir la section "`Mode Watch`" plus haut)
100
+
101
+ # Gérer les transactions SQL dans son projet/API
102
+
103
+ Dans cette librairie est fourni un composant nommé `KnexTransactionManager` permettant d'exécuter
104
+ plusieures requêtes SQL au sein d'une même transaction. Si une des requêtes échoue,
105
+ toutes les requêtes déjà effectuées seront rollbackées. En d'autres mots, toutes les requêtes doivent
106
+ résulter en un succès ou _aucune_ ne sera commitée.
107
+
108
+ Le pattern utilisé pour arriver à gérer de telles transactions est de passer un `context` (implémentant
109
+ l'interface `IDatabaseContext`) _à chaque méthodes suceptible d'exécuter, directement ou indirectement, une requête SQL_.
110
+ En gros, il s'agit de passer l'object `context`, que nous recevrons nous-mêmes, à toutes les
111
+ méthodes de _services_ ou de _repositories_ que nous appellons.
112
+
113
+ Il est fortement recommandé que ce paramètre `context` soit _toujours_ le premier dans la signature d'une méthode.
114
+ Par exemple, dans un service fictif `UserService`, il pourrait y avoir une méthode `updateUser`
115
+ prennant ce `context` comme premier paramètre:
116
+
117
+ ```typescript
118
+ public async updateUser(context: IAppContext, userId: number, userToUpdate: IUser) {
119
+
120
+ // On démarre un scope de transaction avec `withTransaction`
121
+ await txManager.withTransaction(context, async (client: knex.Transaction) => {
122
+
123
+ // Appel à une repository, en lui passant le contexte
124
+ const updatedUser = await userRepository.updateUser(context, userId, userToUpdate);
125
+
126
+ // Appel à un autre service, en lui passant le contexte
127
+ await indexationService.updateUserIndex(context, updatedUser);
128
+
129
+ // Fait une requête SQL directement en utilisant
130
+ // le client fourni par `withTransaction`!
131
+ const res = await client(`statistics`).insert({
132
+ something: 'blablabla'
133
+ });
134
+ });
135
+ }
136
+ ```
137
+
138
+ Dans cet exemple on voit que:
139
+
140
+ - la méthode `updateUser` du service reçoit un `context` comme premier paramètre. C'est ce
141
+ `context` qu'elle devra elle-même passer aux autres méthodes qu'elles appellera. Vous
142
+ avez peut-être remarqué que le type de ce `context` est ici `IAppContext` et non `IDatabaseContext`!
143
+ Il est en effet fréquent qu'une application crée son propre type de context
144
+ _implémentant `IDatabaseContext`_. Ceci lui permet de passer des informations supplémentaires,
145
+ de méthode en méthode! Par exemple, ce context spécialisé pourrait comprendre le `JWT` reçu lors de
146
+ la requête HTTP, les paramètres de cette requête HTTP, etc. Par exemple:
147
+ ```typescript
148
+ export interface IAppContext extends IDatabaseContext {
149
+ jwt: IJWTPayload;
150
+ }
151
+ ```
152
+ - Les appels devant faire partie d'une même transaction sont exécutés dans le "scope" de
153
+ `txManager.withTransaction(...)`. Le code appellé reçoit un `client knex`, et c'est
154
+ ce client qu'il doit utiliser pour effectuer ses requêtes SQL. Dans notre exemple, le service
155
+ ne fait une seule requête SQL par lui-même: `client("statistics").insert(...)`. Mais il passe
156
+ son `context` à une repossitory et à un autre service pour que la transaction qu'il a démarrée soit
157
+ poursuivie correctement par ces composants.
158
+
159
+ Il faut savoir que la création de l'objet `context` _original_, celui qui devra par la suite être
160
+ passé de méthode en méthode, se fait en général _dans le contrôleur_ qui reçoit une requête HTTP.
161
+ Ce `context` initial aura sa propriété `currentKnexClient` non définie. C'est le premier appel à
162
+ `withClient` ou `withTransaction` qui s'occupera de le populer (puis de le tenir à jour).
163
+
164
+ Notez qu'en plus de `withTransaction`, le composant `KnexTransactionManager` fournit aussi une méthode
165
+ `withClient`. L'utilisation est la même, à la différence près qu'aucune transaction n'est
166
+ démarrée avec `withClient`. Ceci dit, il est possible que la méthode où s'effectue la requête
167
+ ne nécessitant pas de transaction _ait elle-même été appellée au sein d'un `withTransaction`_, bref dans le scope d'une transaction, par du code appelant! Dans cette situation, en utilisant le client knex fourni par `withClient`,
168
+ la transaction se poursuivra correctement. C'est pour cette raison qu'il faut _toujours_ utiliser
169
+ le client knex fourni par `withClient` et non un client knex créé manuellement...
170
+ `withClient` et `withTransaction` inspectent le `context` qui leur est passé et retourne un client
171
+ knex bien configuré, selon la situation.
172
+
173
+ Notez aussi que si `withTransaction` est appellée mais que le code est _déjà_ dans le scope
174
+ d'une transaction démarrée par du code appelant, la transaction déjà existante se poursuivera.
175
+ Il n'y aura pas de nouvelle transaction de démarrée.
176
+
177
+ Notez finalement qu'il peut être intéressant de wrapper les méthodes du `KnexTransactionManager`
178
+ dans des méthodes custom, pour simplifier et modifier leur utilisation. Par exemple:
179
+
180
+ ```typescript
181
+ public async withTransaction<T>(
182
+ context: IAppContext,
183
+ fnt: (client: knex.Transaction) => Promise<T>
184
+ ): Promise<T> {
185
+ return this.getKnexTransactionManager().withTransaction<T>(context, async (client: knex) => {
186
+ try {
187
+ return await fnt(client as any);
188
+ } catch (err) {
189
+ // ==========================================
190
+ // Ici, nous pourrions avoir du code convertissant
191
+ // les erreurs BD en erreur d'API standardisées,
192
+ // par exemple.
193
+ // ==========================================
194
+ throw createErrorFromDatabaseError(err);
195
+ }
196
+ });
197
+ }
198
+ ```
199
+
200
+ Par la suite:
201
+
202
+ ```typescript
203
+ // Utilisation de notre méthode `withTransaction` custom.
204
+ await withTransaction(context, async (client: knex.Transaction) => {
205
+ const res = await client(`statistics`).insert({
206
+ something: 'blablabla',
207
+ });
208
+ });
209
+ ```
210
+
211
+ **NOTE**: Voir le fichier de tests `src/transactionManager.test.ts` pour un exemple d'utilisation
212
+ du `KnexTransactionManager`.
213
+
214
+ # Versions et compatibilité
215
+
216
+ ### 5.0.0
217
+
218
+ Utilise la version 5.0.0 de sqlite3
219
+
220
+ #### Compatibilité
221
+
222
+ - NodeJS : 16
223
+
224
+ # Test et publication de la librairie sur Nexus
225
+
226
+ En mergant une pull request dans la branche `develop`, un artifact "`-pre.build`" sera créé automatiquement dans Nexus. Vous
227
+ pouvez utiliser cette version temporaire de la librairie pour bien la tester dans un réel projet.
228
+
229
+ Une fois mergée dans `master`, la librairie est définitiement publiée dans Nexus, en utilisant la version spécifiée dans
230
+ le `package.json`.
231
+
232
+ # Aide / Contributions
233
+
234
+ Pour obtenir de l'aide avec cette librairie, vous pouvez poster sur la salle Google Chat [dev-discussions](https://chat.google.com/room/AAAASmiQveI).
235
+
236
+ Notez que les contributions sous forme de pull requests sont bienvenues.
@@ -0,0 +1,19 @@
1
+ import { ILogger } from '@villedemontreal/logger';
2
+ export declare class Configs {
3
+ /**
4
+ * Absolute path to the root of the project.
5
+ */
6
+ root: string;
7
+ constructor();
8
+ private _loggerCreator;
9
+ /**
10
+ * The Logger creator
11
+ */
12
+ get loggerCreator(): (name: string) => ILogger;
13
+ /**
14
+ * Sets the Logger creator.
15
+ */
16
+ setLoggerCreator(loggerCreator: (name: string) => ILogger): void;
17
+ }
18
+ export declare const configs: Configs;
19
+ //# sourceMappingURL=configs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configs.d.ts","sourceRoot":"","sources":["../../../src/config/configs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGlD,qBAAa,OAAO;IAClB;;OAEG;IACI,IAAI,EAAE,MAAM,CAAC;;IAMpB,OAAO,CAAC,cAAc,CAA4B;IAElD;;OAEG;IACH,IAAI,aAAa,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAK7C;IAED;;OAEG;IACI,gBAAgB,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO;CAGjE;AAED,eAAO,MAAM,OAAO,EAAE,OAAuB,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configs = exports.Configs = void 0;
4
+ const path = require("path");
5
+ class Configs {
6
+ constructor() {
7
+ this.root = path.normalize(`${__dirname}/../../..`);
8
+ }
9
+ /**
10
+ * The Logger creator
11
+ */
12
+ get loggerCreator() {
13
+ if (!this._loggerCreator) {
14
+ throw new Error(`The Logger Creator HAS to be set as a configuration`);
15
+ }
16
+ return this._loggerCreator;
17
+ }
18
+ /**
19
+ * Sets the Logger creator.
20
+ */
21
+ setLoggerCreator(loggerCreator) {
22
+ this._loggerCreator = loggerCreator;
23
+ }
24
+ }
25
+ exports.Configs = Configs;
26
+ exports.configs = new Configs();
27
+ //# sourceMappingURL=configs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configs.js","sourceRoot":"","sources":["../../../src/config/configs.ts"],"names":[],"mappings":";;;AACA,6BAA6B;AAE7B,MAAa,OAAO;IAMlB;QACE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,SAAS,WAAW,CAAC,CAAC;IACtD,CAAC;IAID;;OAEG;IACH,IAAI,aAAa;QACf,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,gBAAgB,CAAC,aAAwC;QAC9D,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;IACtC,CAAC;CACF;AA5BD,0BA4BC;AAEY,QAAA,OAAO,GAAY,IAAI,OAAO,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Application constants
3
+ */
4
+ export declare class Constants {
5
+ /**
6
+ * The library root. When this library is used
7
+ * as a dependency in a project, the "libRoot"
8
+ * will be the path to the dependency folder,
9
+ * inside the "node_modules".
10
+ */
11
+ libRoot: string;
12
+ /**
13
+ * The app root. When this library is used
14
+ * as a dependency in a project, the "appRoot"
15
+ * will be the path to the root project!
16
+ */
17
+ appRoot: string;
18
+ constructor();
19
+ }
20
+ export declare const constants: Constants;
21
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/config/constants.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,qBAAa,SAAS;IACpB;;;;;OAKG;IACI,OAAO,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACI,OAAO,EAAE,MAAM,CAAC;;CAOxB;AAED,eAAO,MAAM,SAAS,EAAE,SAA2B,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.constants = exports.Constants = void 0;
4
+ // ==========================================
5
+ // Application constants
6
+ // ==========================================
7
+ const app_root_path_1 = require("app-root-path");
8
+ const path = require("path");
9
+ /**
10
+ * Application constants
11
+ */
12
+ class Constants {
13
+ constructor() {
14
+ // From the "dist/src/config" folder
15
+ this.libRoot = path.normalize(__dirname + '/../../..');
16
+ this.appRoot = app_root_path_1.path;
17
+ }
18
+ }
19
+ exports.Constants = Constants;
20
+ exports.constants = new Constants();
21
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/config/constants.ts"],"names":[],"mappings":";;;AAAA,6CAA6C;AAC7C,wBAAwB;AACxB,6CAA6C;AAC7C,iDAAgD;AAChD,6BAA6B;AAE7B;;GAEG;AACH,MAAa,SAAS;IAgBpB;QACE,oCAAoC;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,GAAG,oBAAO,CAAC;IACzB,CAAC;CACF;AArBD,8BAqBC;AAEY,QAAA,SAAS,GAAc,IAAI,SAAS,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { ILogger } from '@villedemontreal/logger';
2
+ /**
3
+ * Inits the library.
4
+ */
5
+ export declare function init(loggerCreator: (name: string) => ILogger): void;
6
+ /**
7
+ * Is the library properly initialized?
8
+ *
9
+ * This function MUST be named "isInited()"!
10
+ * Code using this library may loop over all its "@villemontreal"
11
+ * dependencies and, if one of those exports a "isInited" fonction,
12
+ * it will enforce that the lib has been properly initialized before
13
+ * starting...
14
+ */
15
+ export declare function isInited(): boolean;
16
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/config/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAKlD;;GAEG;AACH,wBAAgB,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,QAW5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.init = init;
4
+ exports.isInited = isInited;
5
+ const configs_1 = require("./configs");
6
+ let libIsInited = false;
7
+ /**
8
+ * Inits the library.
9
+ */
10
+ function init(loggerCreator) {
11
+ if (!loggerCreator) {
12
+ throw new Error(`The Logger Creator is required.`);
13
+ }
14
+ configs_1.configs.setLoggerCreator(loggerCreator);
15
+ // ==========================================
16
+ // Set as being "properly initialized".
17
+ // At the very end of the "init()" function!
18
+ // ==========================================
19
+ libIsInited = true;
20
+ }
21
+ /**
22
+ * Is the library properly initialized?
23
+ *
24
+ * This function MUST be named "isInited()"!
25
+ * Code using this library may loop over all its "@villemontreal"
26
+ * dependencies and, if one of those exports a "isInited" fonction,
27
+ * it will enforce that the lib has been properly initialized before
28
+ * starting...
29
+ */
30
+ function isInited() {
31
+ return libIsInited;
32
+ }
33
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/config/init.ts"],"names":[],"mappings":";;AAQA,oBAWC;AAWD,4BAEC;AA/BD,uCAAoC;AAEpC,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB;;GAEG;AACH,SAAgB,IAAI,CAAC,aAAwC;IAC3D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,iBAAO,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAExC,6CAA6C;IAC7C,uCAAuC;IACvC,4CAA4C;IAC5C,6CAA6C;IAC7C,WAAW,GAAG,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,QAAQ;IACtB,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Knex } from 'knex';
2
+ /**
3
+ * A Context that can be used to get the current database
4
+ * client, if any. This allows the use of nested transactions.
5
+ */
6
+ export interface IDatabaseContext {
7
+ currentKnexClient?: Knex;
8
+ }
9
+ //# sourceMappingURL=databaseContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"databaseContext.d.ts","sourceRoot":"","sources":["../../src/databaseContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iBAAiB,CAAC,EAAE,IAAI,CAAC;CAC1B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=databaseContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"databaseContext.js","sourceRoot":"","sources":["../../src/databaseContext.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ export * from './config/init';
2
+ export * from './databaseContext';
3
+ export * from './knexUtils';
4
+ export * from './transactionManager';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ // ==========================================
18
+ // We do not export the configs instance itself,
19
+ // only the "init()" method, so we can define
20
+ // which are the required parameters.
21
+ // ==========================================
22
+ __exportStar(require("./config/init"), exports);
23
+ __exportStar(require("./databaseContext"), exports);
24
+ __exportStar(require("./knexUtils"), exports);
25
+ __exportStar(require("./transactionManager"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA6C;AAC7C,gDAAgD;AAChD,6CAA6C;AAC7C,qCAAqC;AACrC,6CAA6C;AAC7C,gDAA8B;AAC9B,oDAAkC;AAClC,8CAA4B;AAC5B,uDAAqC"}
@@ -0,0 +1,134 @@
1
+ import { IPaginatedResult } from '@villedemontreal/general-utils';
2
+ import { Knex } from 'knex';
3
+ import * as sinon from 'sinon';
4
+ /**
5
+ * Knex utilities
6
+ */
7
+ export declare class KnexUtils {
8
+ protected static KNEX_TOTAL_COUNT_QUERY_COLUMN_NAME: string;
9
+ protected static TOTAL_COUNT_BUILDER_OPTION_NAME: string;
10
+ /**
11
+ * Takes a Knex.QueryBuilder, which is the object created
12
+ * when defining a Knex query, an returns the rows total count.
13
+ *
14
+ * This function is useful when you already have a SELECT Knex query,
15
+ * but you only need the rows total count instead of the rows themselves!
16
+ *
17
+ * Warning!! This function only works with SELECT queries, and
18
+ * may fail in some untested complex situations... It only has
19
+ * been tested with simple select/from/where/orderBy queries.
20
+ *
21
+ * Example :
22
+ *
23
+ * const queryBuilder = client
24
+ * .from(BOOKS_TABLE_NAME)
25
+ * .orderBy("author");
26
+ *
27
+ * ... and then, instead of executing the query, by using
28
+ * "then()" or "await", you pass the builder to the
29
+ * "totalCount()" function :
30
+ *
31
+ * let totalCount: number = await knexUtils.totalCount(client, queryBuilder);
32
+ *
33
+ */
34
+ totalCount(knex: Knex, selectBuilder: Knex.QueryBuilder): Promise<number>;
35
+ /**
36
+ * Takes a Knex.QueryBuilder, which is the object created
37
+ * when defining a Knex query, a limit and a current
38
+ * page, then return a IPaginatedResult.
39
+ *
40
+ * In other words, instead of executing the query you
41
+ * are building with Knex directly, you pass the unsent
42
+ * builder to this function and you get :
43
+ * - Pagination for your query
44
+ * - The total number of elements your query would return if it
45
+ * wasn't paginated.
46
+ *
47
+ * Warning!! This function only works with SELECT queries, and
48
+ * may fail in some untested complex situations... It only has
49
+ * been tested with simple select/from/where/orderBy queries.
50
+ *
51
+ * If this function fails for one of your query, you'll have to
52
+ * duplicate the code of that query to make two separate queries :
53
+ * one for the rows only and one for the total count only.
54
+ *
55
+ * For example, to get 3 items starting at offset 9 :
56
+ *
57
+ * const paginatedResult = await knexUtils.paginate(
58
+ * client,
59
+ * client
60
+ * .select("id", "author", "title")
61
+ * .from(BOOKS_TABLE_NAME)
62
+ * .orderBy("author"),
63
+ * 9, 3);
64
+ */
65
+ paginate(knex: Knex, selectBuilder: Knex.QueryBuilder, offset: number, limit: number): Promise<IPaginatedResult<any>>;
66
+ /**
67
+ * Creates a mocked Knex client, linked to a dummy database.
68
+ * The client allows you to define stubs that will simulate
69
+ * the result from the DB.
70
+ *
71
+ * Useful for testing!
72
+ */
73
+ createKnexMockedClient: () => Promise<IKnexMockedClient>;
74
+ /**
75
+ * For Oracle.
76
+ * Wraps a column name (or a "?") with LOWER or with a CONVERT function
77
+ * which will strip accents.
78
+ */
79
+ wrapWithOracleModificationkeywords(columnNameOrInterrogationMark: string, isConvert: boolean, isLower: boolean): string;
80
+ /**
81
+ * For Oracle.
82
+ * Adds a LIKE clause, where the values can be compared lowercased (isLower), by removing the
83
+ * accents first (isConvert), and where the "val" can starts or ends with a "*" wildcard.
84
+ */
85
+ addOracleLikeClause(queryBuilder: Knex.QueryBuilder, columnName: string, val: string, isConvert: boolean, isLower: boolean): Knex.QueryBuilder;
86
+ /**
87
+ * For SQL Server.
88
+ * Wraps a column name (or a "?") with LOWER and/or with a CAST function
89
+ * which will strip accents.
90
+ */
91
+ wrapWithSqlServerModificationKeywords(columnNameOrInterrogationMark: string, isConvert: boolean, isLower: boolean): string;
92
+ /**
93
+ * For SQL Server.
94
+ * Adds a LIKE clause, where the values can be compared lowercased (lower), by removing the
95
+ * accents first (removeAccent), and where the "val" can starts or ends with a "*" wildcard
96
+ * (acceptWildcard).
97
+ */
98
+ addSqlServerLikeClause(queryBuilder: Knex.QueryBuilder, columnName: string, val: string, acceptWildcard: boolean, removeAccents: boolean, lower: boolean): Knex.QueryBuilder;
99
+ /**
100
+ * @param totalCountOnly if true, only the request to get the total count will
101
+ * be made and an empty array will be returned as the rows.
102
+ */
103
+ protected paginateOrTotalCount(knex: Knex, selectBuilder: Knex.QueryBuilder, offset: number, limit: number, totalCountOnly?: boolean): Promise<IPaginatedResult<any>>;
104
+ }
105
+ export declare const knexUtils: KnexUtils;
106
+ /**
107
+ * A Mocked Knex client.
108
+ */
109
+ export interface IKnexMockedClient extends Knex {
110
+ /**
111
+ * The stub that is going to return the result
112
+ * when the query is executed.
113
+ *
114
+ * Defaults to an empty array.
115
+ */
116
+ resultStub: sinon.SinonStub;
117
+ /**
118
+ * If the query is paginated, this stub
119
+ * will return the "totalCount" part of
120
+ * the result.
121
+ *
122
+ * Defaults to 0.
123
+ */
124
+ totalCountStub: sinon.SinonStub;
125
+ /**
126
+ * This spy is going to be called just before
127
+ * Knex actually execute the query. The builder
128
+ * has at this point been converted to a
129
+ * SQL string and you have access to this SQL and
130
+ * other informations.
131
+ */
132
+ beforeQuerySpy: sinon.SinonSpy;
133
+ }
134
+ //# sourceMappingURL=knexUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knexUtils.d.ts","sourceRoot":"","sources":["../../src/knexUtils.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gBAAgB,EAAS,MAAM,gCAAgC,CAAC;AAEzE,OAAa,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B;;GAEG;AACH,qBAAa,SAAS;IACpB,SAAS,CAAC,MAAM,CAAC,kCAAkC,SAAW;IAC9D,SAAS,CAAC,MAAM,CAAC,+BAA+B,SAAyB;IAEzE;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACU,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAKtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACU,QAAQ,CACnB,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,IAAI,CAAC,YAAY,EAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAKjC;;;;;;OAMG;IACI,sBAAsB,QAAa,OAAO,CAAC,iBAAiB,CAAC,CAsFlE;IAEF;;;;OAIG;IACI,kCAAkC,CACvC,6BAA6B,EAAE,MAAM,EACrC,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,OAAO,GACf,MAAM;IAaT;;;;OAIG;IACI,mBAAmB,CACxB,YAAY,EAAE,IAAI,CAAC,YAAY,EAC/B,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,OAAO,GACf,IAAI,CAAC,YAAY;IAgCpB;;;;OAIG;IACI,qCAAqC,CAC1C,6BAA6B,EAAE,MAAM,EACrC,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,OAAO,GACf,MAAM;IA0BT;;;;;OAKG;IACI,sBAAsB,CAC3B,YAAY,EAAE,IAAI,CAAC,YAAY,EAC/B,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,OAAO,EACvB,aAAa,EAAE,OAAO,EACtB,KAAK,EAAE,OAAO,GACb,IAAI,CAAC,YAAY;IAmCpB;;;OAGG;cACa,oBAAoB,CAClC,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,IAAI,CAAC,YAAY,EAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,cAAc,UAAQ,GACrB,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;CAiFlC;AACD,eAAO,MAAM,SAAS,EAAE,SAA2B,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI;IAC7C;;;;;OAKG;IACH,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAE5B;;;;;;OAMG;IACH,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC;IAEhC;;;;;;OAMG;IACH,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC;CAChC"}