electrodb 2.2.2 → 2.2.4
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 +67 -6
- package/index.d.ts +52 -31
- package/index.js +3 -2
- 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/schema.js +22 -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
|
|
@@ -5635,12 +5637,16 @@ let stores = await StoreLocations.malls({mallId}).query({buildingId, storeId}).g
|
|
|
5635
5637
|
ElectroDB using advanced dynamic typing techniques to automatically create types based on the configurations in your model. Changes to your model will automatically change the types returned by ElectroDB.
|
|
5636
5638
|
|
|
5637
5639
|
## Custom Attributes
|
|
5638
|
-
If you have a need for a custom attribute type (beyond those supported by ElectroDB) you can use the the export function `
|
|
5640
|
+
If you have a need for a custom attribute type (beyond those supported by ElectroDB) you can use the the export function `CustomAttributeType` or `OpaquePrimitiveType`. These functions can be passed a generic and that allow you to specify a custom attribute with ElectroDB:
|
|
5641
|
+
|
|
5642
|
+
### CustomAttributeType
|
|
5643
|
+
This function allows for a narrowing of ElectroDB's `any` type, which does not enforce runtime type checks. This can be useful for expressing complex attribute types.
|
|
5639
5644
|
|
|
5640
|
-
|
|
5645
|
+
The function `CustomAttributeType` takes one argument, which is the "base" type of the attribute. For complex objects and arrays, the base object would be "any" but you can also use a base type like "string", "number", or "boolean" to accomplish (Opaque Keys)[#opaque-keys] which can be used as Composite Attributes.
|
|
5641
5646
|
|
|
5647
|
+
In this example we accomplish a complex union type:
|
|
5642
5648
|
```typescript
|
|
5643
|
-
import { Entity,
|
|
5649
|
+
import { Entity, CustomAttributeType } from 'electrodb';
|
|
5644
5650
|
|
|
5645
5651
|
const table = 'workplace_table';
|
|
5646
5652
|
|
|
@@ -5654,7 +5660,6 @@ type PersonnelRole = {
|
|
|
5654
5660
|
contractEndDate: number;
|
|
5655
5661
|
};
|
|
5656
5662
|
|
|
5657
|
-
|
|
5658
5663
|
const person = new Entity({
|
|
5659
5664
|
model: {
|
|
5660
5665
|
entity: 'personnel',
|
|
@@ -5665,9 +5670,10 @@ const person = new Entity({
|
|
|
5665
5670
|
id: {
|
|
5666
5671
|
type: 'string'
|
|
5667
5672
|
},
|
|
5668
|
-
role:
|
|
5673
|
+
role: {
|
|
5674
|
+
type: CustomAttributeType<PersonnelRole>('any'),
|
|
5669
5675
|
required: true,
|
|
5670
|
-
}
|
|
5676
|
+
},
|
|
5671
5677
|
},
|
|
5672
5678
|
indexes: {
|
|
5673
5679
|
record: {
|
|
@@ -5684,6 +5690,61 @@ const person = new Entity({
|
|
|
5684
5690
|
}, { table });
|
|
5685
5691
|
```
|
|
5686
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
|
+
|
|
5695
|
+
### Opaque Keys
|
|
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.
|
|
5697
|
+
|
|
5698
|
+
```
|
|
5699
|
+
import { Entity, CustomAttributeType } from 'electrodb';
|
|
5700
|
+
|
|
5701
|
+
const UniqueKeySymbol: unique symbol = Symbol();
|
|
5702
|
+
type EmployeeID = string & {[UniqueKeySymbol]: any};
|
|
5703
|
+
|
|
5704
|
+
const UniqueAgeSymbol: unique symbol = Symbol();
|
|
5705
|
+
type Month = number & {[UniqueAgeSymbol]: any};
|
|
5706
|
+
|
|
5707
|
+
const table = 'workplace_table';
|
|
5708
|
+
|
|
5709
|
+
const person = new Entity({
|
|
5710
|
+
model: {
|
|
5711
|
+
entity: 'personnel',
|
|
5712
|
+
service: 'workplace',
|
|
5713
|
+
version: '1'
|
|
5714
|
+
},
|
|
5715
|
+
attributes: {
|
|
5716
|
+
employeeId: {
|
|
5717
|
+
type: CustomAttributeType<EmployeeID>('string')
|
|
5718
|
+
},
|
|
5719
|
+
firstName: {
|
|
5720
|
+
type: 'string',
|
|
5721
|
+
required: true,
|
|
5722
|
+
},
|
|
5723
|
+
lastName: {
|
|
5724
|
+
type: 'string',
|
|
5725
|
+
required: true,
|
|
5726
|
+
},
|
|
5727
|
+
ageInMonths: {
|
|
5728
|
+
type: CustomAttributeType<Month>('number')
|
|
5729
|
+
}
|
|
5730
|
+
},
|
|
5731
|
+
indexes: {
|
|
5732
|
+
record: {
|
|
5733
|
+
pk: {
|
|
5734
|
+
field: 'pk',
|
|
5735
|
+
composite: ['employeeId']
|
|
5736
|
+
},
|
|
5737
|
+
sk: {
|
|
5738
|
+
field: 'sk',
|
|
5739
|
+
composite: [],
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
}
|
|
5743
|
+
}, { table });
|
|
5744
|
+
```
|
|
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
|
+
|
|
5687
5748
|
## Exported Types
|
|
5688
5749
|
|
|
5689
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/index.d.ts
CHANGED
|
@@ -987,16 +987,7 @@ export type ServiceQueryRecordsGo<ResponseType, Options = QueryOptions> = <T = R
|
|
|
987
987
|
|
|
988
988
|
export type QueryRecordsGo<ResponseType, Options = QueryOptions> = <T = ResponseType>(options?: Options) => Promise<{ data: T, cursor: string | null }>;
|
|
989
989
|
|
|
990
|
-
export type UpdateRecordGo<ResponseType> = <T = ResponseType, Options extends UpdateQueryOptions = UpdateQueryOptions>(options?: Options) =>
|
|
991
|
-
Options extends infer O
|
|
992
|
-
? 'response' extends keyof O
|
|
993
|
-
? O['response'] extends 'all_new'
|
|
994
|
-
? Promise<{data: T}>
|
|
995
|
-
: O['response'] extends 'all_old'
|
|
996
|
-
? Promise<{data: T}>
|
|
997
|
-
: Promise<{data: Partial<T>}>
|
|
998
|
-
: Promise<{data: Partial<T>}>
|
|
999
|
-
: never;
|
|
990
|
+
export type UpdateRecordGo<ResponseType> = <T = ResponseType, Options extends UpdateQueryOptions = UpdateQueryOptions>(options?: Options) => Promise<{data: Partial<T>}>
|
|
1000
991
|
|
|
1001
992
|
export type PutRecordGo<ResponseType, Options = QueryOptions> = <T = ResponseType>(options?: Options) => Promise<{ data: T }>;
|
|
1002
993
|
|
|
@@ -1454,16 +1445,23 @@ type StaticAttribute = {
|
|
|
1454
1445
|
readonly field?: string;
|
|
1455
1446
|
}
|
|
1456
1447
|
|
|
1457
|
-
type
|
|
1458
|
-
|
|
1459
|
-
|
|
1448
|
+
type CustomAttributeTypeName<T> = { readonly [CustomAttributeSymbol]: T };
|
|
1449
|
+
|
|
1450
|
+
type OpaquePrimitiveTypeName<T extends string | number | boolean> =
|
|
1451
|
+
T extends string ? 'string' & { readonly [OpaquePrimitiveSymbol]: T }
|
|
1452
|
+
: T extends number ? 'number' & { readonly [OpaquePrimitiveSymbol]: T }
|
|
1453
|
+
: T extends boolean ? 'boolean' & { readonly [OpaquePrimitiveSymbol]: T }
|
|
1454
|
+
: never;
|
|
1455
|
+
|
|
1456
|
+
type CustomAttribute = {
|
|
1457
|
+
readonly type: CustomAttributeTypeName<any> | OpaquePrimitiveTypeName<any>;
|
|
1460
1458
|
readonly required?: boolean;
|
|
1461
1459
|
readonly hidden?: boolean;
|
|
1462
1460
|
readonly readOnly?: boolean;
|
|
1463
|
-
readonly get?: (val:
|
|
1464
|
-
readonly set?: (val?:
|
|
1465
|
-
readonly default?:
|
|
1466
|
-
readonly validate?: ((val:
|
|
1461
|
+
readonly get?: (val: any, item: any) => any | undefined | void;
|
|
1462
|
+
readonly set?: (val?: any, item?: any) => any | undefined | void;
|
|
1463
|
+
readonly default?: any | (() => any);
|
|
1464
|
+
readonly validate?: ((val: any) => boolean) | ((val: any) => void) | ((val: any) => string | void);
|
|
1467
1465
|
readonly field?: string;
|
|
1468
1466
|
readonly watch?: ReadonlyArray<string> | "*";
|
|
1469
1467
|
};
|
|
@@ -1621,7 +1619,9 @@ type PartialDefinedKeys<T> = {
|
|
|
1621
1619
|
}
|
|
1622
1620
|
|
|
1623
1621
|
export type ItemAttribute<A extends Attribute> =
|
|
1624
|
-
A extends
|
|
1622
|
+
A['type'] extends OpaquePrimitiveTypeName<infer T>
|
|
1623
|
+
? T
|
|
1624
|
+
: A['type'] extends CustomAttributeTypeName<infer T>
|
|
1625
1625
|
? T
|
|
1626
1626
|
: A["type"] extends infer R
|
|
1627
1627
|
? R extends "string" ? string
|
|
@@ -1661,8 +1661,10 @@ export type ItemAttribute<A extends Attribute> =
|
|
|
1661
1661
|
: never
|
|
1662
1662
|
|
|
1663
1663
|
export type ReturnedAttribute<A extends Attribute> =
|
|
1664
|
-
A extends
|
|
1665
|
-
|
|
1664
|
+
A['type'] extends OpaquePrimitiveTypeName<infer T>
|
|
1665
|
+
? T
|
|
1666
|
+
: A['type'] extends CustomAttributeTypeName<infer T>
|
|
1667
|
+
? T
|
|
1666
1668
|
: A["type"] extends infer R
|
|
1667
1669
|
? R extends "static" ? never
|
|
1668
1670
|
: R extends "string" ? string
|
|
@@ -1716,7 +1718,9 @@ export type ReturnedAttribute<A extends Attribute> =
|
|
|
1716
1718
|
: never
|
|
1717
1719
|
|
|
1718
1720
|
export type CreatedAttribute<A extends Attribute> =
|
|
1719
|
-
A extends
|
|
1721
|
+
A['type'] extends OpaquePrimitiveTypeName<infer T>
|
|
1722
|
+
? T
|
|
1723
|
+
: A['type'] extends CustomAttributeTypeName<infer T>
|
|
1720
1724
|
? T
|
|
1721
1725
|
: A["type"] extends infer R
|
|
1722
1726
|
? R extends "static" ? never
|
|
@@ -1779,8 +1783,10 @@ export type CreatedItem<A extends string, F extends string, C extends string, S
|
|
|
1779
1783
|
}
|
|
1780
1784
|
|
|
1781
1785
|
export type EditableItemAttribute<A extends Attribute> =
|
|
1782
|
-
A extends
|
|
1783
|
-
|
|
1786
|
+
A['type'] extends OpaquePrimitiveTypeName<infer T>
|
|
1787
|
+
? T
|
|
1788
|
+
: A['type'] extends CustomAttributeTypeName<infer T>
|
|
1789
|
+
? T
|
|
1784
1790
|
: A extends ReadOnlyAttribute
|
|
1785
1791
|
? never
|
|
1786
1792
|
: A["type"] extends infer R
|
|
@@ -1826,7 +1832,9 @@ export type EditableItemAttribute<A extends Attribute> =
|
|
|
1826
1832
|
: never
|
|
1827
1833
|
|
|
1828
1834
|
export type UpdatableItemAttribute<A extends Attribute> =
|
|
1829
|
-
A extends
|
|
1835
|
+
A['type'] extends OpaquePrimitiveTypeName<infer T>
|
|
1836
|
+
? T
|
|
1837
|
+
: A['type'] extends CustomAttributeTypeName<infer T>
|
|
1830
1838
|
? T
|
|
1831
1839
|
: A extends ReadOnlyAttribute
|
|
1832
1840
|
? never
|
|
@@ -1888,7 +1896,9 @@ export type UpdatableItemAttribute<A extends Attribute> =
|
|
|
1888
1896
|
: never
|
|
1889
1897
|
|
|
1890
1898
|
export type RemovableItemAttribute<A extends Attribute> =
|
|
1891
|
-
A extends
|
|
1899
|
+
A['type'] extends OpaquePrimitiveTypeName<infer T>
|
|
1900
|
+
? T
|
|
1901
|
+
: A['type'] extends CustomAttributeTypeName<infer T>
|
|
1892
1902
|
? T
|
|
1893
1903
|
: A extends ReadOnlyAttribute | RequiredAttribute
|
|
1894
1904
|
? never
|
|
@@ -2072,7 +2082,7 @@ export type RemoveItem<A extends string, F extends string, C extends string, S e
|
|
|
2072
2082
|
export type AppendItem<A extends string, F extends string, C extends string, S extends Schema<A,F,C>> =
|
|
2073
2083
|
{
|
|
2074
2084
|
[
|
|
2075
|
-
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'list' | 'any' | 'custom'
|
|
2085
|
+
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'list' | 'any' | 'custom' | CustomAttributeTypeName<any>
|
|
2076
2086
|
? P
|
|
2077
2087
|
: never
|
|
2078
2088
|
]?: P extends keyof SetItem<A,F,C,S>
|
|
@@ -2083,7 +2093,7 @@ export type AppendItem<A extends string, F extends string, C extends string, S e
|
|
|
2083
2093
|
export type AddItem<A extends string, F extends string, C extends string, S extends Schema<A,F,C>> =
|
|
2084
2094
|
{
|
|
2085
2095
|
[
|
|
2086
|
-
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'number' | 'any' | 'set' | 'custom'
|
|
2096
|
+
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'number' | 'any' | 'set' | 'custom' | CustomAttributeTypeName<any> | OpaquePrimitiveTypeName<number>
|
|
2087
2097
|
? P
|
|
2088
2098
|
: never
|
|
2089
2099
|
]?: P extends keyof SetItem<A,F,C,S>
|
|
@@ -2094,7 +2104,7 @@ export type AddItem<A extends string, F extends string, C extends string, S exte
|
|
|
2094
2104
|
export type SubtractItem<A extends string, F extends string, C extends string, S extends Schema<A,F,C>> =
|
|
2095
2105
|
{
|
|
2096
2106
|
[
|
|
2097
|
-
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'number' | 'any' | 'custom'
|
|
2107
|
+
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'number' | 'any' | 'custom' | OpaquePrimitiveTypeName<number>
|
|
2098
2108
|
? P
|
|
2099
2109
|
: never
|
|
2100
2110
|
]?: P extends keyof SetItem<A,F,C,S>
|
|
@@ -2105,7 +2115,7 @@ export type SubtractItem<A extends string, F extends string, C extends string, S
|
|
|
2105
2115
|
export type DeleteItem<A extends string, F extends string, C extends string, S extends Schema<A,F,C>> =
|
|
2106
2116
|
{
|
|
2107
2117
|
[
|
|
2108
|
-
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'any' | 'set' | 'custom'
|
|
2118
|
+
P in keyof ItemTypeDescription<A,F,C,S> as ItemTypeDescription<A,F,C,S>[P] extends 'any' | 'set' | 'custom' | CustomAttributeTypeName<any>
|
|
2109
2119
|
? P
|
|
2110
2120
|
: never
|
|
2111
2121
|
]?: P extends keyof SetItem<A,F,C,S>
|
|
@@ -2116,6 +2126,7 @@ export type DeleteItem<A extends string, F extends string, C extends string, S e
|
|
|
2116
2126
|
export declare const WhereSymbol: unique symbol;
|
|
2117
2127
|
export declare const UpdateDataSymbol: unique symbol;
|
|
2118
2128
|
export declare const CustomAttributeSymbol: unique symbol;
|
|
2129
|
+
export declare const OpaquePrimitiveSymbol: unique symbol;
|
|
2119
2130
|
|
|
2120
2131
|
export type WhereAttributeSymbol<T extends any> =
|
|
2121
2132
|
{ [WhereSymbol]: void }
|
|
@@ -2317,6 +2328,16 @@ type CustomAttributeDefinition<T> = {
|
|
|
2317
2328
|
readonly validate?: ((val: T) => boolean) | ((val: T) => void) | ((val: T) => string | void);
|
|
2318
2329
|
readonly field?: string;
|
|
2319
2330
|
readonly watch?: ReadonlyArray<string> | "*";
|
|
2320
|
-
}
|
|
2331
|
+
};
|
|
2321
2332
|
|
|
2322
|
-
|
|
2333
|
+
/** @depricated use 'CustomAttributeType' or 'OpaquePrimitiveType' instead */
|
|
2334
|
+
declare function createCustomAttribute<T, A extends Readonly<CustomAttributeDefinition<T>> = Readonly<CustomAttributeDefinition<T>>>(definition?: A): A & { type: CustomAttributeTypeName<T> };
|
|
2335
|
+
|
|
2336
|
+
declare function CustomAttributeType<T>(
|
|
2337
|
+
base: T extends string ? 'string'
|
|
2338
|
+
: T extends number ? 'number'
|
|
2339
|
+
: T extends boolean ? 'boolean'
|
|
2340
|
+
: 'any'
|
|
2341
|
+
): T extends string | number | boolean
|
|
2342
|
+
? OpaquePrimitiveTypeName<T>
|
|
2343
|
+
: CustomAttributeTypeName<T>;
|
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 } = require('./src/schema');
|
|
3
|
+
const { createCustomAttribute, CustomAttributeType } = 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
|
-
createCustomAttribute,
|
|
10
9
|
ElectroError,
|
|
10
|
+
CustomAttributeType,
|
|
11
|
+
createCustomAttribute,
|
|
11
12
|
ElectroValidationError,
|
|
12
13
|
};
|
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/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()) {
|
|
@@ -1464,10 +1466,19 @@ function createCustomAttribute(definition = {}) {
|
|
|
1464
1466
|
};
|
|
1465
1467
|
}
|
|
1466
1468
|
|
|
1469
|
+
function CustomAttributeType(base) {
|
|
1470
|
+
const supported = ['string', 'number', 'boolean', 'any'];
|
|
1471
|
+
if (!supported.includes(base)) {
|
|
1472
|
+
throw new Error(`OpaquePrimitiveType only supports base types: ${u.commaSeparatedString(supported)}`);
|
|
1473
|
+
}
|
|
1474
|
+
return base;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1467
1477
|
module.exports = {
|
|
1468
1478
|
Schema,
|
|
1469
1479
|
Attribute,
|
|
1470
1480
|
SetAttribute,
|
|
1471
1481
|
CastTypes,
|
|
1482
|
+
CustomAttributeType,
|
|
1472
1483
|
createCustomAttribute,
|
|
1473
1484
|
};
|