electrodb 2.2.2 → 2.2.3

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 CHANGED
@@ -5635,12 +5635,16 @@ let stores = await StoreLocations.malls({mallId}).query({buildingId, storeId}).g
5635
5635
  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
5636
 
5637
5637
  ## 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 `createCustomAttribute`. This function takes an attribute definition and allows you to specify a custom typed attribute with ElectroDB:
5638
+ 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:
5639
5639
 
5640
- > _NOTE: creating a custom type, ElectroDB will enforce attribute constraints based on the attribute definition provided, but will yield typing control to the user. This may result in some mismatches between your typing and the constraints enforced by ElectroDB._
5640
+ ### CustomAttributeType
5641
+ 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.
5641
5642
 
5643
+ 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.
5644
+
5645
+ In this example we accomplish a complex union type:
5642
5646
  ```typescript
5643
- import { Entity, createCustomAttribute } from 'electrodb';
5647
+ import { Entity, CustomAttributeType } from 'electrodb';
5644
5648
 
5645
5649
  const table = 'workplace_table';
5646
5650
 
@@ -5654,7 +5658,6 @@ type PersonnelRole = {
5654
5658
  contractEndDate: number;
5655
5659
  };
5656
5660
 
5657
-
5658
5661
  const person = new Entity({
5659
5662
  model: {
5660
5663
  entity: 'personnel',
@@ -5665,9 +5668,10 @@ const person = new Entity({
5665
5668
  id: {
5666
5669
  type: 'string'
5667
5670
  },
5668
- role: createCustomAttribute<PersonnelRole>({
5671
+ role: {
5672
+ type: CustomAttributeType<PersonnelRole>('any'),
5669
5673
  required: true,
5670
- }),
5674
+ },
5671
5675
  },
5672
5676
  indexes: {
5673
5677
  record: {
@@ -5684,6 +5688,57 @@ const person = new Entity({
5684
5688
  }, { table });
5685
5689
  ```
5686
5690
 
5691
+ ### Opaque Keys
5692
+ 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
+
5694
+ ```
5695
+ import { Entity, CustomAttributeType } from 'electrodb';
5696
+
5697
+ const UniqueKeySymbol: unique symbol = Symbol();
5698
+ type EmployeeID = string & {[UniqueKeySymbol]: any};
5699
+
5700
+ const UniqueAgeSymbol: unique symbol = Symbol();
5701
+ type Month = number & {[UniqueAgeSymbol]: any};
5702
+
5703
+ const table = 'workplace_table';
5704
+
5705
+ const person = new Entity({
5706
+ model: {
5707
+ entity: 'personnel',
5708
+ service: 'workplace',
5709
+ version: '1'
5710
+ },
5711
+ attributes: {
5712
+ employeeId: {
5713
+ type: CustomAttributeType<EmployeeID>('string')
5714
+ },
5715
+ firstName: {
5716
+ type: 'string',
5717
+ required: true,
5718
+ },
5719
+ lastName: {
5720
+ type: 'string',
5721
+ required: true,
5722
+ },
5723
+ ageInMonths: {
5724
+ type: CustomAttributeType<Month>('number')
5725
+ }
5726
+ },
5727
+ indexes: {
5728
+ record: {
5729
+ pk: {
5730
+ field: 'pk',
5731
+ composite: ['employeeId']
5732
+ },
5733
+ sk: {
5734
+ field: 'sk',
5735
+ composite: [],
5736
+ }
5737
+ }
5738
+ }
5739
+ }, { table });
5740
+ ```
5741
+
5687
5742
  ## Exported Types
5688
5743
 
5689
5744
  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 CustomAttribute<T extends any = any> = {
1458
- readonly type: "custom";
1459
- readonly [CustomAttributeSymbol]: T;
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: T, item: any) => T | undefined | void;
1464
- readonly set?: (val?: T, item?: any) => T | undefined | void;
1465
- readonly default?: T | (() => T);
1466
- readonly validate?: ((val: T) => boolean) | ((val: T) => void) | ((val: T) => string | void);
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 CustomAttribute<infer T>
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 CustomAttribute<infer T>
1665
- ? T
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 CustomAttribute<infer T>
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 CustomAttribute<infer T>
1783
- ? T
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 CustomAttribute<infer T>
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 CustomAttribute<infer T>
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
- declare function createCustomAttribute<T>(definition?: CustomAttributeDefinition<T>): CustomAttribute<T>;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrodb",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/schema.js CHANGED
@@ -1464,10 +1464,19 @@ function createCustomAttribute(definition = {}) {
1464
1464
  };
1465
1465
  }
1466
1466
 
1467
+ function CustomAttributeType(base) {
1468
+ const supported = ['string', 'number', 'boolean', 'any'];
1469
+ if (!supported.includes(base)) {
1470
+ throw new Error(`OpaquePrimitiveType only supports base types: ${u.commaSeparatedString(supported)}`);
1471
+ }
1472
+ return base;
1473
+ }
1474
+
1467
1475
  module.exports = {
1468
1476
  Schema,
1469
1477
  Attribute,
1470
1478
  SetAttribute,
1471
1479
  CastTypes,
1480
+ CustomAttributeType,
1472
1481
  createCustomAttribute,
1473
1482
  };