electrodb 1.4.8 → 1.6.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.
- package/CHANGELOG.md +32 -5
- package/README.md +152 -62
- package/index.d.ts +40 -0
- package/package.json +6 -3
- package/src/clauses.js +20 -2
- package/src/entity.js +188 -81
- package/src/errors.js +104 -8
- package/src/operations.js +6 -1
- package/src/schema.js +101 -50
- package/src/where.js +17 -1
package/src/entity.js
CHANGED
|
@@ -150,7 +150,8 @@ class Entity {
|
|
|
150
150
|
names: expressions.names || {},
|
|
151
151
|
values: expressions.values || {},
|
|
152
152
|
expression: expressions.expression || ""
|
|
153
|
-
}
|
|
153
|
+
},
|
|
154
|
+
_isCollectionQuery: true,
|
|
154
155
|
};
|
|
155
156
|
|
|
156
157
|
let index = this.model.translations.collections.fromCollectionToIndex[collection];
|
|
@@ -197,11 +198,7 @@ class Entity {
|
|
|
197
198
|
|
|
198
199
|
create(attributes = {}) {
|
|
199
200
|
let index = TableIndex;
|
|
200
|
-
let options = {
|
|
201
|
-
params: {
|
|
202
|
-
ConditionExpression: this._makeItemDoesntExistConditions(index)
|
|
203
|
-
}
|
|
204
|
-
};
|
|
201
|
+
let options = {};
|
|
205
202
|
return this._makeChain(index, this._clausesWithFilters, clauses.index, options).create(attributes);
|
|
206
203
|
}
|
|
207
204
|
|
|
@@ -212,21 +209,13 @@ class Entity {
|
|
|
212
209
|
|
|
213
210
|
patch(facets = {}) {
|
|
214
211
|
let index = TableIndex;
|
|
215
|
-
let options = {
|
|
216
|
-
params: {
|
|
217
|
-
ConditionExpression: this._makeItemExistsConditions(index)
|
|
218
|
-
}
|
|
219
|
-
};
|
|
212
|
+
let options = {};
|
|
220
213
|
return this._makeChain(index, this._clausesWithFilters, clauses.index, options).patch(facets);
|
|
221
214
|
}
|
|
222
215
|
|
|
223
216
|
remove(facets = {}) {
|
|
224
217
|
let index = TableIndex;
|
|
225
|
-
let options = {
|
|
226
|
-
params: {
|
|
227
|
-
ConditionExpression: this._makeItemExistsConditions(index)
|
|
228
|
-
}
|
|
229
|
-
};
|
|
218
|
+
let options = {};
|
|
230
219
|
return this._makeChain(index, this._clausesWithFilters, clauses.index, options).remove(facets);
|
|
231
220
|
}
|
|
232
221
|
|
|
@@ -241,8 +230,10 @@ class Entity {
|
|
|
241
230
|
return await this.executeBulkWrite(parameters, config);
|
|
242
231
|
case MethodTypes.batchGet:
|
|
243
232
|
return await this.executeBulkGet(parameters, config);
|
|
233
|
+
case MethodTypes.query:
|
|
234
|
+
return await this.executeQuery(parameters, config)
|
|
244
235
|
default:
|
|
245
|
-
return await this.
|
|
236
|
+
return await this.executeOperation(method, parameters, config);
|
|
246
237
|
}
|
|
247
238
|
} catch (err) {
|
|
248
239
|
if (config.originalErr || stackTrace === undefined) {
|
|
@@ -324,7 +315,54 @@ class Entity {
|
|
|
324
315
|
return [resultsAll, unprocessedAll];
|
|
325
316
|
}
|
|
326
317
|
|
|
327
|
-
async executeQuery(
|
|
318
|
+
async executeQuery(parameters, config = {}) {
|
|
319
|
+
let results = config._isCollectionQuery
|
|
320
|
+
? {}
|
|
321
|
+
: [];
|
|
322
|
+
let ExclusiveStartKey;
|
|
323
|
+
let pages = this._normalizePagesValue(config.pages);
|
|
324
|
+
let max = this._normalizeLimitValue(config.limit);
|
|
325
|
+
let iterations = 0;
|
|
326
|
+
let count = 0;
|
|
327
|
+
do {
|
|
328
|
+
let limit = max === undefined
|
|
329
|
+
? parameters.Limit
|
|
330
|
+
: max - count;
|
|
331
|
+
let response = await this._exec("query", {ExclusiveStartKey, ...parameters, Limit: limit});
|
|
332
|
+
|
|
333
|
+
ExclusiveStartKey = response.LastEvaluatedKey;
|
|
334
|
+
|
|
335
|
+
if (validations.isFunction(config.parse)) {
|
|
336
|
+
response = config.parse(config, response);
|
|
337
|
+
} else {
|
|
338
|
+
response = this.formatResponse(response, parameters.IndexName, config);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (config.raw || config._isPagination) {
|
|
342
|
+
return response;
|
|
343
|
+
} else if (config._isCollectionQuery) {
|
|
344
|
+
for (const entity in response) {
|
|
345
|
+
if (max) {
|
|
346
|
+
count += response[entity].length;
|
|
347
|
+
}
|
|
348
|
+
results[entity] = results[entity] || [];
|
|
349
|
+
results[entity] = [...results[entity], ...response[entity]];
|
|
350
|
+
}
|
|
351
|
+
} else if (Array.isArray(response)) {
|
|
352
|
+
if (max) {
|
|
353
|
+
count += response.length;
|
|
354
|
+
}
|
|
355
|
+
results = [...results, ...response];
|
|
356
|
+
} else {
|
|
357
|
+
return response;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
iterations++;
|
|
361
|
+
} while(ExclusiveStartKey && iterations < pages && (max === undefined || count < max));
|
|
362
|
+
return results;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async executeOperation(method, parameters, config) {
|
|
328
366
|
let response = await this._exec(method, parameters);
|
|
329
367
|
if (validations.isFunction(config.parse)) {
|
|
330
368
|
return config.parse(config, response);
|
|
@@ -566,6 +604,24 @@ class Entity {
|
|
|
566
604
|
return value;
|
|
567
605
|
}
|
|
568
606
|
|
|
607
|
+
_normalizePagesValue(value = Number.MAX_SAFE_INTEGER) {
|
|
608
|
+
value = parseInt(value);
|
|
609
|
+
if (isNaN(value) || value < 1) {
|
|
610
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidPagesOption, "Query option 'pages' must be of type 'number' and greater than zero.");
|
|
611
|
+
}
|
|
612
|
+
return value;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
_normalizeLimitValue(value) {
|
|
616
|
+
if (value !== undefined) {
|
|
617
|
+
value = parseInt(value);
|
|
618
|
+
if (isNaN(value) || value < 1) {
|
|
619
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidLimitOption, "Query option 'limit' must be of type 'number' and greater than zero.");
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return value;
|
|
623
|
+
}
|
|
624
|
+
|
|
569
625
|
_deconstructKeys(index, keyType, key, backupFacets = {}) {
|
|
570
626
|
if (typeof key !== "string" || key.length === 0) {
|
|
571
627
|
return null;
|
|
@@ -693,6 +749,8 @@ class Entity {
|
|
|
693
749
|
response: 'default',
|
|
694
750
|
ignoreOwnership: false,
|
|
695
751
|
_isPagination: false,
|
|
752
|
+
_isCollectionQuery: false,
|
|
753
|
+
pages: undefined,
|
|
696
754
|
};
|
|
697
755
|
|
|
698
756
|
config = options.reduce((config, option) => {
|
|
@@ -705,6 +763,14 @@ class Entity {
|
|
|
705
763
|
config.params.ReturnValues = FormatToReturnValues[format];
|
|
706
764
|
}
|
|
707
765
|
|
|
766
|
+
if (option.pages !== undefined) {
|
|
767
|
+
config.pages = option.pages;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if (option._isCollectionQuery === true) {
|
|
771
|
+
config._isCollectionQuery = true;
|
|
772
|
+
}
|
|
773
|
+
|
|
708
774
|
if (option.includeKeys === true) {
|
|
709
775
|
config.includeKeys = true;
|
|
710
776
|
}
|
|
@@ -727,7 +793,8 @@ class Entity {
|
|
|
727
793
|
config.unprocessed = UnprocessedTypes.raw;
|
|
728
794
|
}
|
|
729
795
|
|
|
730
|
-
if (
|
|
796
|
+
if (option.limit !== undefined) {
|
|
797
|
+
config.limit = option.limit;
|
|
731
798
|
config.params.Limit = option.limit;
|
|
732
799
|
}
|
|
733
800
|
|
|
@@ -787,29 +854,18 @@ class Entity {
|
|
|
787
854
|
return {parameters, config};
|
|
788
855
|
}
|
|
789
856
|
|
|
790
|
-
|
|
791
|
-
let hasSortKey = this.model.lookup.indexHasSortKeys[
|
|
792
|
-
let accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[
|
|
857
|
+
_getPrimaryIndexFieldNames() {
|
|
858
|
+
let hasSortKey = this.model.lookup.indexHasSortKeys[TableIndex];
|
|
859
|
+
let accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[TableIndex];
|
|
793
860
|
let pkField = this.model.indexes[accessPattern].pk.field;
|
|
794
|
-
let
|
|
861
|
+
let skField;
|
|
795
862
|
if (hasSortKey) {
|
|
796
|
-
|
|
797
|
-
filter.push(`attribute_not_exists(${skField})`);
|
|
863
|
+
skField = this.model.indexes[accessPattern].sk.field;
|
|
798
864
|
}
|
|
799
|
-
return
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
_makeItemExistsConditions(index) {
|
|
803
|
-
let hasSortKey = this.model.lookup.indexHasSortKeys[index];
|
|
804
|
-
let accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[index];
|
|
805
|
-
let pkField = this.model.indexes[accessPattern].pk.field;
|
|
806
|
-
|
|
807
|
-
let filter = [`attribute_exists(${pkField})`];
|
|
808
|
-
if (hasSortKey) {
|
|
809
|
-
let skField = this.model.indexes[accessPattern].sk.field;
|
|
810
|
-
filter.push(`attribute_exists(${skField})`);
|
|
865
|
+
return {
|
|
866
|
+
pk: pkField,
|
|
867
|
+
sk: skField
|
|
811
868
|
}
|
|
812
|
-
return filter.join(" AND ");
|
|
813
869
|
}
|
|
814
870
|
|
|
815
871
|
_applyParameterExpressionTypes(params, filter) {
|
|
@@ -1806,54 +1862,105 @@ class Entity {
|
|
|
1806
1862
|
return utilities.formatKeyCasing(key, casing);
|
|
1807
1863
|
}
|
|
1808
1864
|
|
|
1809
|
-
_findBestIndexKeyMatch(attributes) {
|
|
1810
|
-
|
|
1865
|
+
_findBestIndexKeyMatch(attributes = {}) {
|
|
1866
|
+
// an array of arrays, representing the order of pk and sk composites specified for each index, and then an
|
|
1867
|
+
// array with each access pattern occupying the same array index.
|
|
1811
1868
|
let facets = this.model.facets.bySlot;
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
for (let
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
let match = !!attributes[name];
|
|
1827
|
-
let matchNext = !!attributes[next];
|
|
1828
|
-
if (match) {
|
|
1829
|
-
keys[index] = keys[index] || [];
|
|
1830
|
-
keys[index].push({ name, type });
|
|
1831
|
-
currentMatches.push(slot);
|
|
1832
|
-
if (matchNext) {
|
|
1833
|
-
nextMatches.push(slot);
|
|
1834
|
-
}
|
|
1869
|
+
// a flat array containing the match results of each access pattern, in the same array index they occur within
|
|
1870
|
+
// bySlot above
|
|
1871
|
+
let matches = [];
|
|
1872
|
+
for (let f = 0; f < facets.length; f++) {
|
|
1873
|
+
const slots = facets[f] || [];
|
|
1874
|
+
for (let s = 0; s < slots.length; s++) {
|
|
1875
|
+
const accessPatternSlot = slots[s];
|
|
1876
|
+
matches[s] = matches[s] || {
|
|
1877
|
+
index: accessPatternSlot.index,
|
|
1878
|
+
allKeys: false,
|
|
1879
|
+
hasSk: false,
|
|
1880
|
+
count: 0,
|
|
1881
|
+
done: false,
|
|
1882
|
+
keys: []
|
|
1835
1883
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1884
|
+
// already determined to be out of contention on prior iteration
|
|
1885
|
+
const indexOutOfContention = matches[s].done;
|
|
1886
|
+
// composite shorter than other indexes
|
|
1887
|
+
const lacksAttributeAtSlot = !accessPatternSlot;
|
|
1888
|
+
// attribute at this slot is not in the object provided
|
|
1889
|
+
const attributeNotProvided = accessPatternSlot && attributes[accessPatternSlot.name] === undefined;
|
|
1890
|
+
// if the next attribute is a sort key then all partition keys were provided
|
|
1891
|
+
const nextAttributeIsSortKey = accessPatternSlot && accessPatternSlot.next && facets[f+1][s].type === "sk";
|
|
1892
|
+
// if no keys are left then all attribute requirements were met (remember indexes don't require a sort key)
|
|
1893
|
+
const hasAllKeys = accessPatternSlot && !accessPatternSlot.next;
|
|
1894
|
+
|
|
1895
|
+
// no sense iterating on items we know to be "done"
|
|
1896
|
+
if (indexOutOfContention || lacksAttributeAtSlot || attributeNotProvided) {
|
|
1897
|
+
matches[s].done = true;
|
|
1840
1898
|
continue;
|
|
1841
|
-
} else {
|
|
1842
|
-
match = facets[i][currentMatches[0]].index;
|
|
1843
|
-
break;
|
|
1844
1899
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1900
|
+
|
|
1901
|
+
// if the next attribute is a sort key (and you reached this line) then you have fulfilled all the
|
|
1902
|
+
// partition key requirements for this index
|
|
1903
|
+
if (nextAttributeIsSortKey) {
|
|
1904
|
+
matches[s].hasSk = true;
|
|
1905
|
+
// if you reached this step and there are no more attributes, then you fulfilled the index
|
|
1906
|
+
} else if (hasAllKeys) {
|
|
1907
|
+
matches[s].allKeys = true;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// number of successfully fulfilled attributes plays into the ranking heuristic
|
|
1911
|
+
matches[s].count++;
|
|
1912
|
+
|
|
1913
|
+
// note the names/types of fulfilled attributes
|
|
1914
|
+
matches[s].keys.push({
|
|
1915
|
+
name: accessPatternSlot.name,
|
|
1916
|
+
type: accessPatternSlot.type
|
|
1917
|
+
});
|
|
1850
1918
|
}
|
|
1851
1919
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1920
|
+
// the highest count of matched attributes among all access patterns
|
|
1921
|
+
let max = 0;
|
|
1922
|
+
matches = matches
|
|
1923
|
+
// remove incomplete indexes
|
|
1924
|
+
.filter(match => match.hasSk || match.allKeys)
|
|
1925
|
+
// calculate max attribute match
|
|
1926
|
+
.map(match => {
|
|
1927
|
+
max = Math.max(max, match.count);
|
|
1928
|
+
return match;
|
|
1929
|
+
});
|
|
1930
|
+
|
|
1931
|
+
// matched contains the ranked attributes. The closer an element is to zero the "higher" the rank.
|
|
1932
|
+
const matched = [];
|
|
1933
|
+
for (let m = 0; m < matches.length; m++) {
|
|
1934
|
+
const match = matches[m];
|
|
1935
|
+
// a finished primary index is most ideal (could be a get)
|
|
1936
|
+
const primaryIndexIsFinished = match.index === "" && match.allKeys;
|
|
1937
|
+
// if there is a tie for matched index attributes, primary index should win
|
|
1938
|
+
const primaryIndexIsMostMatched = match.index === "" && match.count === max;
|
|
1939
|
+
// composite attributes are complete
|
|
1940
|
+
const indexRequirementsFulfilled = match.allKeys;
|
|
1941
|
+
// having the most matches is important
|
|
1942
|
+
const hasTheMostAttributeMatches = match.count === max;
|
|
1943
|
+
if (primaryIndexIsFinished) {
|
|
1944
|
+
matched[0] = match;
|
|
1945
|
+
} else if (primaryIndexIsMostMatched) {
|
|
1946
|
+
matched[1] = match;
|
|
1947
|
+
} else if (indexRequirementsFulfilled) {
|
|
1948
|
+
matched[2] = match;
|
|
1949
|
+
} else if (hasTheMostAttributeMatches) {
|
|
1950
|
+
matched[3] = match;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
// find the first non-undefined element (best ranked) -- if possible
|
|
1954
|
+
const match = matched.find(value => !!value);
|
|
1955
|
+
let keys = [];
|
|
1956
|
+
let index = "";
|
|
1957
|
+
let shouldScan = true;
|
|
1958
|
+
if (match) {
|
|
1959
|
+
keys = match.keys;
|
|
1960
|
+
index = match.index;
|
|
1961
|
+
shouldScan = false;
|
|
1962
|
+
}
|
|
1963
|
+
return { keys, index, shouldScan };
|
|
1857
1964
|
}
|
|
1858
1965
|
|
|
1859
1966
|
/* istanbul ignore next */
|
|
@@ -1890,7 +1997,7 @@ class Entity {
|
|
|
1890
1997
|
type = "name";
|
|
1891
1998
|
} else if (char === "}" && type === "name") {
|
|
1892
1999
|
if (current.name.match(/^\s*$/)) {
|
|
1893
|
-
throw new e.ElectroError(e.ErrorCodes.InvalidKeyCompositeAttributeTemplate, `Invalid key composite attribute template. Empty expression "\${${current.name}" provided. Expected attribute name.`);
|
|
2000
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidKeyCompositeAttributeTemplate, `Invalid key composite attribute template. Empty expression "\${${current.name}}" provided. Expected attribute name.`);
|
|
1894
2001
|
}
|
|
1895
2002
|
attributes.push({name: current.name, label: current.label});
|
|
1896
2003
|
current.name = "";
|
package/src/errors.js
CHANGED
|
@@ -151,6 +151,18 @@ const ErrorCodes = {
|
|
|
151
151
|
name: "InvalidConcurrencyOption",
|
|
152
152
|
sym: ErrorCode
|
|
153
153
|
},
|
|
154
|
+
InvalidPagesOption: {
|
|
155
|
+
code: 2005,
|
|
156
|
+
section: "invalid-pages-option",
|
|
157
|
+
name: "InvalidPagesOption",
|
|
158
|
+
sym: ErrorCode,
|
|
159
|
+
},
|
|
160
|
+
InvalidLimitOption: {
|
|
161
|
+
code: 2006,
|
|
162
|
+
section: "invalid-limit-option",
|
|
163
|
+
name: "InvalidLimitOption",
|
|
164
|
+
sym: ErrorCode,
|
|
165
|
+
},
|
|
154
166
|
InvalidAttribute: {
|
|
155
167
|
code: 3001,
|
|
156
168
|
section: "invalid-attribute",
|
|
@@ -195,28 +207,112 @@ const ErrorCodes = {
|
|
|
195
207
|
},
|
|
196
208
|
};
|
|
197
209
|
|
|
210
|
+
function makeMessage(message, section) {
|
|
211
|
+
return `${message} - For more detail on this error reference: ${getHelpLink(section)}`
|
|
212
|
+
}
|
|
213
|
+
|
|
198
214
|
class ElectroError extends Error {
|
|
199
|
-
constructor(
|
|
215
|
+
constructor(code, message) {
|
|
200
216
|
super(message);
|
|
201
217
|
let detail = ErrorCodes.UnknownError;
|
|
202
|
-
if (
|
|
203
|
-
detail =
|
|
218
|
+
if (code && code.sym === ErrorCode) {
|
|
219
|
+
detail = code
|
|
204
220
|
}
|
|
205
|
-
this.
|
|
206
|
-
|
|
221
|
+
this._message = message;
|
|
222
|
+
// this.message = `${message} - For more detail on this error reference: ${getHelpLink(detail.section)}`;
|
|
223
|
+
this.message = makeMessage(message, detail.section);
|
|
207
224
|
if (Error.captureStackTrace) {
|
|
208
225
|
Error.captureStackTrace(this, ElectroError);
|
|
209
226
|
}
|
|
210
227
|
|
|
211
228
|
this.name = 'ElectroError';
|
|
212
|
-
this.ref =
|
|
229
|
+
this.ref = code;
|
|
213
230
|
this.code = detail.code;
|
|
214
|
-
this.date =
|
|
231
|
+
this.date = Date.now();
|
|
215
232
|
this.isElectroError = true;
|
|
216
233
|
}
|
|
217
234
|
}
|
|
218
235
|
|
|
236
|
+
class ElectroValidationError extends ElectroError {
|
|
237
|
+
constructor(errors = []) {
|
|
238
|
+
const fields = [];
|
|
239
|
+
const messages = [];
|
|
240
|
+
for (let i = 0; i < errors.length; i++) {
|
|
241
|
+
const error = errors[i];
|
|
242
|
+
const message = error ? (error._message || error.message) : undefined;
|
|
243
|
+
messages.push(message);
|
|
244
|
+
if (error instanceof ElectroUserValidationError) {
|
|
245
|
+
fields.push({
|
|
246
|
+
field: error.field,
|
|
247
|
+
index: error.index,
|
|
248
|
+
reason: message,
|
|
249
|
+
cause: error.cause,
|
|
250
|
+
type: 'validation'
|
|
251
|
+
});
|
|
252
|
+
} else if (error instanceof ElectroAttributeValidationError) {
|
|
253
|
+
fields.push({
|
|
254
|
+
field: error.field,
|
|
255
|
+
index: error.index,
|
|
256
|
+
reason: message,
|
|
257
|
+
cause: error.cause || error, // error | undefined
|
|
258
|
+
type: 'validation'
|
|
259
|
+
});
|
|
260
|
+
} else if (message) {
|
|
261
|
+
fields.push({
|
|
262
|
+
field: '',
|
|
263
|
+
index: error.index,
|
|
264
|
+
reason: message,
|
|
265
|
+
cause: error !== undefined ? error.cause || error : undefined,
|
|
266
|
+
type: 'fatal'
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const message = messages
|
|
272
|
+
.filter(message => typeof message === "string" && message.length)
|
|
273
|
+
.join(', ') || `Invalid value(s) provided`;
|
|
274
|
+
|
|
275
|
+
super(ErrorCodes.InvalidAttribute, message);
|
|
276
|
+
this.fields = fields;
|
|
277
|
+
this.name = "ElectroValidationError";
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
class ElectroUserValidationError extends ElectroError {
|
|
282
|
+
constructor(field, cause) {
|
|
283
|
+
let message;
|
|
284
|
+
let hasCause = false;
|
|
285
|
+
if (typeof cause === "string") {
|
|
286
|
+
message = cause;
|
|
287
|
+
} else if (cause !== undefined && typeof cause._message === "string" && cause._message.length) {
|
|
288
|
+
message = cause._message;
|
|
289
|
+
hasCause = true;
|
|
290
|
+
} else if (cause !== undefined && typeof cause.message === "string" && cause.message.length) {
|
|
291
|
+
message = cause.message;
|
|
292
|
+
hasCause = true;
|
|
293
|
+
} else {
|
|
294
|
+
message = "Invalid value provided";
|
|
295
|
+
}
|
|
296
|
+
super(ErrorCodes.InvalidAttribute, message);
|
|
297
|
+
this.field = field;
|
|
298
|
+
this.name = "ElectroUserValidationError";
|
|
299
|
+
if (hasCause) {
|
|
300
|
+
this.cause = cause;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
class ElectroAttributeValidationError extends ElectroError {
|
|
306
|
+
constructor(field, reason) {
|
|
307
|
+
super(ErrorCodes.InvalidAttribute, reason);
|
|
308
|
+
this.field = field;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
219
312
|
module.exports = {
|
|
313
|
+
ErrorCodes,
|
|
220
314
|
ElectroError,
|
|
221
|
-
|
|
315
|
+
ElectroValidationError,
|
|
316
|
+
ElectroUserValidationError,
|
|
317
|
+
ElectroAttributeValidationError
|
|
222
318
|
};
|
package/src/operations.js
CHANGED
|
@@ -453,4 +453,9 @@ class AttributeOperationProxy {
|
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
|
|
456
|
+
const FilterOperationNames = Object.keys(FilterOperations).reduce((ops, name) => {
|
|
457
|
+
ops[name] = name;
|
|
458
|
+
return ops;
|
|
459
|
+
}, {});
|
|
460
|
+
|
|
461
|
+
module.exports = {UpdateOperations, FilterOperations, FilterOperationNames, ExpressionState, AttributeOperationProxy};
|