electrodb 2.3.5 → 2.4.1
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/index.d.ts +28 -1
- package/index.js +2 -1
- package/package.json +1 -1
- package/src/operations.js +88 -27
- package/src/schema.js +23 -3
- package/src/types.js +18 -0
package/index.d.ts
CHANGED
|
@@ -116,6 +116,18 @@ export type IsolatedCollectionAttributes<E extends {[name: string]: Entity<any,
|
|
|
116
116
|
}[keyof E]
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
type DynamoDBAttributeType =
|
|
120
|
+
| 'S'
|
|
121
|
+
| 'SS'
|
|
122
|
+
| 'N'
|
|
123
|
+
| 'NS'
|
|
124
|
+
| 'B'
|
|
125
|
+
| 'BS'
|
|
126
|
+
| 'BOOL'
|
|
127
|
+
| 'NULL'
|
|
128
|
+
| 'L'
|
|
129
|
+
| 'M'
|
|
130
|
+
|
|
119
131
|
export interface CollectionWhereOperations {
|
|
120
132
|
eq: <T, A extends WhereAttributeSymbol<T>>(attr: A, value: T) => string;
|
|
121
133
|
ne: <T, A extends WhereAttributeSymbol<T>>(attr: A, value: T) => string;
|
|
@@ -131,6 +143,12 @@ export interface CollectionWhereOperations {
|
|
|
131
143
|
notContains: <T, A extends WhereAttributeSymbol<T>>(attr: A, value: T) => string;
|
|
132
144
|
value: <T, A extends WhereAttributeSymbol<T>>(attr: A, value: T) => string;
|
|
133
145
|
name: <T, A extends WhereAttributeSymbol<T>>(attr: A) => string;
|
|
146
|
+
size: <T, A extends WhereAttributeSymbol<T>>(attr: A) => string;
|
|
147
|
+
type: <T, A extends WhereAttributeSymbol<T>>(attr: A, type: DynamoDBAttributeType) => string;
|
|
148
|
+
escape: <T extends string | number | boolean>(value: T) => T extends string ? string
|
|
149
|
+
: T extends number ? number
|
|
150
|
+
: T extends boolean ? boolean
|
|
151
|
+
: never;
|
|
134
152
|
}
|
|
135
153
|
|
|
136
154
|
export type CollectionWhereCallback<E extends {[name: string]: Entity<any, any, any, any>}, I extends Partial<AllEntityAttributes<E>>> =
|
|
@@ -2199,6 +2217,13 @@ export interface WhereOperations<A extends string, F extends string, C extends s
|
|
|
2199
2217
|
notContains: <T, A extends WhereAttributeSymbol<T>>(attr: A, value: T) => string;
|
|
2200
2218
|
value: <T, A extends WhereAttributeSymbol<T>>(attr: A, value: A extends WhereAttributeSymbol<infer V> ? V : never) => A extends WhereAttributeSymbol<infer V> ? V : never;
|
|
2201
2219
|
name: <A extends WhereAttributeSymbol<any>>(attr: A) => string;
|
|
2220
|
+
size: <T, A extends WhereAttributeSymbol<T>>(attr: A) => number;
|
|
2221
|
+
type: <T, A extends WhereAttributeSymbol<T>>(attr: A, type: DynamoDBAttributeType) => string;
|
|
2222
|
+
escape: <T extends string | number | boolean>(value: T) =>
|
|
2223
|
+
T extends string ? string
|
|
2224
|
+
: T extends number ? number
|
|
2225
|
+
: T extends boolean ? boolean
|
|
2226
|
+
: never;
|
|
2202
2227
|
}
|
|
2203
2228
|
|
|
2204
2229
|
export interface DataUpdateOperations<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, I extends UpdateData<A,F,C,S>> {
|
|
@@ -2347,4 +2372,6 @@ declare function CustomAttributeType<T>(
|
|
|
2347
2372
|
: 'any'
|
|
2348
2373
|
): T extends string | number | boolean
|
|
2349
2374
|
? OpaquePrimitiveTypeName<T>
|
|
2350
|
-
: CustomAttributeTypeName<T>;
|
|
2375
|
+
: CustomAttributeTypeName<T>;
|
|
2376
|
+
|
|
2377
|
+
declare function createSchema<A extends string, F extends string, C extends string, S extends Schema<A,F,C>>(schema: S): S
|
package/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
const { Entity } = require("./src/entity");
|
|
2
2
|
const { Service } = require("./src/service");
|
|
3
|
-
const { createCustomAttribute, CustomAttributeType } = require('./src/schema');
|
|
3
|
+
const { createCustomAttribute, CustomAttributeType, createSchema } = require('./src/schema');
|
|
4
4
|
const { ElectroError, ElectroValidationError, ElectroUserValidationError, ElectroAttributeValidationError } = require('./src/errors');
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
Entity,
|
|
8
8
|
Service,
|
|
9
9
|
ElectroError,
|
|
10
|
+
createSchema,
|
|
10
11
|
CustomAttributeType,
|
|
11
12
|
createCustomAttribute,
|
|
12
13
|
ElectroValidationError,
|
package/package.json
CHANGED
package/src/operations.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {AttributeTypes, ItemOperations, AttributeProxySymbol, BuilderTypes} = require("./types");
|
|
1
|
+
const {AttributeTypes, ItemOperations, AttributeProxySymbol, BuilderTypes, DynamoDBAttributeTypes} = require("./types");
|
|
2
2
|
const e = require("./errors");
|
|
3
3
|
const u = require("./util");
|
|
4
4
|
|
|
@@ -159,8 +159,26 @@ const UpdateOperations = {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
const FilterOperations = {
|
|
162
|
+
escape: {
|
|
163
|
+
template: function escape(options, attr) {
|
|
164
|
+
return `${attr}`;
|
|
165
|
+
},
|
|
166
|
+
noAttribute: true,
|
|
167
|
+
},
|
|
168
|
+
size: {
|
|
169
|
+
template: function size(options, attr, name) {
|
|
170
|
+
return `size(${name})`
|
|
171
|
+
},
|
|
172
|
+
strict: false,
|
|
173
|
+
},
|
|
174
|
+
type: {
|
|
175
|
+
template: function attributeType(options, attr, name, value) {
|
|
176
|
+
return `attribute_type(${name}, ${value})`;
|
|
177
|
+
},
|
|
178
|
+
strict: false
|
|
179
|
+
},
|
|
162
180
|
ne: {
|
|
163
|
-
template: function
|
|
181
|
+
template: function ne(options, attr, name, value) {
|
|
164
182
|
return `${name} <> ${value}`;
|
|
165
183
|
},
|
|
166
184
|
strict: false,
|
|
@@ -379,31 +397,61 @@ class AttributeOperationProxy {
|
|
|
379
397
|
|
|
380
398
|
static buildOperations(builder, operations) {
|
|
381
399
|
let ops = {};
|
|
382
|
-
let seen = new
|
|
400
|
+
let seen = new Map();
|
|
383
401
|
for (let operation of Object.keys(operations)) {
|
|
384
|
-
let {template, canNest} = operations[operation];
|
|
402
|
+
let {template, canNest, noAttribute} = operations[operation];
|
|
385
403
|
Object.defineProperty(ops, operation, {
|
|
386
404
|
get: () => {
|
|
387
405
|
return (property, ...values) => {
|
|
388
406
|
if (property === undefined) {
|
|
389
407
|
throw new e.ElectroError(e.ErrorCodes.InvalidWhere, `Invalid/Unknown property passed in where clause passed to operation: '${operation}'`);
|
|
390
408
|
}
|
|
391
|
-
if (property
|
|
392
|
-
const {
|
|
409
|
+
if (property[AttributeProxySymbol]) {
|
|
410
|
+
const {commit, target} = property();
|
|
411
|
+
const fixedValues = values.map((value) => target.applyFixings(value))
|
|
412
|
+
.filter(value => value !== undefined);
|
|
413
|
+
const isFilterBuilder = builder.type === BuilderTypes.filter;
|
|
414
|
+
const takesValueArgument = template.length > 3;
|
|
415
|
+
const isAcceptableValue = fixedValues.every(value => {
|
|
416
|
+
const seenAttributes = seen.get(value);
|
|
417
|
+
if (seenAttributes) {
|
|
418
|
+
return seenAttributes.every(v => target.acceptable(v))
|
|
419
|
+
}
|
|
420
|
+
return target.acceptable(value);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const shouldCommit =
|
|
424
|
+
// if it is a filterBuilder than we don't care what they pass because the user needs more freedom here
|
|
425
|
+
isFilterBuilder ||
|
|
426
|
+
// if the operation does not take a value argument then not committing here could cause problems.
|
|
427
|
+
// this should be revisited to make more robust, we could hypothetically store the commit in the
|
|
428
|
+
// "seen" map for when the value is used, but that's a lot of new complexity
|
|
429
|
+
!takesValueArgument ||
|
|
430
|
+
// if the operation takes a value, we should determine if that value is acceptable. For
|
|
431
|
+
// example, in the cases of a "set" we check to see if it is empty, or if the value is
|
|
432
|
+
// undefined, we should not commit. The "fixedValues" length check is because the
|
|
433
|
+
// "fixedValues" array has been filtered for undefined, so no length there indicates an
|
|
434
|
+
// undefined value was passed.
|
|
435
|
+
(takesValueArgument && isAcceptableValue && fixedValues.length > 0);
|
|
436
|
+
|
|
437
|
+
if (!shouldCommit) {
|
|
438
|
+
return '';
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const paths = commit();
|
|
393
442
|
const attributeValues = [];
|
|
394
443
|
let hasNestedValue = false;
|
|
395
|
-
for (let
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
444
|
+
for (let fixedValue of fixedValues) {
|
|
445
|
+
if (seen.has(fixedValue)) {
|
|
446
|
+
attributeValues.push(fixedValue);
|
|
447
|
+
hasNestedValue = true;
|
|
448
|
+
} else {
|
|
449
|
+
let attributeValueName = builder.setValue(target.name, fixedValue);
|
|
450
|
+
builder.setPath(paths.json, {
|
|
451
|
+
value: fixedValue,
|
|
452
|
+
name: attributeValueName
|
|
453
|
+
});
|
|
454
|
+
attributeValues.push(attributeValueName);
|
|
407
455
|
}
|
|
408
456
|
}
|
|
409
457
|
|
|
@@ -414,8 +462,8 @@ class AttributeOperationProxy {
|
|
|
414
462
|
const formatted = template(options, target, paths.expression, ...attributeValues);
|
|
415
463
|
builder.setImpacted(operation, paths.json, target);
|
|
416
464
|
if (canNest) {
|
|
417
|
-
seen.
|
|
418
|
-
seen.
|
|
465
|
+
seen.set(paths.expression, attributeValues);
|
|
466
|
+
seen.set(formatted, attributeValues);
|
|
419
467
|
}
|
|
420
468
|
|
|
421
469
|
if (builder.type === BuilderTypes.update && formatted && typeof formatted.operation === "string" && typeof formatted.expression === "string") {
|
|
@@ -423,6 +471,17 @@ class AttributeOperationProxy {
|
|
|
423
471
|
return formatted.expression;
|
|
424
472
|
}
|
|
425
473
|
|
|
474
|
+
return formatted;
|
|
475
|
+
} else if (noAttribute) {
|
|
476
|
+
// const {json, expression} = builder.setName({}, property, property);
|
|
477
|
+
let attributeValueName = builder.setValue(property, property);
|
|
478
|
+
builder.setPath(property, {
|
|
479
|
+
value: property,
|
|
480
|
+
name: attributeValueName,
|
|
481
|
+
});
|
|
482
|
+
const formatted = template({}, attributeValueName);
|
|
483
|
+
seen.set(attributeValueName, [property]);
|
|
484
|
+
seen.set(formatted, [property]);
|
|
426
485
|
return formatted;
|
|
427
486
|
} else {
|
|
428
487
|
throw new e.ElectroError(e.ErrorCodes.InvalidWhere, `Invalid Attribute in where clause passed to operation '${operation}'. Use injected attributes only.`);
|
|
@@ -437,15 +496,15 @@ class AttributeOperationProxy {
|
|
|
437
496
|
static pathProxy(build) {
|
|
438
497
|
return new Proxy(() => build(), {
|
|
439
498
|
get: (_, prop, o) => {
|
|
440
|
-
if (prop ===
|
|
441
|
-
return
|
|
499
|
+
if (prop === AttributeProxySymbol) {
|
|
500
|
+
return true;
|
|
442
501
|
} else {
|
|
443
502
|
return AttributeOperationProxy.pathProxy(() => {
|
|
444
|
-
const {
|
|
503
|
+
const { commit, root, target, builder } = build();
|
|
445
504
|
const attribute = target.getChild(prop);
|
|
446
505
|
let field;
|
|
447
506
|
if (attribute === undefined) {
|
|
448
|
-
throw new Error(`Invalid attribute "${prop}" at path "${
|
|
507
|
+
throw new Error(`Invalid attribute "${prop}" at path "${target.path}.${prop}"`);
|
|
449
508
|
} else if (attribute === root && attribute.type === AttributeTypes.any) {
|
|
450
509
|
// This function is only called if a nested property is called. If this attribute is ultimately the root, don't use the root's field name
|
|
451
510
|
field = prop;
|
|
@@ -457,7 +516,10 @@ class AttributeOperationProxy {
|
|
|
457
516
|
root,
|
|
458
517
|
builder,
|
|
459
518
|
target: attribute,
|
|
460
|
-
|
|
519
|
+
commit: () => {
|
|
520
|
+
const paths = commit();
|
|
521
|
+
return builder.setName(paths, prop, field);
|
|
522
|
+
},
|
|
461
523
|
}
|
|
462
524
|
});
|
|
463
525
|
}
|
|
@@ -471,12 +533,11 @@ class AttributeOperationProxy {
|
|
|
471
533
|
Object.defineProperty(attr, name, {
|
|
472
534
|
get: () => {
|
|
473
535
|
return AttributeOperationProxy.pathProxy(() => {
|
|
474
|
-
const paths = builder.setName({}, attribute.name, attribute.field);
|
|
475
536
|
return {
|
|
476
|
-
paths,
|
|
477
537
|
root: attribute,
|
|
478
538
|
target: attribute,
|
|
479
539
|
builder,
|
|
540
|
+
commit: () => builder.setName({}, attribute.name, attribute.field)
|
|
480
541
|
}
|
|
481
542
|
});
|
|
482
543
|
}
|
package/src/schema.js
CHANGED
|
@@ -238,7 +238,11 @@ class Attribute {
|
|
|
238
238
|
|
|
239
239
|
_makeApplyFixings({ prefix = "", postfix = "", casing= KeyCasing.none } = {}) {
|
|
240
240
|
return (value) => {
|
|
241
|
-
if (
|
|
241
|
+
if (value === undefined) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if ([AttributeTypes.string, AttributeTypes.enum].includes(this.type)) {
|
|
242
246
|
value = `${prefix}${value}${postfix}`;
|
|
243
247
|
}
|
|
244
248
|
|
|
@@ -305,6 +309,10 @@ class Attribute {
|
|
|
305
309
|
};
|
|
306
310
|
}
|
|
307
311
|
|
|
312
|
+
acceptable(val) {
|
|
313
|
+
return val !== undefined;
|
|
314
|
+
}
|
|
315
|
+
|
|
308
316
|
getPathType(type, parentType) {
|
|
309
317
|
if (parentType === AttributeTypes.list || parentType === AttributeTypes.set) {
|
|
310
318
|
return PathTypes.item;
|
|
@@ -876,12 +884,18 @@ class SetAttribute extends Attribute {
|
|
|
876
884
|
value = Array.isArray(value)
|
|
877
885
|
? Array.from(new Set(value))
|
|
878
886
|
: value;
|
|
879
|
-
return this.client.createSet(value, {validate: true});
|
|
887
|
+
return this.client.createSet(value, { validate: true });
|
|
880
888
|
} else {
|
|
881
889
|
return new DynamoDBSet(value, this.items.type);
|
|
882
890
|
}
|
|
883
891
|
}
|
|
884
892
|
|
|
893
|
+
acceptable(val) {
|
|
894
|
+
return Array.isArray(val)
|
|
895
|
+
? val.length > 0
|
|
896
|
+
: this.items.acceptable(val);
|
|
897
|
+
}
|
|
898
|
+
|
|
885
899
|
toDDBSet(value) {
|
|
886
900
|
const valueType = getValueType(value);
|
|
887
901
|
let array;
|
|
@@ -1474,11 +1488,17 @@ function CustomAttributeType(base) {
|
|
|
1474
1488
|
return base;
|
|
1475
1489
|
}
|
|
1476
1490
|
|
|
1491
|
+
function createSchema(schema) {
|
|
1492
|
+
v.model(schema);
|
|
1493
|
+
return schema;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1477
1496
|
module.exports = {
|
|
1478
1497
|
Schema,
|
|
1479
1498
|
Attribute,
|
|
1480
|
-
SetAttribute,
|
|
1481
1499
|
CastTypes,
|
|
1500
|
+
SetAttribute,
|
|
1501
|
+
createSchema,
|
|
1482
1502
|
CustomAttributeType,
|
|
1483
1503
|
createCustomAttribute,
|
|
1484
1504
|
};
|
package/src/types.js
CHANGED
|
@@ -271,6 +271,23 @@ const ResultOrderOption = {
|
|
|
271
271
|
|
|
272
272
|
const ResultOrderParam = 'ScanIndexForward';
|
|
273
273
|
|
|
274
|
+
const DynamoDBAttributeTypes = Object.entries({
|
|
275
|
+
string: 'S',
|
|
276
|
+
stringSet: 'SS',
|
|
277
|
+
number: 'N',
|
|
278
|
+
numberSet: 'NS',
|
|
279
|
+
binary: 'B',
|
|
280
|
+
binarySet: 'BS',
|
|
281
|
+
boolean: 'BOOL',
|
|
282
|
+
null: 'NULL',
|
|
283
|
+
list: 'L',
|
|
284
|
+
map: 'M',
|
|
285
|
+
}).reduce((obj, [name, type]) => {
|
|
286
|
+
obj[name] = type;
|
|
287
|
+
obj[type] = type;
|
|
288
|
+
return obj;
|
|
289
|
+
}, {});
|
|
290
|
+
|
|
274
291
|
module.exports = {
|
|
275
292
|
Pager,
|
|
276
293
|
KeyTypes,
|
|
@@ -303,6 +320,7 @@ module.exports = {
|
|
|
303
320
|
ElectroInstanceTypes,
|
|
304
321
|
MethodTypeTranslation,
|
|
305
322
|
EventSubscriptionTypes,
|
|
323
|
+
DynamoDBAttributeTypes,
|
|
306
324
|
AttributeMutationMethods,
|
|
307
325
|
AllPages,
|
|
308
326
|
ResultOrderOption,
|