1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | Object.defineProperty(exports, "__esModule", { value: true });
|
11 | exports.extendValidator = void 0;
|
12 | const luxon_1 = require("luxon");
|
13 | const utils_1 = require("@poppinss/utils");
|
14 |
|
15 |
|
16 |
|
17 | class DbRowCheck {
|
18 | constructor(ruleName, database, helpers) {
|
19 | Object.defineProperty(this, "ruleName", {
|
20 | enumerable: true,
|
21 | configurable: true,
|
22 | writable: true,
|
23 | value: ruleName
|
24 | });
|
25 | Object.defineProperty(this, "database", {
|
26 | enumerable: true,
|
27 | configurable: true,
|
28 | writable: true,
|
29 | value: database
|
30 | });
|
31 | Object.defineProperty(this, "helpers", {
|
32 | enumerable: true,
|
33 | configurable: true,
|
34 | writable: true,
|
35 | value: helpers
|
36 | });
|
37 | }
|
38 | |
39 |
|
40 |
|
41 | applyWhere(query, constraints, refs) {
|
42 | if (!constraints.length) {
|
43 | return;
|
44 | }
|
45 | constraints.forEach(({ key, operator, value, ref }) => {
|
46 | const val = ref ? refs[ref].value : value;
|
47 | if (operator === 'in') {
|
48 | query.whereIn(key, val);
|
49 | }
|
50 | else {
|
51 | query.where(key, val);
|
52 | }
|
53 | });
|
54 | }
|
55 | |
56 |
|
57 |
|
58 | applyWhereNot(query, constraints, refs) {
|
59 | if (!constraints.length) {
|
60 | return;
|
61 | }
|
62 | constraints.forEach(({ key, operator, value, ref }) => {
|
63 | const val = ref ? refs[ref].value : value;
|
64 | if (operator === 'in') {
|
65 | query.whereNotIn(key, val);
|
66 | }
|
67 | else {
|
68 | query.whereNot(key, val);
|
69 | }
|
70 | });
|
71 | }
|
72 | |
73 |
|
74 |
|
75 | normalizeConstraints(constraints) {
|
76 | const normalized = [];
|
77 | if (!constraints) {
|
78 | return normalized;
|
79 | }
|
80 | |
81 |
|
82 |
|
83 | return Object.keys(constraints).reduce((result, key) => {
|
84 | const value = constraints[key];
|
85 | if (this.helpers.isRef(value)) {
|
86 | result.push({ key, ref: value.key, operator: Array.isArray(value.value) ? 'in' : 'eq' });
|
87 | }
|
88 | else {
|
89 | result.push({ key, value, operator: Array.isArray(value) ? 'in' : 'eq' });
|
90 | }
|
91 | return result;
|
92 | }, normalized);
|
93 | }
|
94 | |
95 |
|
96 |
|
97 | compile(options) {
|
98 | |
99 |
|
100 |
|
101 | if (!options || !options.table || !options.column) {
|
102 | throw new utils_1.Exception(`"${this.ruleName}" rule expects a "table" and a "column" name`);
|
103 | }
|
104 | |
105 |
|
106 |
|
107 | if (options.constraints) {
|
108 | process.emitWarning('DeprecationWarning', '"options.constraints" have been depreciated. Use "options.where" instead.');
|
109 | }
|
110 | return {
|
111 | table: options.table,
|
112 | column: options.column,
|
113 | caseInsensitive: !!options.caseInsensitive,
|
114 | connection: options.connection,
|
115 | dateFormat: options.dateFormat,
|
116 | where: this.normalizeConstraints(options.where || options.constraints),
|
117 | whereNot: this.normalizeConstraints(options.whereNot),
|
118 | };
|
119 | }
|
120 | |
121 |
|
122 |
|
123 | async validate(value, { table, column, where, whereNot, connection, caseInsensitive, dateFormat }, { pointer, errorReporter, arrayExpressionPointer, refs }) {
|
124 | const client = this.database.connection(connection);
|
125 | const query = client.from(table).select(1);
|
126 | |
127 |
|
128 |
|
129 | if (luxon_1.DateTime.isDateTime(value)) {
|
130 | const format = dateFormat || client.dialect.dateTimeFormat;
|
131 | value = value.toFormat(format);
|
132 | }
|
133 | |
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 | if (caseInsensitive) {
|
142 | query.whereRaw(`lower(${column}) = ?`, [this.database.raw(`lower(?)`, [value])]);
|
143 | }
|
144 | else {
|
145 | query.where(column, value);
|
146 | }
|
147 | this.applyWhere(query, where, refs);
|
148 | this.applyWhereNot(query, whereNot, refs);
|
149 | const row = await query.first();
|
150 | if (this.ruleName === 'exists') {
|
151 | if (!row) {
|
152 | errorReporter.report(pointer, this.ruleName, `${this.ruleName} validation failure`, arrayExpressionPointer);
|
153 | }
|
154 | return;
|
155 | }
|
156 | if (this.ruleName === 'unique') {
|
157 | if (row) {
|
158 | errorReporter.report(pointer, this.ruleName, `${this.ruleName} validation failure`, arrayExpressionPointer);
|
159 | }
|
160 | return;
|
161 | }
|
162 | }
|
163 | }
|
164 |
|
165 |
|
166 |
|
167 | function extendValidator(validator, database, logger) {
|
168 | |
169 |
|
170 |
|
171 | const existsChecker = new DbRowCheck('exists', database, validator.helpers);
|
172 | validator.rule('exists', async (value, compiledOptions, options) => {
|
173 | try {
|
174 | await existsChecker.validate(value, compiledOptions, options);
|
175 | }
|
176 | catch (error) {
|
177 | logger.fatal({ err: error }, '"exists" validation rule failed');
|
178 | options.errorReporter.report(options.pointer, 'exists', 'exists validation failure', options.arrayExpressionPointer);
|
179 | }
|
180 | }, (options) => {
|
181 | return {
|
182 | compiledOptions: existsChecker.compile(options[0]),
|
183 | async: true,
|
184 | };
|
185 | });
|
186 | |
187 |
|
188 |
|
189 | const uniqueChecker = new DbRowCheck('unique', database, validator.helpers);
|
190 | validator.rule('unique', async (value, compiledOptions, options) => {
|
191 | try {
|
192 | await uniqueChecker.validate(value, compiledOptions, options);
|
193 | }
|
194 | catch (error) {
|
195 | logger.fatal({ err: error }, '"unique" validation rule failed');
|
196 | options.errorReporter.report(options.pointer, 'unique', 'unique validation failure', options.arrayExpressionPointer);
|
197 | }
|
198 | }, (options) => {
|
199 | return {
|
200 | compiledOptions: uniqueChecker.compile(options[0]),
|
201 | async: true,
|
202 | };
|
203 | });
|
204 | }
|
205 | exports.extendValidator = extendValidator;
|