vsrepo 1.0.0 → 1.0.2

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.
@@ -0,0 +1,1112 @@
1
+ /*
2
+ * BEM VINDO AO CÓDIGO DO VSREPOSITORY!!!
3
+ * Esse código foi totalmente desenvolvido apenas por João Pedro Azevedo
4
+ * O código não tá muito organizado, dá pra melhorar muito, mas já ta funcionando bunitin
5
+ */
6
+
7
+ // * Exportando classes de erro
8
+ export * from "./VSRepoError.js";
9
+
10
+ // * Importando classes de erro
11
+ import { VSRepoConfigError, VSRepoBuildError, VSRepoExtendError, VSRepoRuntimeError } from "./VSRepoError.js";
12
+
13
+ // * Essa é a classe pincipal, é a partir dela que serão criados os objetos dos repositories
14
+ export class VSRepository {
15
+
16
+ // * O vsrepocache é um Map que serve para cachear onde os argumentos dos métodos gerados dinamicamente devem ser injetados, retornando todos os argumentos do Prisma já organizados
17
+ vsrepocache;
18
+ // * tableName serve para saber qual o nome da tabela que deverá ser injetado na função do prisma q será chamada
19
+ tableName;
20
+ // * Nome da primary key da tabela para o get, o remove e o save funcionarem corretamente
21
+ pkName;
22
+ // * Aqui são os modelos de select que poderão ser usados no seu repository
23
+ selectModels;
24
+ // * Aqui é onde você define qual é o modelo principal que deve ser injetado nos métodos, porém você pode escolher outro ao criar ou ao chamar o método (OBS: se o defaultSelectModel não for fornecido e não passar um model no método o select será undefined e o prisma retornará as colunas padrão)
25
+ defaultSelectModel;
26
+ relations;
27
+ requiredWhere;
28
+ methods;
29
+
30
+ constructor(config) {
31
+ if(typeof config !== 'object' || config === null){
32
+ throw new VSRepoConfigError(`[VSRepository] (config) 'config' must be a valid object.`);
33
+ }
34
+ if(typeof config.tableName !== 'string') {
35
+ throw new VSRepoConfigError(`[VSRepository] (config) 'tableName' must be a valid string.`);
36
+ }
37
+ if(typeof config.pkName !== 'string') {
38
+ throw new VSRepoConfigError(`[VSRepository] (config) 'pkName' must be a valid string.`);
39
+ }
40
+ if(config.selectModels !== undefined && typeof config.selectModels !== 'object' || config.selectModels === null) {
41
+ throw new VSRepoConfigError(`[VSRepository] (config) 'selectModels' must be a valid object.`);
42
+ }
43
+ if(config.defaultSelectModel !== undefined) {
44
+ if(!config.selectModels) {
45
+ throw new VSRepoConfigError(`[VSRepository] (config) 'defaultSelectModel' can only be passed with 'selectModels'.`);
46
+ }
47
+ if(typeof config.defaultSelectModel !== 'string') {
48
+ throw new VSRepoConfigError(`[VSRepository] (config) 'defaultSelectModel' must be a valid string.`);
49
+ }
50
+ if(!Object.keys(config.selectModels).includes(config.defaultSelectModel)){
51
+ throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'defaultSelectModel': ${config.defaultSelectModel}`);
52
+ }
53
+ }
54
+ if(config.relations !== undefined) {
55
+ const relations = config.relations;
56
+ if(typeof relations !== 'object' || relations === null){
57
+ throw new VSRepoConfigError(`[VSRepository] (config) 'relations' must be a valid object.`);
58
+ }
59
+
60
+ for (const key of Object.keys(relations)) {
61
+ const relation = relations[key];
62
+ if(typeof relation.pk !== 'string'){
63
+ throw new VSRepoConfigError(`[VSRepository] (config) The property 'pk' of relation '${key}' must be a string.`);
64
+ }
65
+ if(typeof relation.mode !== 'string'){
66
+ throw new VSRepoConfigError(`[VSRepository] (config) The property 'mode' of relation '${key}' must be 'otm', 'mtm', 'mto' or 'oto'.`);
67
+ }
68
+ if(typeof relation.restriction !== 'string'){
69
+ throw new VSRepoConfigError(`[VSRepository] (config) The property 'restriction' of relation '${key}' must be 'set' or 'add'.`);
70
+ }
71
+ }
72
+ }
73
+ if(config.requiredWhere !== undefined && typeof config.requiredWhere !== 'object' || config.requiredWhere === null) {
74
+ throw new VSRepoConfigError(`[VSRepository] (config) 'requiredWhere' must be a valid object.`);
75
+ }
76
+ if(config.methods !== undefined) {
77
+ if(typeof config.methods !== 'object' || config.methods === null){
78
+ throw new VSRepoConfigError(`[VSRepository] (config) 'methods' must be a valid object.`);
79
+ } else {
80
+ for (const [key, value] of Object.entries(config.methods)) {
81
+
82
+ if(typeof value.map !== "boolean") {
83
+ throw new VSRepoConfigError(`[VSRepository] (config) 'map' on ${key} must be a valid boolean.`);
84
+ }
85
+
86
+ if(value.whereType !== undefined && !['extending', 'overwrite'].includes(value.whereType)){
87
+ throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'whereType' on ${key}: ${value.whereType}`);
88
+ }
89
+
90
+ if(value.selectModel !== undefined && value.selectModel !== false && (!config.selectModels || !Object.keys(config.selectModels).includes(value.selectModel))){
91
+ throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'selectModel' on ${key}: ${value.selectModel}`);
92
+ }
93
+
94
+ if(value.proxyTo !== undefined && typeof value.proxyTo !== 'string') {
95
+ throw new VSRepoConfigError(`[VSRepository] (config) 'proxyTo' on ${key} must be a valid string.`);
96
+ }
97
+
98
+ if(value.fbMode !== undefined && !['one', 'list'].includes(value.fbMode)) {
99
+ throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'fbMode' on ${key}: ${value.whereType}`);
100
+ }
101
+
102
+ if(value.pushWhere !== undefined && (typeof value.pushWhere !== 'object' || value.pushWhere === null)) {
103
+ throw new VSRepoConfigError(`[VSRepository] (config) 'pushWhere' on ${key} must be a valid object.`);
104
+ }
105
+
106
+ if(value.injectOrdenation !== undefined && (typeof value.injectOrdenation !== 'object' || value.injectOrdenation === null)) {
107
+ throw new VSRepoConfigError(`[VSRepository] (config) 'injectOrdenation' on ${key} must be a valid object or array.`);
108
+ }
109
+
110
+ if(value.injectPagination !== undefined && (typeof value.injectPagination !== 'object' || value.injectPagination === null)) {
111
+ throw new VSRepoConfigError(`[VSRepository] (config) 'injectPagination' on ${key} must be a valid object.`);
112
+ }
113
+
114
+ }
115
+ }
116
+ }
117
+
118
+ this.vsrepocache = new Map();
119
+ this.tableName = config.tableName;
120
+ this.pkName = config.pkName;
121
+ this.selectModels = config.selectModels;
122
+ this.defaultSelectModel = config.defaultSelectModel;
123
+ this.relations = config.relations;
124
+ this.requiredWhere = config.requiredWhere;
125
+ this.methods = config.methods ?? {};
126
+ }
127
+
128
+ extend(extensionFunc) {
129
+ if(typeof extensionFunc !== 'function'){
130
+ throw new VSRepoExtendError(`[VSRepository] (extend) 'extensionFunc' must be a valid funcion.`);
131
+ }
132
+ const extension = extensionFunc(this);
133
+ if(typeof extension !== 'object' || extension === null){
134
+ throw new VSRepoExtendError(`[VSRepository] (extend) The return of the 'extensionFunc' must be a valid object.`)
135
+ }
136
+
137
+ const extended = Object.assign(Object.create(this), extension);
138
+
139
+ if(Object.isFrozen(this)) {
140
+ Object.freeze(extended);
141
+ }
142
+
143
+ return extended;
144
+ }
145
+
146
+ build(prisma, config = {}) {
147
+ const showWorking = config.showWorking;
148
+
149
+ if(typeof config !== 'object' || config === null) {
150
+ throw new VSRepoBuildError(`[VSRepository] (build) 'config' must be a valid object.`);
151
+ }
152
+ if(config.freeze === undefined) {
153
+ config.freeze = true;
154
+ }
155
+
156
+ const relationsKeys = this.relations ? Object.keys(this.relations) : [];
157
+
158
+ const methods = this.methods;
159
+ const repositoryKeysToMap = Object.keys(methods);
160
+
161
+ if(showWorking) {
162
+ console.log(`[VSRepository] (build) Keys to map:`, JSON.stringify(repositoryKeysToMap, null, 2));
163
+ }
164
+
165
+ for (let keyToMap of repositoryKeysToMap) {
166
+
167
+ let onlyBaseWheres = false;
168
+ let ignoreWhere = false;
169
+ let ignoreOrderByAndPagination = true;
170
+ let ignoreSelect = false;
171
+ let keyToMapReplaced;
172
+ let argsCount = 0;
173
+ let method;
174
+ let dataIndex;
175
+ let updateIndex;
176
+ let createIndex;
177
+ let originalKey = keyToMap;
178
+ keyToMap = methods[originalKey].proxyTo ?? keyToMap;
179
+ let existsMode = false;
180
+ let skipDuplicates;
181
+ let ignoreSkipDuplicates = true;
182
+ let whereIndex
183
+ const whereParams = [];
184
+ const otherParams = [];
185
+
186
+ if(keyToMap.startsWith('findUniqueBy')) {
187
+ keyToMapReplaced = keyToMap.replace('findUniqueBy', '');
188
+ method = 'findUnique';
189
+ } else if(keyToMap.startsWith('findFirstBy')) {
190
+ keyToMapReplaced = keyToMap.replace('findFirstBy', '')
191
+ ignoreOrderByAndPagination = false;
192
+ method = 'findFirst';
193
+ } else if(keyToMap.startsWith('findFirst')) {
194
+ keyToMapReplaced = keyToMap.replace('findFirst', '');
195
+ ignoreOrderByAndPagination = false;
196
+ ignoreWhere = true;
197
+ onlyBaseWheres = true;
198
+ method = 'findFirst';
199
+ } else if(keyToMap.startsWith('countBy')) {
200
+ keyToMapReplaced = keyToMap.replace('countBy', '');
201
+ ignoreOrderByAndPagination = false;
202
+ ignoreSelect = true;
203
+ method = 'count';
204
+ } else if(keyToMap.startsWith('count')) {
205
+ keyToMapReplaced = keyToMap.replace('count', '');
206
+ ignoreOrderByAndPagination = false;
207
+ ignoreSelect = true;
208
+ ignoreWhere = true;
209
+ onlyBaseWheres = true;
210
+ method = 'count';
211
+ } else if(keyToMap.startsWith('existsBy')) {
212
+ keyToMapReplaced = keyToMap.replace('existsBy', '');
213
+ ignoreSelect = true;
214
+ existsMode = true;
215
+ method = 'findFirst';
216
+ } else if(keyToMap.startsWith('findManyBy')) {
217
+ keyToMapReplaced = keyToMap.replace('findManyBy', '');
218
+ ignoreOrderByAndPagination = false;
219
+ method = 'findMany';
220
+ } else if(keyToMap.startsWith('findMany')) {
221
+ keyToMapReplaced = keyToMap.replace('findMany', '');
222
+ ignoreOrderByAndPagination = false;
223
+ ignoreWhere = true;
224
+ onlyBaseWheres = true;
225
+ method = 'findMany';
226
+ } else if(keyToMap.startsWith('createManyAndReturn')) {
227
+ keyToMapReplaced = keyToMap.replace('createManyAndReturn', '')
228
+ ignoreWhere = true;
229
+ ignoreSkipDuplicates = false;
230
+ method = 'createManyAndReturn';
231
+ dataIndex = 0;
232
+ otherParams.push('data');
233
+ argsCount++;
234
+ } else if(keyToMap.startsWith('createMany')) {
235
+ keyToMapReplaced = keyToMap.replace('createMany', '')
236
+ ignoreWhere = true;
237
+ ignoreSelect = true;
238
+ ignoreSkipDuplicates = false;
239
+ method = 'createMany';
240
+ dataIndex = 0;
241
+ otherParams.push('data');
242
+ argsCount++;
243
+ } else if(keyToMap.startsWith('create')) {
244
+ keyToMapReplaced = keyToMap.replace('create', '')
245
+ ignoreWhere = true;
246
+ method = 'create';
247
+ dataIndex = 0
248
+ otherParams.push('data');
249
+ argsCount++;
250
+ } else if(keyToMap.startsWith('updateManyAndReturnBy')) {
251
+ keyToMapReplaced = keyToMap.replace('updateManyAndReturnBy', '')
252
+ method = 'updateManyAndReturn';
253
+ dataIndex = -2;
254
+ otherParams.push('data');
255
+ argsCount++;
256
+ } else if(keyToMap.startsWith('updateManyBy')) {
257
+ keyToMapReplaced = keyToMap.replace('updateManyBy', '')
258
+ ignoreSelect = true;
259
+ method = 'updateMany';
260
+ dataIndex = -2;
261
+ otherParams.push('data');
262
+ argsCount++;
263
+ } else if(keyToMap.startsWith('updateBy')) {
264
+ keyToMapReplaced = keyToMap.replace('updateBy', '')
265
+ method = 'update';
266
+ dataIndex = -2;
267
+ otherParams.push('data');
268
+ argsCount++;
269
+ } else if(keyToMap.startsWith('upsertBy')) {
270
+ keyToMapReplaced = keyToMap.replace('upsertBy', '')
271
+ method = 'upsert';
272
+ createIndex = -2;
273
+ updateIndex = -3;
274
+ otherParams.push('update');
275
+ otherParams.push('create');
276
+ argsCount += 2;
277
+ } else if(keyToMap.startsWith('deleteManyBy')) {
278
+ keyToMapReplaced = keyToMap.replace('deleteManyBy', '')
279
+ ignoreSelect = true;
280
+ method = 'deleteMany';
281
+ } else if(keyToMap.startsWith('deleteBy')) {
282
+ keyToMapReplaced = keyToMap.replace('deleteBy', '')
283
+ method = 'delete';
284
+ } else if(keyToMap.startsWith('findWhere')) {
285
+ keyToMapReplaced = keyToMap.replace('findWhere', '');
286
+ ignoreOrderByAndPagination = false;
287
+ ignoreWhere = true;
288
+ onlyBaseWheres = true;
289
+ method = 'findFirst';
290
+ whereIndex = 0;
291
+ otherParams.push('where');
292
+ argsCount += 1;
293
+ } else if(keyToMap.startsWith('findListWhere')) {
294
+ keyToMapReplaced = keyToMap.replace('findListWhere', '');
295
+ ignoreOrderByAndPagination = false;
296
+ ignoreWhere = true;
297
+ onlyBaseWheres = true;
298
+ method = 'findMany';
299
+ whereIndex = 0;
300
+ otherParams.push('where');
301
+ argsCount += 1;
302
+ } else if(keyToMap.startsWith('findBy')) {
303
+ keyToMapReplaced = keyToMap.replace('findBy', '');
304
+ ignoreOrderByAndPagination = false;
305
+ method = methods[originalKey].fbMode === 'one' ? 'findFirst' : 'findMany';
306
+ } else {
307
+ throw new VSRepoBuildError(`[VSRepository] (build) Unknown method: ${keyToMap}.`);
308
+ }
309
+
310
+
311
+ if(!ignoreSkipDuplicates) {
312
+ if(keyToMapReplaced.endsWith('SkipDuplicates')) {
313
+ keyToMapReplaced = keyToMapReplaced.replace('SkipDuplicates', '');
314
+ skipDuplicates = true;
315
+ }
316
+ }
317
+
318
+ let orderPosition;
319
+ let paginationPosition;
320
+ let injectOrdenation;
321
+ let injectPagination;
322
+
323
+ if(!ignoreOrderByAndPagination) {
324
+ injectOrdenation = methods[originalKey].injectOrdenation;
325
+ injectPagination = methods[originalKey].injectPagination;
326
+
327
+ if(keyToMapReplaced.endsWith('PaginatedAndOrdered')) {
328
+ orderPosition = -2;
329
+ paginationPosition = -3;
330
+
331
+ otherParams.push('pagination');
332
+ otherParams.push('order');
333
+
334
+ keyToMapReplaced = keyToMapReplaced.replace('PaginatedAndOrdered', '')
335
+
336
+ argsCount+=2
337
+ } else if(keyToMapReplaced.endsWith('OrderedAndPaginated')) {
338
+ orderPosition = -3;
339
+ paginationPosition = -2;
340
+
341
+ otherParams.push('order');
342
+ otherParams.push('pagination');
343
+
344
+ keyToMapReplaced = keyToMapReplaced.replace('OrderedAndPaginated', '')
345
+
346
+ argsCount+=2
347
+ } else if(keyToMapReplaced.endsWith('Paginated')) {
348
+ paginationPosition = -2;
349
+
350
+ otherParams.push('pagination');
351
+
352
+ keyToMapReplaced = keyToMapReplaced.replace('Paginated', '')
353
+
354
+ argsCount++
355
+ } else if(keyToMapReplaced.endsWith('Ordered')) {
356
+ orderPosition = -2;
357
+
358
+ otherParams.push('order');
359
+
360
+ keyToMapReplaced = keyToMapReplaced.replace('Ordered', '')
361
+
362
+ argsCount++
363
+ }
364
+
365
+ }
366
+
367
+ const whereArgs = [];
368
+ let whereType = methods[originalKey].whereType ?? 'extending';
369
+ let pushWhere = methods[originalKey].pushWhere;
370
+ let whereResolved;
371
+
372
+ if(!ignoreWhere) {
373
+
374
+ function buildWhere(keySplitedAnd) {
375
+
376
+ const buildedWhere = {}
377
+ let nullMode;
378
+
379
+ if(keySplitedAnd.includes('IsNull')){
380
+ buildedWhere.pushProperty = '$$$';
381
+ buildedWhere.autoInjectVal = null;
382
+ nullMode = 'is';
383
+ keySplitedAnd = keySplitedAnd.replace('IsNull', '')
384
+ } else if(keySplitedAnd.includes('IsNotNull')){
385
+ buildedWhere.pushProperty = 'not';
386
+ buildedWhere.autoInjectVal = null;
387
+ nullMode = 'not';
388
+ keySplitedAnd = keySplitedAnd.replace('IsNotNull', '')
389
+ } else if(keySplitedAnd.includes('IsTrue')){
390
+ buildedWhere.pushProperty = '$$$';
391
+ buildedWhere.autoInjectVal = true;
392
+ keySplitedAnd = keySplitedAnd.replace('IsTrue', '')
393
+ } else if(keySplitedAnd.includes('IsFalse')){
394
+ buildedWhere.pushProperty = '$$$';
395
+ buildedWhere.autoInjectVal = false;
396
+ keySplitedAnd = keySplitedAnd.replace('IsFalse', '')
397
+ } else {
398
+ if(keySplitedAnd.includes('Insensitive')){
399
+ buildedWhere.properties = {}
400
+ buildedWhere.properties.mode = 'insensitive';
401
+ keySplitedAnd = keySplitedAnd.replace('Insensitive', '')
402
+ }
403
+
404
+ if(keySplitedAnd.includes('NotStartsWith')){
405
+ buildedWhere.pushProperty = 'not.startsWith';
406
+ keySplitedAnd = keySplitedAnd.replace('NotStartsWith', '')
407
+ } else if(keySplitedAnd.includes('StartsWith')){
408
+ buildedWhere.pushProperty = 'startsWith';
409
+ keySplitedAnd = keySplitedAnd.replace('StartsWith', '')
410
+ } else if(keySplitedAnd.includes('NotEndsWith')){
411
+ buildedWhere.pushProperty = 'not.endsWith';
412
+ keySplitedAnd = keySplitedAnd.replace('NotEndsWith', '')
413
+ } else if(keySplitedAnd.includes('EndsWith')){
414
+ buildedWhere.pushProperty = 'endsWith';
415
+ keySplitedAnd = keySplitedAnd.replace('EndsWith', '')
416
+ } else if(keySplitedAnd.includes('NotContains')){
417
+ buildedWhere.pushProperty = 'not.contains';
418
+ keySplitedAnd = keySplitedAnd.replace('NotContains', '')
419
+ } else if(keySplitedAnd.includes('Contains')){
420
+ buildedWhere.pushProperty = 'contains';
421
+ keySplitedAnd = keySplitedAnd.replace('Contains', '')
422
+ } else if(keySplitedAnd.includes('LessThanEqual')){
423
+ buildedWhere.pushProperty = 'lte';
424
+ keySplitedAnd = keySplitedAnd.replace('LessThanEqual', '')
425
+ } else if(keySplitedAnd.includes('LessThan')){
426
+ buildedWhere.pushProperty = 'lt';
427
+ keySplitedAnd = keySplitedAnd.replace('LessThan', '')
428
+ } else if(keySplitedAnd.includes('GreaterThanEqual')){
429
+ buildedWhere.pushProperty = 'gte';
430
+ keySplitedAnd = keySplitedAnd.replace('GreaterThanEqual', '')
431
+ } else if(keySplitedAnd.includes('GreaterThan')){
432
+ buildedWhere.pushProperty = 'gt';
433
+ keySplitedAnd = keySplitedAnd.replace('GreaterThan', '')
434
+ } else if(keySplitedAnd.includes('NotIn')){
435
+ buildedWhere.pushProperty = 'notIn';
436
+ keySplitedAnd = keySplitedAnd.replace('NotIn', '')
437
+ } else if(keySplitedAnd.includes('In')){
438
+ buildedWhere.pushProperty = 'in';
439
+ keySplitedAnd = keySplitedAnd.replace('In', '')
440
+ } else if(keySplitedAnd.includes('Not')){
441
+ buildedWhere.pushProperty = 'not';
442
+ keySplitedAnd = keySplitedAnd.replace('Not', '')
443
+ } else {
444
+ buildedWhere.pushProperty = '$$$';
445
+ }
446
+ }
447
+
448
+ function uncaptalize(text) {
449
+ return text[0].toLowerCase() + text.slice(1, text.length);
450
+ }
451
+
452
+ if(keySplitedAnd.includes('Without')){
453
+ const keySplitedConector = keySplitedAnd.split('Without');
454
+ const specificField = keySplitedConector[1];
455
+ if(!specificField) {
456
+ if (nullMode) {
457
+ buildedWhere.pushProperty = nullMode === 'not' ? 'is' : 'isNot';
458
+ } else {
459
+ buildedWhere.pushProperty = 'isNot';
460
+ buildedWhere.autoInjectVal = {};
461
+ }
462
+ } else {
463
+ buildedWhere.pushProperty = `isNot.${uncaptalize(specificField)}${buildedWhere.pushProperty === '$$$' ? '' : `.${buildedWhere.pushProperty}`}`;
464
+ }
465
+ keySplitedAnd = keySplitedConector[0];
466
+ } else if(keySplitedAnd.includes('With')){
467
+ const keySplitedConector = keySplitedAnd.split('With');
468
+ const specificField = keySplitedConector[1];
469
+ if(!specificField) {
470
+ if (nullMode) {
471
+ buildedWhere.pushProperty = nullMode === 'not' ? 'isNot' : 'is';
472
+ } else {
473
+ buildedWhere.pushProperty = 'is';
474
+ buildedWhere.autoInjectVal = {};
475
+ }
476
+ } else {
477
+ buildedWhere.pushProperty = `is.${uncaptalize(specificField)}${buildedWhere.pushProperty === '$$$' ? '' : `.${buildedWhere.pushProperty}`}`;
478
+ }
479
+ keySplitedAnd = keySplitedConector[0];
480
+ } else if(keySplitedAnd.includes('Some')){
481
+ const keySplitedConector = keySplitedAnd.split('Some');
482
+ const specificField = keySplitedConector[1];
483
+ if(!specificField) {
484
+ buildedWhere.pushProperty = 'some';
485
+ buildedWhere.autoInjectVal = {};
486
+ } else {
487
+ buildedWhere.pushProperty = `some.${uncaptalize(specificField)}${buildedWhere.pushProperty === '$$$' ? '' : `.${buildedWhere.pushProperty}`}`;
488
+ }
489
+ keySplitedAnd = keySplitedConector[0];
490
+ } else if(keySplitedAnd.includes('Every')){
491
+ const keySplitedConector = keySplitedAnd.split('Every');
492
+ const specificField = keySplitedConector[1];
493
+ if(!specificField) {
494
+ buildedWhere.pushProperty = 'every';
495
+ buildedWhere.autoInjectVal = {};
496
+ } else {
497
+ buildedWhere.pushProperty = `every.${uncaptalize(specificField)}${buildedWhere.pushProperty === '$$$' ? '' : `.${buildedWhere.pushProperty}`}`;
498
+ }
499
+ keySplitedAnd = keySplitedConector[0];
500
+ } else if(keySplitedAnd.includes('None')){
501
+ const keySplitedConector = keySplitedAnd.split('None');
502
+ const specificField = keySplitedConector[1];
503
+ if(!specificField) {
504
+ buildedWhere.pushProperty = 'none';
505
+ buildedWhere.autoInjectVal = {};
506
+ } else {
507
+ buildedWhere.pushProperty = `none.${uncaptalize(specificField)}${buildedWhere.pushProperty === '$$$' ? '' : `.${buildedWhere.pushProperty}`}`;
508
+ }
509
+ keySplitedAnd = keySplitedConector[0];
510
+ }
511
+
512
+ keySplitedAnd = uncaptalize(keySplitedAnd);
513
+
514
+ buildedWhere.name = keySplitedAnd;
515
+
516
+ return buildedWhere;
517
+
518
+ }
519
+
520
+ let ANDMode = false
521
+ let keysSplitedAND = keyToMapReplaced.split("AND");
522
+ if(keysSplitedAND.length > 1) {
523
+ ANDMode = true;
524
+ }
525
+
526
+ keysSplitedAND.forEach((keySplitedAND, idx)=>{
527
+
528
+ let orMode = false;
529
+ let keysSplitedOr = idx === 0 ? keySplitedAND.split('Or') : [keySplitedAND];
530
+ if(keysSplitedOr.length > 1){
531
+ orMode = true;
532
+ }
533
+
534
+ for (let i = 0; i < keysSplitedOr.length; i++) {
535
+
536
+ if(keysSplitedOr[i]==='') continue;
537
+
538
+ const keysSplitedAnd = keysSplitedOr[i].split('And')
539
+
540
+ for (const keySplitedAnd of keysSplitedAnd) {
541
+
542
+ if(keySplitedAnd==='') continue;
543
+
544
+ const buildedWhere = buildWhere(keySplitedAnd);
545
+
546
+ if(!orMode) {
547
+ if(idx === 1 && ANDMode){
548
+ buildedWhere.name = `AND.${i}idx.${buildedWhere.name}`;
549
+ }
550
+ whereArgs.push(buildedWhere);
551
+ } else {
552
+ buildedWhere.name = `OR.${i}idx.${buildedWhere.name}`;
553
+ whereArgs.push(buildedWhere);
554
+ }
555
+
556
+ if(showWorking) {
557
+ console.log(`[VSRepository] (build) Where object builded to ${keyToMap}:\n`, JSON.stringify(buildedWhere, null, 2));
558
+ }
559
+
560
+ if(buildedWhere.autoInjectVal === undefined) argsCount++;
561
+ }
562
+
563
+ }
564
+
565
+ });
566
+
567
+ whereResolved = whereArgs.map(arg=>{
568
+ let context = [];
569
+ let otherProps
570
+
571
+ let argName = arg.name;
572
+ const agrNameSplitedOr = argName.split('OR.')
573
+ if(agrNameSplitedOr.length > 1) {
574
+ const agrNameSplitedOrIdx = agrNameSplitedOr[1].split('idx.')
575
+ context.push('OR')
576
+ context.push(Number(agrNameSplitedOrIdx[0]))
577
+ argName = agrNameSplitedOrIdx[1]
578
+ } else {
579
+ const agrNameSplitedAND = argName.split('AND.');
580
+ if(agrNameSplitedAND.length > 1) {
581
+ const agrNameSplitedANDIdx = agrNameSplitedAND[1].split('idx.')
582
+ context.push('AND')
583
+ context.push(Number(agrNameSplitedANDIdx[0]))
584
+ argName = agrNameSplitedANDIdx[1];
585
+ }
586
+ }
587
+
588
+ context.push(argName)
589
+ if(arg.pushProperty !== '$$$'){
590
+ const pushProperty = arg.pushProperty;
591
+ const pushPropertySplitedDot = pushProperty.split('.');
592
+
593
+ pushPropertySplitedDot.forEach(prop=>context.push(prop));
594
+ }
595
+
596
+ if(arg.properties !== undefined) {
597
+ const propertiesKeys = Object.keys(arg.properties);
598
+ otherProps = {}
599
+ for (let i = 0; i < propertiesKeys.length; i++) {
600
+ const key = propertiesKeys[i]
601
+ otherProps[key] = arg.properties[key]
602
+ }
603
+ if(arg.pushProperty === '$$$'){
604
+ context.push('equals');
605
+ }
606
+ }
607
+
608
+ whereParams.push(argName);
609
+ return { context, otherProps, argName, autoVal: arg.autoInjectVal };
610
+ });
611
+ if(showWorking) {
612
+ console.log(`[VSRepository] (build) Where object resolved to ${keyToMap}:\n`, JSON.stringify(whereResolved, null, 2));
613
+ }
614
+ }
615
+
616
+ let select;
617
+ if(!ignoreSelect) {
618
+
619
+ const providedSelectModel = methods[originalKey].selectModel;
620
+
621
+ if(providedSelectModel) {
622
+ select = this.selectModels[providedSelectModel];
623
+ } else if(this.defaultSelectModel && providedSelectModel !== false) {
624
+ select = this.selectModels[this.defaultSelectModel];
625
+ }
626
+
627
+ }
628
+ if(existsMode) {
629
+ select = { [this.pkName]: true };
630
+ }
631
+
632
+ this.vsrepocache.set(originalKey, (args, optionsSelectModel) => {
633
+ const prismaArgs = {};
634
+
635
+ if(!ignoreSelect) {
636
+ prismaArgs.select = existsMode || optionsSelectModel === undefined ?
637
+ select :
638
+ optionsSelectModel === false ?
639
+ undefined :
640
+ this.selectModels[optionsSelectModel];
641
+ }
642
+
643
+ if(orderPosition !== undefined) {
644
+ prismaArgs.orderBy = args.at(orderPosition);
645
+ } else if(injectOrdenation !== undefined) {
646
+ prismaArgs.orderBy = injectOrdenation;
647
+ }
648
+
649
+ if(paginationPosition !== undefined) {
650
+ const paginate = args.at(paginationPosition);
651
+ prismaArgs.skip = paginate.skip;
652
+ prismaArgs.take = paginate.take;
653
+ prismaArgs.cursor = paginate.cursor;
654
+ } else if(injectPagination !== undefined) {
655
+ prismaArgs.skip = injectPagination.skip;
656
+ prismaArgs.take = injectPagination.take;
657
+ prismaArgs.cursor = injectPagination.cursor;
658
+ }
659
+
660
+ if(skipDuplicates!==undefined){
661
+ prismaArgs.skipDuplicates = skipDuplicates;
662
+ }
663
+
664
+ const assignWhere = (where) => {
665
+ if(whereType==='extending' && this.requiredWhere) {
666
+ let safeRequiredWhere = structuredClone(this.requiredWhere);
667
+ if(where.OR && safeRequiredWhere.OR) safeRequiredWhere.OR = safeRequiredWhere.OR.concat(where.OR)
668
+ if(where.AND && safeRequiredWhere.AND) safeRequiredWhere.AND = safeRequiredWhere.AND.concat(where.AND)
669
+ Object.assign(where, safeRequiredWhere);
670
+ }
671
+ if(pushWhere !== undefined) {
672
+ let safePushWhere = structuredClone(pushWhere);
673
+ if(where.OR && safePushWhere.OR) safePushWhere.OR = safePushWhere.OR.concat(where.OR)
674
+ if(where.AND && safePushWhere.AND) safePushWhere.AND = safePushWhere.AND.concat(where.AND)
675
+ Object.assign(where, safePushWhere);
676
+ }
677
+ }
678
+
679
+ if(!ignoreWhere) {
680
+
681
+ const where = {};
682
+ let OR;
683
+ let AND;
684
+
685
+ let adjust = 0;
686
+ for (let j = 0; j < whereResolved.length; j++) {
687
+ let path = {}
688
+ let current = path
689
+ let ormode = false;
690
+ let andmode = false;
691
+ let modeIdx;
692
+ const currentWhereRslvd = whereResolved[j];
693
+ const context = currentWhereRslvd.context
694
+ const contextLength = context.length;
695
+ const contextLengthM1 = contextLength-1;
696
+ for (let i = 0; i < contextLength; i++) {
697
+ if(i<contextLengthM1){
698
+ if(context[i]==='OR'){
699
+ ormode = true;
700
+ } else if(context[i]==='AND'){
701
+ andmode = true;
702
+ } else if(typeof context[i] === 'number'){
703
+ modeIdx = context[i];
704
+ } else {
705
+ if(!current[context[i]]) current[context[i]] = {};
706
+ current = current[context[i]];
707
+ }
708
+ } else {
709
+ if(currentWhereRslvd.autoVal !== undefined) {
710
+ current[context[i]] = currentWhereRslvd.autoVal;
711
+ adjust++
712
+ } else {
713
+ current[context[i]] = args[j - adjust];
714
+ }
715
+ }
716
+ }
717
+
718
+ if(currentWhereRslvd.otherProps !== undefined) {
719
+ Object.assign(path[currentWhereRslvd.argName], currentWhereRslvd.otherProps)
720
+ }
721
+ if (ormode) {
722
+ if(!OR) OR = [];
723
+ if(!OR[modeIdx]) OR[modeIdx] = {}
724
+ Object.assign(OR[modeIdx], path)
725
+ } else if(andmode) {
726
+ if(!AND) AND = [];
727
+ if(!AND[modeIdx]) AND[modeIdx] = {}
728
+ Object.assign(AND[modeIdx], path)
729
+ } else {
730
+ Object.assign(where, path);
731
+ }
732
+ }
733
+
734
+ if(OR) where.OR = OR.filter(x=>x!==undefined);
735
+ if(AND) where.AND = AND.filter(x=>x!==undefined);
736
+
737
+ assignWhere(where);
738
+
739
+ prismaArgs.where = where;
740
+ } else if(onlyBaseWheres) {
741
+ const where = whereIndex !== undefined ? args.at(whereIndex) : {};
742
+
743
+ assignWhere(where);
744
+
745
+ prismaArgs.where = where;
746
+ }
747
+
748
+ if(dataIndex !== undefined) {
749
+ prismaArgs.data = args.at(dataIndex);
750
+ }
751
+ if(updateIndex !== undefined) {
752
+ prismaArgs.update = args.at(updateIndex);
753
+ }
754
+ if(createIndex !== undefined) {
755
+ prismaArgs.create = args.at(createIndex);
756
+ }
757
+
758
+ return prismaArgs;
759
+ })
760
+
761
+ this[originalKey] = async (...args) => {
762
+
763
+ let db = prisma;
764
+ let optionsSelectModel;
765
+ if(args.length < argsCount) {
766
+ const missingParams = whereParams.concat(otherParams).slice(args.length);
767
+ throw new VSRepoRuntimeError(`[VSRepository] (runtime) Missing parameters: ${missingParams.join(', ')}`);
768
+ } else if(args.length > argsCount) {
769
+ const optionsArg = args[args.length - 1]
770
+ db = optionsArg.db ?? db;
771
+ optionsSelectModel = optionsArg.selectModel
772
+ } else {
773
+ args.push('1')
774
+ }
775
+
776
+ const prismaArgs = this.vsrepocache.get(originalKey)(args, optionsSelectModel);
777
+
778
+ let start;
779
+ if(showWorking){
780
+ console.log(`[VSRepository] (runtime) Executing ${method} on ${this.tableName}.`);
781
+ console.log(`[VSRepository] (runtime) Built arguments to ${method} on ${this.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
782
+ start = performance.now();
783
+ }
784
+
785
+ try {
786
+ const result = await db[this.tableName][method](prismaArgs);
787
+
788
+ if(showWorking) {
789
+ const end = performance.now();
790
+ const duration = (end - start).toFixed(2);
791
+ console.log(`[VSRepository] (runtime) Executed ${method} on ${this.tableName} (took: ${duration}ms).`);
792
+ }
793
+
794
+ if(existsMode) {
795
+ return !!result;
796
+ }
797
+ return result;
798
+ } catch (err) {
799
+ console.log(`[VSRepository] (runtime) Fatal error when executing ${method} on ${this.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
800
+ throw err;
801
+ }
802
+
803
+ }
804
+
805
+ }
806
+
807
+ if(config.baseMethods?.get?.active !== false) {
808
+ this.get = async(pk, options = {}) => {
809
+ let db;
810
+ if(options?.db) db = options.db;
811
+ else db = prisma;
812
+
813
+ const prismaArgs = {};
814
+
815
+ const where = { [this.pkName]: pk };
816
+ if(this.requiredWhere && !config.baseMethods?.get?.ignoreRequiredWhere) {
817
+ Object.assign(where, this.requiredWhere);
818
+ }
819
+ prismaArgs.where = where;
820
+
821
+ let selectModelKey = options?.selectModel ?? config.baseMethods?.get?.defaultSelect ?? this.defaultSelectModel;
822
+ if(selectModelKey){
823
+ prismaArgs.select = this.selectModels[selectModelKey];
824
+ }
825
+
826
+ let start;
827
+ if(showWorking){
828
+ console.log(`[VSRepository] (runtime) Executing get on ${this.tableName}.`);
829
+ console.log(`[VSRepository] (runtime) Built arguments to get on ${this.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
830
+ start = performance.now();
831
+ }
832
+
833
+ try {
834
+ const result = await db[this.tableName].findUnique(prismaArgs);
835
+
836
+ if(showWorking) {
837
+ const end = performance.now();
838
+ const duration = (end - start).toFixed(2);
839
+ console.log(`[VSRepository] (runtime) Executed get on ${this.tableName} (took: ${duration}ms).`);
840
+ }
841
+
842
+ return result;
843
+ } catch (err) {
844
+ console.log(`[VSRepository] (runtime) Fatal error when trying to get on ${this.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
845
+ throw err;
846
+ }
847
+ }
848
+ }
849
+ if(config.baseMethods?.remove?.active !== false) {
850
+ this.remove = async (pk, options = {}) => {
851
+ let db;
852
+ if(options?.db) db = options.db;
853
+ else db = prisma;
854
+
855
+ const prismaArgs = {};
856
+
857
+ const where = { [this.pkName]: pk };
858
+ if(this.requiredWhere && !config.baseMethods?.remove?.ignoreRequiredWhere) {
859
+ Object.assign(where, this.requiredWhere);
860
+ }
861
+ prismaArgs.where = where;
862
+
863
+ let selectModelKey = options?.selectModel ?? config.baseMethods?.remove?.defaultSelect ?? this.defaultSelectModel;
864
+ if(selectModelKey){
865
+ prismaArgs.select = this.selectModels[selectModelKey];
866
+ }
867
+
868
+ let start;
869
+ if(showWorking){
870
+ console.log(`[VSRepository] (runtime) Executing remove on ${this.tableName}.`);
871
+ console.log(`[VSRepository] (runtime) Built arguments to remove on ${this.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
872
+ start = performance.now();
873
+ }
874
+ try {
875
+ const result = await db[this.tableName].delete(prismaArgs);
876
+
877
+ if(showWorking) {
878
+ const end = performance.now();
879
+ const duration = (end - start).toFixed(2);
880
+ console.log(`[VSRepository] (runtime) Executed remove on ${this.tableName} (took: ${duration}ms).`);
881
+ }
882
+
883
+ return result;
884
+ } catch (err) {
885
+ console.log(`[VSRepository] (runtime) Fatal error when trying to remove on ${this.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
886
+ throw err;
887
+ }
888
+ }
889
+ }
890
+ if(config.baseMethods?.save?.active !== false) {
891
+ this.save = async (obj, options = {}) => {
892
+ let db;
893
+ if(options?.db) db = options.db;
894
+ else db = prisma;
895
+
896
+ const prismaArgs = {};
897
+
898
+ let selectModelKey = options?.selectModel ?? config.baseMethods?.save?.defaultSelect ?? this.defaultSelectModel;
899
+ if(selectModelKey){
900
+ prismaArgs.select = this.selectModels[selectModelKey];
901
+ }
902
+
903
+ let start;
904
+ if(showWorking){
905
+ console.log(`[VSRepository] (runtime) Executing save on ${this.tableName}.`);
906
+ start = performance.now();
907
+ }
908
+
909
+ try {
910
+ let result;
911
+ if(obj[this.pkName] !== undefined){
912
+ prismaArgs.create = {};
913
+ prismaArgs.update = {};
914
+
915
+ const keys = Object.keys(obj);
916
+ for (let i = 0; i < keys.length; i++) {
917
+ const key = keys[i];
918
+ const field = obj[key];
919
+
920
+ if(field === undefined) continue;
921
+
922
+ if(relationsKeys.includes(key)){
923
+ const relation = this.relations[key];
924
+ const relationMode = relation.mode;
925
+ const relationRestriction = relation.restriction;
926
+ const relationPk = relation.pk;
927
+
928
+ if(relationMode === 'oto' || relationMode === 'mto') {
929
+ if(field === null) {
930
+ if(relationMode === 'oto' && relationRestriction === 'set') {
931
+ prismaArgs.update[key] = { delete: true };
932
+ } else if(relationMode === 'mto' && relation.nullAble) {
933
+ prismaArgs.update[key] = { disconnect: true };
934
+ }
935
+ } else if (field !== undefined) {
936
+ const relationFieldPk = field[relationPk];
937
+ if(relationFieldPk){
938
+ const connectOrCreate = {
939
+ where: { [relationPk]: relationFieldPk },
940
+ create: field
941
+ };
942
+
943
+ prismaArgs.create[key] = { connectOrCreate };
944
+
945
+ if(relationRestriction === 'add') {
946
+ prismaArgs.update[key] = { connectOrCreate };
947
+ } else {
948
+ const update = {...field};
949
+ delete update[relationPk];
950
+
951
+ prismaArgs.update[key] = {
952
+ upsert: {
953
+ where: { [relationPk]: relationFieldPk },
954
+ create: field,
955
+ update: update
956
+ }
957
+ };
958
+ }
959
+ } else {
960
+ prismaArgs.create[key] = { create: field };
961
+ prismaArgs.update[key] = { create: field };
962
+ }
963
+ }
964
+ } else if(Array.isArray(field)) {
965
+ const dataWithPk = field.filter(data=>data[relationPk]!==undefined);
966
+ const dataWithoutPk = field.filter(data=>data[relationPk]===undefined);
967
+
968
+ const connectOrCreate = dataWithPk.map(data=>({
969
+ where: { [relationPk]: data[relationPk] },
970
+ create: data
971
+ }));
972
+
973
+ prismaArgs.create[key] = {
974
+ create: dataWithoutPk,
975
+ connectOrCreate
976
+ };
977
+
978
+ if(relationRestriction === 'add') {
979
+ if(relationMode === 'mtm') {
980
+ prismaArgs.update[key] = {
981
+ create: dataWithoutPk,
982
+ connectOrCreate
983
+ }
984
+ } else {
985
+ prismaArgs.update[key] = {
986
+ create: dataWithoutPk,
987
+ upsert: dataWithPk.map(data=>{
988
+ const update = { ...data };
989
+ delete update[relationPk];
990
+ return {
991
+ where: { [relationPk]: data[relationPk] },
992
+ create: data, update
993
+ }
994
+ })
995
+ }
996
+ }
997
+ } else {
998
+ if(relationMode === 'mtm') {
999
+ prismaArgs.update[key] = {
1000
+ set: [],
1001
+ create: dataWithoutPk,
1002
+ connectOrCreate
1003
+ }
1004
+ } else {
1005
+ prismaArgs.update[key] = {
1006
+ deleteMany: { [relationPk]: { notIn: dataWithPk.map(data=>data[relationPk]) } },
1007
+ create: dataWithoutPk,
1008
+ upsert: dataWithPk.map(data=>{
1009
+ const update = { ...data };
1010
+ delete update[relationPk];
1011
+ return {
1012
+ where: { [relationPk]: data[relationPk] },
1013
+ create: data, update
1014
+ }
1015
+ })
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+ } else {
1021
+ prismaArgs.create[key] = field;
1022
+ if(key !== this.pkName) {
1023
+ prismaArgs.update[key] = field;
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ const where = { [this.pkName]: obj[this.pkName] };
1029
+ if(this.requiredWhere && !config.baseMethods?.save?.ignoreRequiredWhere) {
1030
+ Object.assign(where, this.requiredWhere);
1031
+ }
1032
+ prismaArgs.where = where;
1033
+
1034
+ if(showWorking) {
1035
+ console.log(`[VSRepository] (runtime) Built arguments to save on ${this.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
1036
+ }
1037
+
1038
+ result = await db[this.tableName].upsert(prismaArgs);
1039
+ } else {
1040
+ prismaArgs.data = {};
1041
+
1042
+ const keys = Object.keys(obj);
1043
+ for (let i = 0; i < keys.length; i++) {
1044
+ const key = keys[i];
1045
+ const field = obj[key];
1046
+
1047
+ if(field == null) continue;
1048
+
1049
+ if(relationsKeys.includes(key)){
1050
+ const relation = this.relations[key];
1051
+ const relationMode = relation.mode;
1052
+ const relationPk = relation.pk;
1053
+
1054
+ if(relationMode === 'otm' || relationMode === 'mtm') {
1055
+ const dataWithPk = field.filter(data=>data[relationPk]!==undefined);
1056
+ const dataWithoutPk = field.filter(data=>data[relationPk]===undefined);
1057
+
1058
+ prismaArgs.data[key] = {
1059
+ create: dataWithoutPk,
1060
+ connectOrCreate: dataWithPk.map(data=>({
1061
+ where: { [relationPk]: data[relationPk] },
1062
+ create: data
1063
+ }))
1064
+ }
1065
+ } else {
1066
+ const relationFieldPk = field[relationPk];
1067
+ if(relationFieldPk !== undefined) {
1068
+ prismaArgs.data[key] = {
1069
+ connectOrCreate: {
1070
+ where: { [relationPk]: relationFieldPk },
1071
+ create: field
1072
+ }
1073
+ }
1074
+ } else {
1075
+ prismaArgs.data[key] = {
1076
+ create: field
1077
+ }
1078
+ }
1079
+ }
1080
+ } else {
1081
+ prismaArgs.data[key] = field;
1082
+ }
1083
+ }
1084
+
1085
+ if(showWorking) {
1086
+ console.log(`[VSRepository] (runtime) Built arguments to save on ${this.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
1087
+ }
1088
+
1089
+ result = await db[this.tableName].create(prismaArgs);
1090
+ }
1091
+
1092
+ if(showWorking) {
1093
+ const end = performance.now();
1094
+ const duration = (end - start).toFixed(2);
1095
+ console.log(`[VSRepository] (runtime) Executed save on ${this.tableName} (took: ${duration}ms).`);
1096
+ }
1097
+
1098
+ return result;
1099
+ } catch (err) {
1100
+ console.log(`[VSRepository] (runtime) Fatal error when trying to save on ${this.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
1101
+ throw err;
1102
+ }
1103
+ }
1104
+ }
1105
+
1106
+ if(config.freeze) Object.freeze(this)
1107
+ return this;
1108
+ }
1109
+
1110
+ }
1111
+
1112
+ export const setupVSRepo = () => (config) => new VSRepository(config);