electrodb 2.2.3 → 2.2.5
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/README.md +6 -0
- package/package.json +1 -1
- package/src/clauses.js +10 -1
- package/src/entity.js +1 -1
- package/src/filters.js +1 -0
- package/src/operations.js +33 -18
- package/src/schema.js +13 -11
- package/src/where.js +1 -0
- package/output +0 -2299
package/README.md
CHANGED
|
@@ -3419,6 +3419,8 @@ operation | example | result
|
|
|
3419
3419
|
`value` | `value(rent, amount)` | `:rent1` | Create a reference to a particular value, can be passed to other operation that allows leveraging existing attribute values in calculating new values
|
|
3420
3420
|
`ifNotExists` | `ifNotExists(rent, amount)` | `#rent = if_not_exists(#rent, :rent0)` | Update a property's value only if that property doesn't yet exist on the record
|
|
3421
3421
|
|
|
3422
|
+
> _NOTE: Usage of `name` and `value` operations allow for some escape hatching in the case that a custom operation needs to be expressed. When used however, ElectroDB loses the context necessary to validate the expression created by the user. In practical terms, this means the `validation` function/regex on the impacted attribute will not be called._
|
|
3423
|
+
|
|
3422
3424
|
Example:
|
|
3423
3425
|
```javascript
|
|
3424
3426
|
await StoreLocations
|
|
@@ -5688,6 +5690,8 @@ const person = new Entity({
|
|
|
5688
5690
|
}, { table });
|
|
5689
5691
|
```
|
|
5690
5692
|
|
|
5693
|
+
[](https://electrodb.fun/?ssl=3&ssc=29&pln=37&pc=2#code/JYWwDg9gTgLgBAbzgUQHY2DAngGjgYQFcBnGCEAQRhimACNCYBTAFSzCbgF84AzKcnADkTADZMAxjQgATOkIDcAKCUSIqUnACqqYAEdCTANJMsAZSwg6EUQC44hXQc7FL10XAC8cC1ZsAKAEplbA4UcFEILCYmAEkAES84UlpUAHM4ADJEAG0dfUMTczcbAF17AENULC5lVXVNfOcKNKZfd3tHApcSj292gOClUM4AWXUYAAsk1EIrJigs3KbDFrbe8rgqmrqRuAAFBeJ1VDEAJRtObwQlODu4EfsRCKiYxVv70grYeIrmexSwHSynucCYqBkv2YAH4ATQgWllDwAD6ID53R7CNToKAVKTQd6g7E0PEwMwwb4wKFMOGpRHouDE3FSNCQv405Lw4FKWoqbGaCl0cRJIQAd2gAGswKI8UwAPqC8TveoaeAcKDHVAzJiilDoTBYfw3UEgWRiezG0H3cEYbBPdWa06iIQ4Bmg4gLABuwAkHLFkulspdbvunqOwHUTwAjEIGVxXaC-vCGMxiBaQ3cmC9onEZOmrQWHuwOURSOQqMnGKxiwAeZDZmIJAB8-iEgPSQkCGe4CcLWelrwW+cLoMxba5aVjI-j3d4wA1MAAchUQBzLSOMcWnu3J72N3AoEwDPOmHmHlBDHurTORzLSMvV8P92Od8H93dD8fD2eaJfuzfCwqVonw3MdZnmKAp0LACCyAuJUHGdBJjTNF3zgUU-gkSZ7ByIQ4KEUorxHTFSzIShqFoFNqw4GtEKmFshHAugFk7IjCw9GB7CCLwm0QGCNxkJheAqQhRE4uBuM8XiEH4kdWnE-w5XsOjJjwBA4K4C04PsJiFi4QIeNQtD7kPGBCCgLVRj+SYADpeEiaB-DguAAHo4CjAAmIY0K4f82I-S4QOIrcCBIMiK0oqs2Bow4NROc5LgY7ZWP-OMryBQSAA8mBQ9crUPNQoDPPKRzACUgvfOcxDPIQyrfYy7jUcAIGITAOVw-tIhzSDSm7UFZPY8qjIaqrRBq4gJXqhqmsgVr-jgDqG1zAj-OvVL+p5NSHgqIVOH0up+XgCRD3ZWIZCSIJ7HrAccwSQy8tM8ytQAAwAEgQakbNQCBRSCLhnq2Yhwhuxt4iRFQHXUBkbOOph2SNbsXLc4gOAkYAKg8CAwAqZw4GAc6Rm7TrBzO+xYdOmQglW4nuqefYqkICQ0aB-ZgAALzZiopqtOcFwfP19kmYBRGAMBudBO8lxXP0ADEoCwcX7m0uAPIAVlWgRxAqgsxxpt5VvdCkfnZaMAE5TYAdgAWgABg8q2PNNxWC3BNl5qEKNzdNq3PKtgBmGNVt8-qu1BGy0ggIJoamcF-EPYhRPgKThqtJGDyYMyLKLDggYx448fAUlT27ePE5smQ-gqGy4NiBCJmQuNAiAA)
|
|
5694
|
+
|
|
5691
5695
|
### Opaque Keys
|
|
5692
5696
|
If you use Opaque Keys for identifiers or other primitive types, you can use the function `CustomAttributeType` and pass it the primitive base type of your key ('string', 'number', 'boolean'). This can be useful to gain more precise control over which properties can be used as entity identifiers, create unique unit types, etc.
|
|
5693
5697
|
|
|
@@ -5739,6 +5743,8 @@ const person = new Entity({
|
|
|
5739
5743
|
}, { table });
|
|
5740
5744
|
```
|
|
5741
5745
|
|
|
5746
|
+
[](https://electrodb.fun/?ssl=3&ssc=29&pln=37&pc=2#code/JYWwDg9gTgLgBAbzgUQHY2DAngGjgYQFcBnGCEAQRhimACNCYBTAFSzCbgF84AzKcnADkTADZMAxjQgATOkIDcAKCUSIqUnACqqYAEdCTANJMsAZSwg6EUQC44hXQc7FL10XAC8cC1ZsAKAEplbA4UcFEILCYmAEkAES84UlpUAHM4ADJEAG0dfUMTczcbAF17AENULC5lVXVNfOcKNKZfd3tHApcSj292gOClUM4AWXUYAAsk1EIrJigs3KbDFrbe8rgqmrqRuAAFBeJ1VDEAJRtObwQlODu4EfsRCKiYxVv70grYeIrmexSwHSynucCYqBkv2YAH4ATQgWllDwAD6ID53R7CNToKAVKTQd6g7E0PEwMwwb4wKFMOGpRHouDE3FSNCQv405Lw4FKWoqbGaCl0cRJIQAd2gAGswKI8UwAPqC8TveoaeAcKDHVAzJiilDoTBYfw3UEgWRiezG0H3cEYbBPdWa06iIQ4Bmg4gLABuwAkHLFkulspdbvunqOwHUTwAjEIGVxXaC-vCGMxiBaQ3cmC9onEZOmrQWHuwOURSOQqMnGKxiwAeZDZmIJAB8-iEgPSQkCGe4CcLWelrwW+cLoMxba5aVjI-j3d4wA1MAAchUQBzLSOMcWnu3J72N3AoEwDPOmHmHlBDHurTORzLSMvV8P92Od8H93dD8fD2eaJfuzfCwqVonw3MdZnmKAp0LACCyAuJUHGdBJjTNF3zgUU-gkSZ7ByIQ4KEUorxHTFSzIShqFoFNqw4GtEKmFshHAugFk7IjCw9GB7CCLwm0QGCNxkJheAqQhRE4uBuM8XiEH4kdWnE-w5XsOjJjwBA4K4C04PsJiFi4QIeNQtD7kPGBCCgLVRj+SYADpeEiaB-DguAAHo4CjAAmIY0K4f82I-S4QOIrcCBIMiK0oqs2Bow4NROc5LgY7ZWP-OMryBQSAA8mBQ9crUPNQoDPPKRzACUgvfOcxDPIQyrfYy7jUcAIGITAOVw-tIhzSDSm7UFZPY8qjIaqrRBq4gJXqhqmsgVr-jgDqG1zAj-OvVL+p5NSHgqIVOH0up+XgCRD3ZWIZCSIJ7HrAccwSQy8tM8ytQAAwAEgQakbNQCBRSCLhnq2Yhwhuxt4iRFQHXUBkbOOph2SNbsXLc4gOAkYAKg8CAwAqZw4GAc6Rm7TrBzO+xYdOmQglW4nuqefYqkICQ0aB-ZgAALzZiopqtOcFwfP19kmYBRGAMBudBO8lxXP0ADEoCwcX7m0uAPIAVlWgRxAqgsxxpt5VvdCkfnZaMAE5TYAdgAWgABg8q2PNNxWC3BNl5qEKNzdNq3PKtgBmGNVt8-qu1BGy0ggIJoamcF-EPYhRPgKThqtJGDyYMyLKLDggYx448fAUlT27ePE5smQ-gqGy4NiBCJmQuNAiAA)
|
|
5747
|
+
|
|
5742
5748
|
## Exported Types
|
|
5743
5749
|
|
|
5744
5750
|
The following types are exported for easier use while using ElectroDB with TypeScript. The naming convention for the types include three different kinds:
|
package/package.json
CHANGED
package/src/clauses.js
CHANGED
|
@@ -309,7 +309,16 @@ let clauses = {
|
|
|
309
309
|
for (const path of Object.keys(state.query.update.refs)) {
|
|
310
310
|
const operation = state.query.update.impacted[path];
|
|
311
311
|
const attribute = state.query.update.refs[path];
|
|
312
|
-
|
|
312
|
+
// note: keyValue will be empty if the user used `name`/`value` operations
|
|
313
|
+
// because it becomes hard to know how they are used and which attribute
|
|
314
|
+
// should validate the change. This is an edge case however, this change
|
|
315
|
+
// still improves on the existing implementation.
|
|
316
|
+
const keyValue = state.query.update.paths[path] || {};
|
|
317
|
+
if (!attribute) {
|
|
318
|
+
throw new e.ElectroAttributeValidationError(path, `Attribute "${path}" does not exist on model.`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
entity.model.schema.checkOperation(attribute, operation, keyValue.value);
|
|
313
322
|
}
|
|
314
323
|
return state;
|
|
315
324
|
} catch(err) {
|
package/src/entity.js
CHANGED
|
@@ -229,7 +229,7 @@ class Entity {
|
|
|
229
229
|
if (Array.isArray(facets)) {
|
|
230
230
|
return this._makeChain(index, this._clausesWithFilters, clauses.index).batchGet(facets);
|
|
231
231
|
} else {
|
|
232
|
-
return this._makeChain(index,
|
|
232
|
+
return this._makeChain(index, this._clausesWithFilters, clauses.index).get(facets);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
package/src/filters.js
CHANGED
package/src/operations.js
CHANGED
|
@@ -431,24 +431,32 @@ class AttributeOperationProxy {
|
|
|
431
431
|
return ops;
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
static pathProxy(
|
|
435
|
-
return new Proxy(() => (
|
|
436
|
-
get: (_, prop) => {
|
|
434
|
+
static pathProxy(build) {
|
|
435
|
+
return new Proxy(() => build(), {
|
|
436
|
+
get: (_, prop, o) => {
|
|
437
437
|
if (prop === "__is_clause__") {
|
|
438
|
-
return AttributeProxySymbol
|
|
438
|
+
return AttributeProxySymbol;
|
|
439
439
|
} else {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
440
|
+
return AttributeOperationProxy.pathProxy(() => {
|
|
441
|
+
const { paths, root, target, builder } = build();
|
|
442
|
+
const attribute = target.getChild(prop);
|
|
443
|
+
let field;
|
|
444
|
+
if (attribute === undefined) {
|
|
445
|
+
throw new Error(`Invalid attribute "${prop}" at path "${paths.json}".`);
|
|
446
|
+
} else if (attribute === root && attribute.type === AttributeTypes.any) {
|
|
447
|
+
// 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
|
|
448
|
+
field = prop;
|
|
449
|
+
} else {
|
|
450
|
+
field = attribute.field;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return {
|
|
454
|
+
root,
|
|
455
|
+
builder,
|
|
456
|
+
target: attribute,
|
|
457
|
+
paths: builder.setName(paths, prop, field),
|
|
458
|
+
}
|
|
459
|
+
});
|
|
452
460
|
}
|
|
453
461
|
}
|
|
454
462
|
});
|
|
@@ -459,8 +467,15 @@ class AttributeOperationProxy {
|
|
|
459
467
|
for (let [name, attribute] of Object.entries(attributes)) {
|
|
460
468
|
Object.defineProperty(attr, name, {
|
|
461
469
|
get: () => {
|
|
462
|
-
|
|
463
|
-
|
|
470
|
+
return AttributeOperationProxy.pathProxy(() => {
|
|
471
|
+
const paths = builder.setName({}, attribute.name, attribute.field);
|
|
472
|
+
return {
|
|
473
|
+
paths,
|
|
474
|
+
root: attribute,
|
|
475
|
+
target: attribute,
|
|
476
|
+
builder,
|
|
477
|
+
}
|
|
478
|
+
});
|
|
464
479
|
}
|
|
465
480
|
});
|
|
466
481
|
}
|
package/src/schema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { CastTypes, ValueTypes, KeyCasing, AttributeTypes, AttributeMutationMethods, AttributeWildCard, PathTypes, TableIndex } = require("./types");
|
|
1
|
+
const { CastTypes, ValueTypes, KeyCasing, AttributeTypes, AttributeMutationMethods, AttributeWildCard, PathTypes, TableIndex, ItemOperations } = require("./types");
|
|
2
2
|
const AttributeTypeNames = Object.keys(AttributeTypes);
|
|
3
3
|
const ValidFacetTypes = [AttributeTypes.string, AttributeTypes.number, AttributeTypes.boolean, AttributeTypes.enum];
|
|
4
4
|
const e = require("./errors");
|
|
@@ -1389,16 +1389,6 @@ class Schema {
|
|
|
1389
1389
|
return record;
|
|
1390
1390
|
}
|
|
1391
1391
|
|
|
1392
|
-
checkOperation(attribute, operation) {
|
|
1393
|
-
if (!attribute) {
|
|
1394
|
-
throw new e.ElectroAttributeValidationError(path, `Attribute "${path}" does not exist on model.`);
|
|
1395
|
-
} else if (attribute.required && operation === 'remove') {
|
|
1396
|
-
throw new e.ElectroAttributeValidationError(attribute.path, `Attribute "${attribute.path}" is Required and cannot be removed`);
|
|
1397
|
-
} else if (attribute.readOnly) {
|
|
1398
|
-
throw new e.ElectroAttributeValidationError(attribute.path, `Attribute "${attribute.path}" is Read-Only and cannot be updated`);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
1392
|
checkRemove(paths = []) {
|
|
1403
1393
|
for (const path of paths) {
|
|
1404
1394
|
const attribute = this.traverser.getPath(path);
|
|
@@ -1413,6 +1403,18 @@ class Schema {
|
|
|
1413
1403
|
return paths;
|
|
1414
1404
|
}
|
|
1415
1405
|
|
|
1406
|
+
checkOperation(attribute, operation, value) {
|
|
1407
|
+
if (attribute.required && operation === ItemOperations.remove) {
|
|
1408
|
+
throw new e.ElectroAttributeValidationError(attribute.path, `Attribute "${attribute.path}" is Required and cannot be removed`);
|
|
1409
|
+
} else if (attribute.readOnly) {
|
|
1410
|
+
throw new e.ElectroAttributeValidationError(attribute.path, `Attribute "${attribute.path}" is Read-Only and cannot be updated`);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
return value === undefined
|
|
1414
|
+
? undefined
|
|
1415
|
+
: attribute.getValidate(value);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1416
1418
|
checkUpdate(payload = {}) {
|
|
1417
1419
|
let record = {};
|
|
1418
1420
|
for (let [path, attribute] of this.traverser.getAll()) {
|