1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.Condition = void 0;
|
4 | const Document_1 = require("./Document");
|
5 | const CustomError = require("./Error");
|
6 | const utils = require("./utils");
|
7 | const OR = Symbol("OR");
|
8 | const isRawConditionObject = (object) => Object.keys(object).length === 3 && ["ExpressionAttributeValues", "ExpressionAttributeNames"].every((item) => Boolean(object[item]) && typeof object[item] === "object");
|
9 | var ConditionComparisonComparatorName;
|
10 | (function (ConditionComparisonComparatorName) {
|
11 | ConditionComparisonComparatorName["equals"] = "eq";
|
12 | ConditionComparisonComparatorName["lessThan"] = "lt";
|
13 | ConditionComparisonComparatorName["lessThanEquals"] = "le";
|
14 | ConditionComparisonComparatorName["greaterThan"] = "gt";
|
15 | ConditionComparisonComparatorName["greaterThanEquals"] = "ge";
|
16 | ConditionComparisonComparatorName["beginsWith"] = "beginsWith";
|
17 | ConditionComparisonComparatorName["contains"] = "contains";
|
18 | ConditionComparisonComparatorName["exists"] = "exists";
|
19 | ConditionComparisonComparatorName["in"] = "in";
|
20 | ConditionComparisonComparatorName["between"] = "between";
|
21 | })(ConditionComparisonComparatorName || (ConditionComparisonComparatorName = {}));
|
22 | var ConditionComparisonComparatorDynamoName;
|
23 | (function (ConditionComparisonComparatorDynamoName) {
|
24 | ConditionComparisonComparatorDynamoName["equals"] = "EQ";
|
25 | ConditionComparisonComparatorDynamoName["notEquals"] = "NE";
|
26 | ConditionComparisonComparatorDynamoName["lessThan"] = "LT";
|
27 | ConditionComparisonComparatorDynamoName["lessThanEquals"] = "LE";
|
28 | ConditionComparisonComparatorDynamoName["greaterThan"] = "GT";
|
29 | ConditionComparisonComparatorDynamoName["greaterThanEquals"] = "GE";
|
30 | ConditionComparisonComparatorDynamoName["beginsWith"] = "BEGINS_WITH";
|
31 | ConditionComparisonComparatorDynamoName["contains"] = "CONTAINS";
|
32 | ConditionComparisonComparatorDynamoName["notContains"] = "NOT_CONTAINS";
|
33 | ConditionComparisonComparatorDynamoName["exists"] = "EXISTS";
|
34 | ConditionComparisonComparatorDynamoName["notExists"] = "NOT_EXISTS";
|
35 | ConditionComparisonComparatorDynamoName["in"] = "IN";
|
36 | ConditionComparisonComparatorDynamoName["between"] = "BETWEEN";
|
37 | })(ConditionComparisonComparatorDynamoName || (ConditionComparisonComparatorDynamoName = {}));
|
38 | const types = [
|
39 | { "name": ConditionComparisonComparatorName.equals, "typeName": ConditionComparisonComparatorDynamoName.equals, "not": ConditionComparisonComparatorDynamoName.notEquals },
|
40 | { "name": ConditionComparisonComparatorName.lessThan, "typeName": ConditionComparisonComparatorDynamoName.lessThan, "not": ConditionComparisonComparatorDynamoName.greaterThanEquals },
|
41 | { "name": ConditionComparisonComparatorName.lessThanEquals, "typeName": ConditionComparisonComparatorDynamoName.lessThanEquals, "not": ConditionComparisonComparatorDynamoName.greaterThan },
|
42 | { "name": ConditionComparisonComparatorName.greaterThan, "typeName": ConditionComparisonComparatorDynamoName.greaterThan, "not": ConditionComparisonComparatorDynamoName.lessThanEquals },
|
43 | { "name": ConditionComparisonComparatorName.greaterThanEquals, "typeName": ConditionComparisonComparatorDynamoName.greaterThanEquals, "not": ConditionComparisonComparatorDynamoName.lessThan },
|
44 | { "name": ConditionComparisonComparatorName.beginsWith, "typeName": ConditionComparisonComparatorDynamoName.beginsWith },
|
45 | { "name": ConditionComparisonComparatorName.contains, "typeName": ConditionComparisonComparatorDynamoName.contains, "not": ConditionComparisonComparatorDynamoName.notContains },
|
46 | { "name": ConditionComparisonComparatorName.exists, "typeName": ConditionComparisonComparatorDynamoName.exists, "not": ConditionComparisonComparatorDynamoName.notExists },
|
47 | { "name": ConditionComparisonComparatorName.in, "typeName": ConditionComparisonComparatorDynamoName.in },
|
48 | { "name": ConditionComparisonComparatorName.between, "typeName": ConditionComparisonComparatorDynamoName.between, "multipleArguments": true }
|
49 | ];
|
50 | class Condition {
|
51 | constructor(object) {
|
52 | if (object instanceof Condition) {
|
53 | Object.entries(object).forEach((entry) => {
|
54 | const [key, value] = entry;
|
55 | this[key] = value;
|
56 | });
|
57 | }
|
58 | else {
|
59 | this.settings = {
|
60 | "conditions": [],
|
61 | "pending": {}
|
62 | };
|
63 | if (typeof object === "object") {
|
64 | if (!isRawConditionObject(object)) {
|
65 | Object.keys(object).forEach((key) => {
|
66 | const value = object[key];
|
67 | const valueType = typeof value === "object" && Object.keys(value).length > 0 ? Object.keys(value)[0] : "eq";
|
68 | const comparisonType = types.find((item) => item.name === valueType);
|
69 | if (!comparisonType) {
|
70 | throw new CustomError.InvalidFilterComparison(`The type: ${valueType} is invalid.`);
|
71 | }
|
72 | this.settings.conditions.push({
|
73 | [key]: {
|
74 | "type": comparisonType.typeName,
|
75 | "value": typeof value[valueType] !== "undefined" && value[valueType] !== null ? value[valueType] : value
|
76 | }
|
77 | });
|
78 | });
|
79 | }
|
80 | }
|
81 | else if (object) {
|
82 | this.settings.pending.key = object;
|
83 | }
|
84 | }
|
85 | this.settings.raw = object;
|
86 | return this;
|
87 | }
|
88 | }
|
89 | exports.Condition = Condition;
|
90 | function finalizePending(instance) {
|
91 | const pending = instance.settings.pending;
|
92 | let dynamoNameType;
|
93 | if (pending.not === true) {
|
94 | if (!pending.type.not) {
|
95 | throw new CustomError.InvalidFilterComparison(`${pending.type.typeName} can not follow not()`);
|
96 | }
|
97 | dynamoNameType = pending.type.not;
|
98 | }
|
99 | else {
|
100 | dynamoNameType = pending.type.typeName;
|
101 | }
|
102 | instance.settings.conditions.push({
|
103 | [pending.key]: {
|
104 | "type": dynamoNameType,
|
105 | "value": pending.value
|
106 | }
|
107 | });
|
108 | instance.settings.pending = {};
|
109 | }
|
110 | Condition.prototype.parenthesis = Condition.prototype.group = function (value) {
|
111 | value = typeof value === "function" ? value(new Condition()) : value;
|
112 | this.settings.conditions.push(value.settings.conditions);
|
113 | return this;
|
114 | };
|
115 | Condition.prototype.or = function () {
|
116 | this.settings.conditions.push(OR);
|
117 | return this;
|
118 | };
|
119 | Condition.prototype.and = function () {
|
120 | return this;
|
121 | };
|
122 | Condition.prototype.not = function () {
|
123 | this.settings.pending.not = !this.settings.pending.not;
|
124 | return this;
|
125 | };
|
126 | Condition.prototype.where = Condition.prototype.filter = Condition.prototype.attribute = function (key) {
|
127 | this.settings.pending = { key };
|
128 | return this;
|
129 | };
|
130 |
|
131 | types.forEach((type) => {
|
132 | Condition.prototype[type.name] = function (...args) {
|
133 | if (args.includes(undefined)) {
|
134 | console.warn(`Dynamoose Warning: Passing \`undefined\` into a condition ${type.name} is not supported and can lead to behavior where DynamoDB returns an error related to your conditional. In a future version of Dynamoose this behavior will throw an error. If you believe your conditional is valid and you received this message in error, please submit an issue at https://github.com/dynamoose/dynamoose/issues/new/choose.`);
|
135 | }
|
136 | this.settings.pending.value = type.multipleArguments ? args : args[0];
|
137 | this.settings.pending.type = type;
|
138 | finalizePending(this);
|
139 | return this;
|
140 | };
|
141 | });
|
142 | Condition.prototype.requestObject = function (settings = { "conditionString": "ConditionExpression", "conditionStringType": "string" }) {
|
143 | if (this.settings.raw && utils.object.equals(Object.keys(this.settings.raw).sort(), [settings.conditionString, "ExpressionAttributeValues", "ExpressionAttributeNames"].sort())) {
|
144 | return Object.entries(this.settings.raw.ExpressionAttributeValues).reduce((obj, entry) => {
|
145 | const [key, value] = entry;
|
146 |
|
147 | if (!Document_1.Document.isDynamoObject({ "key": value })) {
|
148 | obj.ExpressionAttributeValues[key] = Document_1.Document.objectToDynamo(value, { "type": "value" });
|
149 | }
|
150 | return obj;
|
151 | }, this.settings.raw);
|
152 | }
|
153 | else if (this.settings.conditions.length === 0) {
|
154 | return {};
|
155 | }
|
156 | let index = (settings.index || {}).start || 0;
|
157 | const setIndex = (i) => {
|
158 | index = i;
|
159 | (settings.index || { "set": utils.empty_function }).set(i);
|
160 | };
|
161 | function main(input) {
|
162 | return input.reduce((object, entry, i, arr) => {
|
163 | let expression = "";
|
164 | if (Array.isArray(entry)) {
|
165 | const result = main(entry);
|
166 | const newData = utils.merge_objects.main({ "combineMethod": "object_combine" })(Object.assign({}, result), Object.assign({}, object));
|
167 | const returnObject = utils.object.pick(newData, ["ExpressionAttributeNames", "ExpressionAttributeValues"]);
|
168 | expression = settings.conditionStringType === "array" ? result[settings.conditionString] : `(${result[settings.conditionString]})`;
|
169 | object = Object.assign(Object.assign({}, object), returnObject);
|
170 | }
|
171 | else if (entry !== OR) {
|
172 | const [key, condition] = Object.entries(entry)[0];
|
173 | const { value } = condition;
|
174 | const keys = { "name": `#a${index}`, "value": `:v${index}` };
|
175 | setIndex(++index);
|
176 | const keyParts = key.split(".");
|
177 | if (keyParts.length === 1) {
|
178 | object.ExpressionAttributeNames[keys.name] = key;
|
179 | }
|
180 | else {
|
181 | keys.name = keyParts.reduce((finalName, part, index) => {
|
182 | const name = `${keys.name}_${index}`;
|
183 | object.ExpressionAttributeNames[name] = part;
|
184 | finalName.push(name);
|
185 | return finalName;
|
186 | }, []).join(".");
|
187 | }
|
188 | const toDynamo = (value) => {
|
189 | return Document_1.Document.objectToDynamo(value, { "type": "value" });
|
190 | };
|
191 | object.ExpressionAttributeValues[keys.value] = toDynamo(value);
|
192 | switch (condition.type) {
|
193 | case "EQ":
|
194 | case "NE":
|
195 | expression = `${keys.name} ${condition.type === "EQ" ? "=" : "<>"} ${keys.value}`;
|
196 | break;
|
197 | case "IN":
|
198 | delete object.ExpressionAttributeValues[keys.value];
|
199 | expression = `${keys.name} IN (${value.map((_v, i) => `${keys.value}_${i + 1}`).join(", ")})`;
|
200 | value.forEach((valueItem, i) => {
|
201 | object.ExpressionAttributeValues[`${keys.value}_${i + 1}`] = toDynamo(valueItem);
|
202 | });
|
203 | break;
|
204 | case "GT":
|
205 | case "GE":
|
206 | case "LT":
|
207 | case "LE":
|
208 | expression = `${keys.name} ${condition.type.startsWith("G") ? ">" : "<"}${condition.type.endsWith("E") ? "=" : ""} ${keys.value}`;
|
209 | break;
|
210 | case "BETWEEN":
|
211 | expression = `${keys.name} BETWEEN ${keys.value}_1 AND ${keys.value}_2`;
|
212 | object.ExpressionAttributeValues[`${keys.value}_1`] = toDynamo(value[0]);
|
213 | object.ExpressionAttributeValues[`${keys.value}_2`] = toDynamo(value[1]);
|
214 | delete object.ExpressionAttributeValues[keys.value];
|
215 | break;
|
216 | case "CONTAINS":
|
217 | case "NOT_CONTAINS":
|
218 | expression = `${condition.type === "NOT_CONTAINS" ? "NOT " : ""}contains (${keys.name}, ${keys.value})`;
|
219 | break;
|
220 | case "EXISTS":
|
221 | case "NOT_EXISTS":
|
222 | expression = `attribute_${condition.type === "NOT_EXISTS" ? "not_" : ""}exists (${keys.name})`;
|
223 | delete object.ExpressionAttributeValues[keys.value];
|
224 | break;
|
225 | case "BEGINS_WITH":
|
226 | expression = `begins_with (${keys.name}, ${keys.value})`;
|
227 | break;
|
228 | }
|
229 | }
|
230 | else {
|
231 | return object;
|
232 | }
|
233 | const conditionStringNewItems = [expression];
|
234 | if (object[settings.conditionString].length > 0) {
|
235 | conditionStringNewItems.unshift(` ${arr[i - 1] === OR ? "OR" : "AND"} `);
|
236 | }
|
237 | conditionStringNewItems.forEach((item) => {
|
238 | if (typeof object[settings.conditionString] === "string") {
|
239 | object[settings.conditionString] = `${object[settings.conditionString]}${item}`;
|
240 | }
|
241 | else {
|
242 | object[settings.conditionString].push(Array.isArray(item) ? item : item.trim());
|
243 | }
|
244 | });
|
245 | return object;
|
246 | }, { [settings.conditionString]: settings.conditionStringType === "array" ? [] : "", "ExpressionAttributeNames": {}, "ExpressionAttributeValues": {} });
|
247 | }
|
248 | return utils.object.clearEmpties(main(this.settings.conditions));
|
249 | };
|
250 |
|
\ | No newline at end of file |