vsrepo 1.1.2 → 1.1.3

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,84 +1,127 @@
1
- import { VSRepoConfigError } from "./VSRepoError.js";
1
+ import z from "zod";
2
+ import { VSRepoConfigError, VSRepoBuildError } from "./VSRepoError.js";
2
3
 
3
- export class FieldValidator {
4
- constructor(throws) {
5
- this.throws = throws;
6
- }
4
+ const stringSchema = z.string().trim().nonempty();
5
+ const objectSchema = z.looseObject({});
6
+ const booleanSchema = z.boolean();
7
7
 
8
- validate(
9
- field,
10
- fieldName,
11
- mustBe,
12
- undefinedAble,
13
- nullAble,
14
- customReason
15
- ) {
16
- if (field === undefined) {
17
- if (undefinedAble) return;
18
- throw this.instanceError(fieldName, customReason ?? "cannot be undefined");
8
+ export function validateConfig(config) {
9
+ const configSchema = z.strictObject({
10
+ tableName: stringSchema,
11
+ pkName: stringSchema,
12
+ selectModels: z.record(stringSchema, objectSchema).optional(),
13
+ defaultSelectModel: stringSchema.optional(),
14
+ requiredWhere: objectSchema.optional(),
15
+ relations: z.record(
16
+ stringSchema,
17
+ z.strictObject({
18
+ mode: z.enum(['otm', 'mtm', 'mto', 'oto']),
19
+ restriction: z.enum(['set', 'add']),
20
+ pk: stringSchema,
21
+ nullAble: booleanSchema.optional(),
22
+ })
23
+ ).optional(),
24
+ methods: z.record(stringSchema, z.strictObject({
25
+ map: booleanSchema,
26
+ selectModel: stringSchema.or(z.literal(false)).optional(),
27
+ whereType: z.enum(["overwrite", "extending"]).optional(),
28
+ proxyTo: stringSchema.optional(),
29
+ pushWhere: objectSchema.optional(),
30
+ fbMode: z.enum(["one", "list"]).optional(),
31
+ injectOrdenation: objectSchema.or(z.array(objectSchema)).optional(),
32
+ injectPagination: objectSchema.optional()
33
+ })).optional()
34
+ }).superRefine((config, ctx)=>{
35
+ if (config.defaultSelectModel && !config.selectModels?.[config.defaultSelectModel]) {
36
+ ctx.addIssue({
37
+ code: "vs_custom",
38
+ path: ["defaultSelectModel"],
39
+ message: "must be a valid key of 'selectModels'",
40
+ });
19
41
  }
20
42
 
21
- if (field === null) {
22
- if (nullAble) return;
23
- throw this.instanceError(fieldName, customReason ?? "cannot be null");
43
+ if (config.methods) {
44
+ for (const [key, method] of Object.entries(config.methods)) {
45
+ if (method.selectModel && !config.selectModels?.[method.selectModel]) {
46
+ ctx.addIssue({
47
+ code: "vs_custom",
48
+ path: ["methods", key, "selectModel"],
49
+ message: "must be a valid key of 'selectModels'",
50
+ });
51
+ }
52
+ }
24
53
  }
54
+ });
25
55
 
26
- const condition = typeof mustBe === "function" ? !mustBe(field) : typeof field !== mustBe;
56
+ const configParsed = configSchema.safeParse(config);
27
57
 
28
- if(condition) {
29
- throw this.instanceError(fieldName, customReason ?? `must be a valid ${mustBe}`);
30
- };
58
+ if(!configParsed.success) {
59
+ const firstIssue = configParsed.error.issues[0];
60
+ const path = firstIssue.path.length ? firstIssue.path.join(".") : "config";
61
+ throw new VSRepoConfigError(`[VSRepository] (config) ${path}: ${firstIssue.message}`)
31
62
  }
32
63
 
33
- instanceError(fieldName, reason) {
34
- const error = new this.throws("");
35
- error.message = `[VSRepository] (${error.type}) '${fieldName}' ${reason}.`;
36
- return error;
37
- }
64
+ return configParsed.data;
38
65
  }
39
66
 
40
- export function validateConfig(config) {
41
- const validator = new FieldValidator(VSRepoConfigError);
42
-
43
- validator.validate(config, "config", "object");
44
- validator.validate(config.tableName, "tableName", "string");
45
- validator.validate(config.pkName, "pkName", "string");
46
- validator.validate(config.selectModels, "selectModels", "object", true);
47
-
48
- if(config.defaultSelectModel !== undefined) {
49
- validator.validate(config.defaultSelectModel, "defaultSelectModel", "string");
50
-
51
- validator.validate(config.defaultSelectModel, "defaultSelectModel", (field) => {
52
- return !!(config.selectModels && Object.keys(config.selectModels).includes(config.defaultSelectModel))
53
- }, false, false, "must be a valid key of 'selectModels'");
67
+ export function validateBuildConfig(buildConfig, buildInstance) {
68
+ const activeSchema = booleanSchema.default(true);
69
+ const defaultSelectSchema = buildInstance.selectModels ?
70
+ z.enum(Object.keys(buildInstance.selectModels)).optional()
71
+ : z.never("can only be passed if you have configured 'selectModels'.");
72
+ const ignoreRequiredWhereSchema = booleanSchema.default(false);
73
+
74
+ const buildConfigSchema = z.strictObject({
75
+ freeze: booleanSchema.default(true),
76
+ showWorking: booleanSchema.default(false),
77
+ baseMethods: z.strictObject({
78
+ get: z.strictObject({
79
+ active: activeSchema,
80
+ defaultSelect: defaultSelectSchema,
81
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
82
+ }).optional(),
83
+ getOrThrow: z.strictObject({
84
+ active: activeSchema,
85
+ defaultSelect: defaultSelectSchema,
86
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
87
+ }).optional(),
88
+ getAll: z.strictObject({
89
+ active: activeSchema,
90
+ defaultSelect: defaultSelectSchema,
91
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
92
+ }).optional(),
93
+ remove: z.strictObject({
94
+ active: activeSchema,
95
+ defaultSelect: defaultSelectSchema,
96
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
97
+ }).optional(),
98
+ save: z.strictObject({
99
+ active: activeSchema,
100
+ defaultSelect: defaultSelectSchema,
101
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
102
+ }).optional(),
103
+ removeList: z.strictObject({
104
+ active: activeSchema,
105
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
106
+ }).optional(),
107
+ total: z.strictObject({
108
+ active: activeSchema,
109
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
110
+ }).optional(),
111
+ has: z.strictObject({
112
+ active: activeSchema,
113
+ ignoreRequiredWhere: ignoreRequiredWhereSchema
114
+ }).optional(),
115
+ }).optional()
116
+ });
117
+
118
+ const buildConfigParsed = buildConfigSchema.safeParse(buildConfig);
119
+
120
+ if(!buildConfigParsed.success) {
121
+ const firstIssue = buildConfigParsed.error.issues[0];
122
+ const path = firstIssue.path.length ? firstIssue.path.join(".") : "config";
123
+ throw new VSRepoBuildError(`[VSRepository] (build) ${path}: ${firstIssue.message}`)
54
124
  }
55
125
 
56
- if(config.relations !== undefined) {
57
- validator.validate(config.relations, "relations", "object");
58
-
59
- for (const key of Object.keys(config.relations)) {
60
- const relation = config.relations[key];
61
-
62
- validator.validate(relation.pk, "pk", "string", false, false, `of relation '${key}' must be a string`);
63
- validator.validate(relation.mode, "mode", (field) => ['otm', 'mtm', 'mto', 'oto'].includes(field), false, false, `of relation '${key}' must be 'otm', 'mtm', 'mto' or 'oto'`);
64
- validator.validate(relation.restriction, "restriction", (field) => ['set', 'add'].includes(field), false, false, `of relation '${key}' must be 'set' or 'add'`);
65
- }
66
- }
67
-
68
- validator.validate(config.requiredWhere, "requiredWhere", "object", true);
69
-
70
- if(config.methods !== undefined) {
71
- validator.validate(config.methods, "methods", "object");
72
-
73
- for (const [key, value] of Object.entries(config.methods)) {
74
- validator.validate(value.map, "map", "boolean", false, false, `on ${key} must be a valid boolean`);
75
- validator.validate(value.whereType, "whereType", (field) => ['extending', 'overwrite'].includes(field), true, false, `on ${key} must be 'extending' or 'overwrite'`);
76
- validator.validate(value.selectModel, "selectModel", (field) => !!(field === false || (config.selectModels && Object.keys(config.selectModels).includes(field))), true, false, `on ${key} must be a valid key of 'selectModels'`);
77
- validator.validate(value.proxyTo, "proxyTo", "string", true, false, `on ${key} must be a valid string`);
78
- validator.validate(value.fbMode, "fbMode", (field) => ['one', 'list'].includes(field), true, false, `on ${key} must be 'one' or 'list'`);
79
- validator.validate(value.pushWhere, "pushWhere", "object", true, false, `on ${key} must be a valid object`);
80
- validator.validate(value.injectOrdenation, "injectOrdenation", "object", true, false, `on ${key} must be a valid object or array`);
81
- validator.validate(value.injectPagination, "injectPagination", "object", true, false, `on ${key} must be a valid object`);
82
- }
83
- }
84
- }
126
+ return buildConfigParsed.data;
127
+ }
@@ -590,6 +590,11 @@ export type BuiltRepository<T extends object, M extends Prisma.ModelName, Config
590
590
  * Estende o repository com métodos personalizados sem perder a tipagem.
591
591
  */
592
592
  extend<E>(extensionFunc: (repo: BuiltRepository<T, M, Config, C>) => E): BuiltRepository<T, M, Config, C> & E;
593
+
594
+ /**
595
+ * Instância do Prisma Client passada no `build`.
596
+ */
597
+ readonly prisma: DbClient;
593
598
  } & DynamicMethods<T, M, Config, PrismaModelInputs<M>> & InjectedBaseMethods<T, M, Config, C>;
594
599
 
595
600
  /**
@@ -605,7 +610,7 @@ export declare class VSRepository<T extends object, M extends Prisma.ModelName,
605
610
  /**
606
611
  * Constrói o repository final com os métodos base e dinâmicos.
607
612
  */
608
- build<C extends BuildConfig<any>>(prisma: DbClient, config?: C): BuiltRepository<T, M, Config, C>;
613
+ build<C extends BuildConfig<keyof ExtractSelectModels<Config>>>(prisma: DbClient, config?: C): BuiltRepository<T, M, Config, C>;
609
614
  vsrepocache: never;
610
615
  }
611
616
 
@@ -9,7 +9,7 @@ export * from "./VSRepoError.js";
9
9
 
10
10
  // * Importando classes de erro
11
11
  import { VSRepoBuildError, VSRepoExtendError, VSRepoRuntimeError } from "./VSRepoError.js";
12
- import { validateConfig } from "./VSRepoUtils.js";
12
+ import { validateBuildConfig, validateConfig } from "./VSRepoUtils.js";
13
13
 
14
14
  // * Essa é a classe pincipal, é a partir dela que serão criados os objetos dos repositories
15
15
  export class VSRepository {
@@ -29,7 +29,7 @@ export class VSRepository {
29
29
  methods;
30
30
 
31
31
  constructor(config) {
32
- validateConfig(config);
32
+ config = validateConfig(config);
33
33
 
34
34
  this.vsrepocache = new Map();
35
35
  this.tableName = config.tableName;
@@ -59,18 +59,17 @@ export class VSRepository {
59
59
  return extended;
60
60
  }
61
61
 
62
- build(prisma, config = {}) {
63
- const showWorking = config.showWorking;
64
-
65
- if(typeof config !== 'object' || config === null) {
66
- throw new VSRepoBuildError(`[VSRepository] (build) 'config' must be a valid object.`);
67
- }
68
- if(config.freeze === undefined) {
69
- config.freeze = true;
62
+ build(prisma, config = { freeze: true, showWorking: false }) {
63
+ if(typeof prisma !== 'object' || prisma === null) {
64
+ throw new VSRepoBuildError(`[VSRepository] (build) 'prisma' must be a valid Prisma Client.`);
70
65
  }
71
66
 
72
67
  const buildInstance = Object.create(this);
73
68
 
69
+ config = validateBuildConfig(config, buildInstance);
70
+
71
+ const showWorking = config.showWorking;
72
+
74
73
  const relationsKeys = buildInstance.relations ? Object.keys(buildInstance.relations) : [];
75
74
 
76
75
  const methods = buildInstance.methods;
@@ -487,10 +486,6 @@ export class VSRepository {
487
486
  whereArgs.push(buildedWhere);
488
487
  }
489
488
 
490
- if(showWorking) {
491
- console.log(`[VSRepository] (build) Where object builded to ${keyToMap}:\n`, JSON.stringify(buildedWhere, null, 2));
492
- }
493
-
494
489
  if(buildedWhere.autoInjectVal === undefined) argsCount++;
495
490
  }
496
491
 
@@ -700,9 +695,9 @@ export class VSRepository {
700
695
  const missingParams = whereParams.concat(otherParams).slice(args.length);
701
696
  throw new VSRepoRuntimeError(`[VSRepository] (runtime) Missing parameters: ${missingParams.join(', ')}`);
702
697
  } else if(args.length > argsCount) {
703
- const optionsArg = args[args.length - 1]
698
+ const optionsArg = args[args.length - 1];
704
699
  db = optionsArg.db ?? db;
705
- optionsSelectModel = optionsArg.selectModel
700
+ optionsSelectModel = optionsArg.selectModel;
706
701
  } else {
707
702
  args.push('1')
708
703
  }
@@ -1198,7 +1193,9 @@ export class VSRepository {
1198
1193
  }
1199
1194
  }
1200
1195
 
1201
- if(config.freeze) Object.freeze(buildInstance)
1196
+ buildInstance.prisma = prisma;
1197
+
1198
+ if(config.freeze) Object.freeze(buildInstance);
1202
1199
  return buildInstance;
1203
1200
  }
1204
1201
 
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "vsrepo",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Uma biblioteca de repository pattern para Prisma",
5
5
  "homepage": "https://github.com/jaobrabo123/VSRepository#readme",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/jaobrabo123/VSRepository"
8
+ "url": "git+https://github.com/jaobrabo123/VSRepository.git"
9
9
  },
10
10
  "main": "./VSRepository/index.js",
11
11
  "types": "./VSRepository/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "scripts"
33
33
  ],
34
34
  "bin": {
35
- "vsrepo": "./scripts/configure-prisma-import.mjs"
35
+ "vsrepo": "scripts/configure-prisma-import.mjs"
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=18"
@@ -63,5 +63,8 @@
63
63
  "prisma": "^7.8.0",
64
64
  "tsx": "^4.22.3",
65
65
  "typescript": "^6.0.3"
66
+ },
67
+ "dependencies": {
68
+ "zod": "^4.4.3"
66
69
  }
67
- }
70
+ }