electrodb 1.10.2 → 1.11.0
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 -3
- package/index.d.ts +208 -75
- package/package.json +6 -9
- package/src/clauses.js +5 -3
- package/src/entity.js +116 -7
- package/src/schema.js +14 -3
- package/src/types.js +6 -0
- package/src/parse.js +0 -45
package/README.md
CHANGED
|
@@ -2607,9 +2607,10 @@ const formattedQueryResults = myEntity.parse(formattedQueryResults);
|
|
|
2607
2607
|
|
|
2608
2608
|
Parse also accepts an optional `options` object as a second argument (see the section [Query Options](#query-options) to learn more). Currently, the following query options are relevant to the `parse()` method:
|
|
2609
2609
|
|
|
2610
|
-
Option | Default
|
|
2611
|
-
----------------- :
|
|
2612
|
-
|
|
2610
|
+
Option | Type | Default | Notes
|
|
2611
|
+
----------------- : -------- : ------------------ | -----
|
|
2612
|
+
ignoreOwnership | boolean | `true` | This property defaults to `true` here, unlike elsewhere in the application when it defaults to `false`. You can overwrite the default here with your own preference.
|
|
2613
|
+
attributes | string[] | _(all attributes)_ | The `attributes` option allows you to specify a subset of attributes to return
|
|
2613
2614
|
|
|
2614
2615
|
# Building Queries
|
|
2615
2616
|
> For hands-on learners: the following example can be followed along with **and** executed on runkit: https://runkit.com/tywalch/electrodb-building-queries
|
|
@@ -4300,6 +4301,7 @@ By default, **ElectroDB** enables you to work with records as the names and prop
|
|
|
4300
4301
|
logger?: (event) => void;
|
|
4301
4302
|
listeners Array<(event) => void>;
|
|
4302
4303
|
preserveBatchOrder?: boolean;
|
|
4304
|
+
attributes?: string[];
|
|
4303
4305
|
};
|
|
4304
4306
|
```
|
|
4305
4307
|
|
|
@@ -4307,6 +4309,7 @@ Option | Default | Description
|
|
|
4307
4309
|
------------------ | :------------------: | -----------
|
|
4308
4310
|
params | `{}` | Properties added to this object will be merged onto the params sent to the document client. Any conflicts with **ElectroDB** will favor the params specified here.
|
|
4309
4311
|
table | _(from constructor)_ | Use a different table than the one defined in the [Service Options](#service-options)
|
|
4312
|
+
attributes | _(all attributes)_ | The `attributes` query option allows you to specify ProjectionExpression Attributes for your `get` or `query` operation. As of `1.11.0` only root attributes are allowed to be specified.
|
|
4310
4313
|
raw | `false` | Returns query results as they were returned by the docClient.
|
|
4311
4314
|
includeKeys | `false` | By default, **ElectroDB** does not return partition, sort, or global keys in its response.
|
|
4312
4315
|
pager | `"named"` | Used in with pagination (`.pages()`) calls to override ElectroDBs default behaviour to break apart `LastEvaluatedKeys` records into composite attributes. See more detail about this in the sections for [Pager Query Options](#pager-query-options).
|
package/index.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ export type CollectionWhereCallback<E extends {[name: string]: Entity<any, any,
|
|
|
79
79
|
|
|
80
80
|
export type CollectionWhereClause<E extends {[name: string]: Entity<any, any, any, any>}, A extends string, F extends string, C extends string, S extends Schema<A,F,C>, I extends Partial<AllEntityAttributes<E>>, T> = (where: CollectionWhereCallback<E, I>) => T;
|
|
81
81
|
|
|
82
|
+
|
|
82
83
|
export interface WhereRecordsActionOptions<E extends {[name: string]: Entity<any, any, any, any>}, A extends string, F extends string, C extends string, S extends Schema<A,F,C>, I extends Partial<AllEntityAttributes<E>>, Items, IndexCompositeAttributes> {
|
|
83
84
|
go: GoRecord<Items>;
|
|
84
85
|
params: ParamRecord;
|
|
@@ -349,6 +350,13 @@ export type CollectionItem<SERVICE extends Service<any>, COLLECTION extends keyo
|
|
|
349
350
|
: never>
|
|
350
351
|
: never
|
|
351
352
|
|
|
353
|
+
export interface QueryBranches<A extends string,
|
|
354
|
+
F extends string, C extends string, S extends Schema<A,F,C>, ResponseItem, IndexCompositeAttributes> {
|
|
355
|
+
go: GoQueryTerminal<A,F,C,S,ResponseItem>;
|
|
356
|
+
params: ParamTerminal<A,F,C,S,ResponseItem>;
|
|
357
|
+
page: PageQueryTerminal<A,F,C,S,ResponseItem,IndexCompositeAttributes>;
|
|
358
|
+
where: WhereClause<A,F,C,S,Item<A,F,C,S,S["attributes"]>,QueryBranches<A,F,C,S,ResponseItem,IndexCompositeAttributes>>
|
|
359
|
+
}
|
|
352
360
|
|
|
353
361
|
export interface RecordsActionOptions<A extends string,
|
|
354
362
|
F extends string, C extends string, S extends Schema<A,F,C>, Items, IndexCompositeAttributes> {
|
|
@@ -359,11 +367,16 @@ export interface RecordsActionOptions<A extends string,
|
|
|
359
367
|
}
|
|
360
368
|
|
|
361
369
|
export interface SingleRecordOperationOptions<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseType> {
|
|
362
|
-
go:
|
|
363
|
-
params:
|
|
370
|
+
go: GoGetTerminal<A,F,C,S, ResponseType>;
|
|
371
|
+
params: ParamTerminal<A,F,C,S,ResponseType>;
|
|
364
372
|
where: WhereClause<A,F,C,S,Item<A,F,C,S,S["attributes"]>,SingleRecordOperationOptions<A,F,C,S,ResponseType>>;
|
|
365
373
|
}
|
|
366
374
|
|
|
375
|
+
export interface BatchGetRecordOperationOptions<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseType> {
|
|
376
|
+
go: GoBatchGetTerminal<A,F,C,S,ResponseType>
|
|
377
|
+
params: ParamTerminal<A,F,C,S,ResponseType>;
|
|
378
|
+
}
|
|
379
|
+
|
|
367
380
|
export interface PutRecordOperationOptions<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseType> {
|
|
368
381
|
go: GoRecord<ResponseType, PutQueryOptions>;
|
|
369
382
|
params: ParamRecord<PutQueryOptions>;
|
|
@@ -406,17 +419,17 @@ export type RemoveRecord<A extends string, F extends string, C extends string, S
|
|
|
406
419
|
export type DataUpdateMethodRecord<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, SetAttr, IndexCompositeAttributes, TableItem> =
|
|
407
420
|
DataUpdateMethod<A,F,C,S, UpdateData<A,F,C,S>, SetRecordActionOptions<A,F,C,S, SetAttr, IndexCompositeAttributes, TableItem>>
|
|
408
421
|
|
|
409
|
-
interface QueryOperations<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, CompositeAttributes,
|
|
410
|
-
between: (skCompositeAttributesStart: CompositeAttributes, skCompositeAttributesEnd: CompositeAttributes) =>
|
|
411
|
-
gt: (skCompositeAttributes: CompositeAttributes) =>
|
|
412
|
-
gte: (skCompositeAttributes: CompositeAttributes) =>
|
|
413
|
-
lt: (skCompositeAttributes: CompositeAttributes) =>
|
|
414
|
-
lte: (skCompositeAttributes: CompositeAttributes) =>
|
|
415
|
-
begins: (skCompositeAttributes: CompositeAttributes) =>
|
|
416
|
-
go:
|
|
417
|
-
params:
|
|
418
|
-
page:
|
|
419
|
-
where: WhereClause<A,F,C,S,Item<A,F,C,S,S["attributes"]>,
|
|
422
|
+
interface QueryOperations<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, CompositeAttributes, ResponseItem, IndexCompositeAttributes> {
|
|
423
|
+
between: (skCompositeAttributesStart: CompositeAttributes, skCompositeAttributesEnd: CompositeAttributes) => QueryBranches<A,F,C,S, ResponseItem, IndexCompositeAttributes>;
|
|
424
|
+
gt: (skCompositeAttributes: CompositeAttributes) => QueryBranches<A,F,C,S, ResponseItem,IndexCompositeAttributes>;
|
|
425
|
+
gte: (skCompositeAttributes: CompositeAttributes) => QueryBranches<A,F,C,S, ResponseItem,IndexCompositeAttributes>;
|
|
426
|
+
lt: (skCompositeAttributes: CompositeAttributes) => QueryBranches<A,F,C,S, ResponseItem,IndexCompositeAttributes>;
|
|
427
|
+
lte: (skCompositeAttributes: CompositeAttributes) => QueryBranches<A,F,C,S, ResponseItem,IndexCompositeAttributes>;
|
|
428
|
+
begins: (skCompositeAttributes: CompositeAttributes) => QueryBranches<A,F,C,S, ResponseItem,IndexCompositeAttributes>;
|
|
429
|
+
go: GoQueryTerminal<A,F,C,S,ResponseItem>;
|
|
430
|
+
params: ParamTerminal<A,F,C,S,ResponseItem>;
|
|
431
|
+
page: PageQueryTerminal<A,F,C,S,ResponseItem,IndexCompositeAttributes>;
|
|
432
|
+
where: WhereClause<A,F,C,S,Item<A,F,C,S,S["attributes"]>,QueryBranches<A,F,C,S,ResponseItem,IndexCompositeAttributes>>
|
|
420
433
|
}
|
|
421
434
|
|
|
422
435
|
export type Queries<A extends string, F extends string, C extends string, S extends Schema<A,F,C>> = {
|
|
@@ -424,7 +437,7 @@ export type Queries<A extends string, F extends string, C extends string, S exte
|
|
|
424
437
|
IndexSKAttributes<A,F,C,S,I> extends infer SK
|
|
425
438
|
// If there is no SK, dont show query operations (when an empty array is provided)
|
|
426
439
|
? [keyof SK] extends [never]
|
|
427
|
-
?
|
|
440
|
+
? QueryBranches<A,F,C,S, ResponseItem<A,F,C,S>, AllTableIndexCompositeAttributes<A,F,C,S> & Required<CompositeAttributes>>
|
|
428
441
|
// If there is no SK, dont show query operations (When no PK is specified)
|
|
429
442
|
: S["indexes"][I] extends IndexWithSortKey
|
|
430
443
|
? QueryOperations<
|
|
@@ -434,7 +447,7 @@ export type Queries<A extends string, F extends string, C extends string, S exte
|
|
|
434
447
|
ResponseItem<A,F,C,S>,
|
|
435
448
|
AllTableIndexCompositeAttributes<A,F,C,S> & Required<CompositeAttributes> & SK
|
|
436
449
|
>
|
|
437
|
-
:
|
|
450
|
+
: QueryBranches<A,F,C,S, ResponseItem<A,F,C,S>, AllTableIndexCompositeAttributes<A,F,C,S> & Required<CompositeAttributes> & SK>
|
|
438
451
|
: never
|
|
439
452
|
}
|
|
440
453
|
|
|
@@ -464,7 +477,8 @@ export interface QueryOptions {
|
|
|
464
477
|
}
|
|
465
478
|
|
|
466
479
|
// subset of QueryOptions
|
|
467
|
-
export interface ParseOptions {
|
|
480
|
+
export interface ParseOptions<Attributes> {
|
|
481
|
+
attributes?: ReadonlyArray<Attributes>;
|
|
468
482
|
ignoreOwnership?: boolean;
|
|
469
483
|
}
|
|
470
484
|
|
|
@@ -510,6 +524,162 @@ export type OptionalDefaultEntityIdentifiers = {
|
|
|
510
524
|
__edb_v__?: string;
|
|
511
525
|
}
|
|
512
526
|
|
|
527
|
+
interface GoBatchGetTerminalOptions<Attributes> {
|
|
528
|
+
raw?: boolean;
|
|
529
|
+
table?: string;
|
|
530
|
+
limit?: number;
|
|
531
|
+
params?: object;
|
|
532
|
+
includeKeys?: boolean;
|
|
533
|
+
originalErr?: boolean;
|
|
534
|
+
ignoreOwnership?: boolean;
|
|
535
|
+
pages?: number;
|
|
536
|
+
attributes?: ReadonlyArray<Attributes>;
|
|
537
|
+
unprocessed?: "raw" | "item";
|
|
538
|
+
concurrency?: number;
|
|
539
|
+
preserveBatchOrder?: boolean;
|
|
540
|
+
listeners?: Array<ElectroEventListener>;
|
|
541
|
+
logger?: ElectroEventListener;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
interface GoQueryTerminalOptions<Attributes> {
|
|
545
|
+
raw?: boolean;
|
|
546
|
+
table?: string;
|
|
547
|
+
limit?: number;
|
|
548
|
+
params?: object;
|
|
549
|
+
includeKeys?: boolean;
|
|
550
|
+
originalErr?: boolean;
|
|
551
|
+
ignoreOwnership?: boolean;
|
|
552
|
+
pages?: number;
|
|
553
|
+
attributes?: ReadonlyArray<Attributes>;
|
|
554
|
+
listeners?: Array<ElectroEventListener>;
|
|
555
|
+
logger?: ElectroEventListener;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
interface PageQueryTerminalOptions<Attributes> extends GoQueryTerminalOptions<Attributes> {
|
|
559
|
+
pager?: "raw" | "item" | "named";
|
|
560
|
+
raw?: boolean;
|
|
561
|
+
table?: string;
|
|
562
|
+
limit?: number;
|
|
563
|
+
includeKeys?: boolean;
|
|
564
|
+
originalErr?: boolean;
|
|
565
|
+
ignoreOwnership?: boolean;
|
|
566
|
+
attributes?: ReadonlyArray<Attributes>;
|
|
567
|
+
listeners?: Array<ElectroEventListener>;
|
|
568
|
+
logger?: ElectroEventListener;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export interface ParamTerminalOptions<Attributes> {
|
|
572
|
+
table?: string;
|
|
573
|
+
limit?: number;
|
|
574
|
+
params?: object;
|
|
575
|
+
originalErr?: boolean;
|
|
576
|
+
attributes?: ReadonlyArray<Attributes>;
|
|
577
|
+
response?: "default" | "none" | 'all_old' | 'updated_old' | 'all_new' | 'updated_new';
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
type GoBatchGetTerminal<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseItem> = <Options extends GoBatchGetTerminalOptions<keyof ResponseItem>>(options?: Options) =>
|
|
581
|
+
Options extends GoBatchGetTerminalOptions<infer Attr>
|
|
582
|
+
? 'preserveBatchOrder' extends keyof Options
|
|
583
|
+
? Options['preserveBatchOrder'] extends true
|
|
584
|
+
? Promise<[
|
|
585
|
+
Array<Resolve<{
|
|
586
|
+
[
|
|
587
|
+
Name in keyof ResponseItem as Name extends Attr
|
|
588
|
+
? Name
|
|
589
|
+
: never
|
|
590
|
+
]: ResponseItem[Name]
|
|
591
|
+
} | null>>, Array<Resolve<AllTableIndexCompositeAttributes<A,F,C,S>>>
|
|
592
|
+
]>
|
|
593
|
+
: Promise<[
|
|
594
|
+
Array<Resolve<{
|
|
595
|
+
[
|
|
596
|
+
Name in keyof ResponseItem as Name extends Attr
|
|
597
|
+
? Name
|
|
598
|
+
: never
|
|
599
|
+
]: ResponseItem[Name]
|
|
600
|
+
}>>, Array<Resolve<AllTableIndexCompositeAttributes<A,F,C,S>>>
|
|
601
|
+
]>
|
|
602
|
+
: Promise<[
|
|
603
|
+
Array<Resolve<{
|
|
604
|
+
[
|
|
605
|
+
Name in keyof ResponseItem as Name extends Attr
|
|
606
|
+
? Name
|
|
607
|
+
: never
|
|
608
|
+
]: ResponseItem[Name]
|
|
609
|
+
}>>, Array<Resolve<AllTableIndexCompositeAttributes<A,F,C,S>>>
|
|
610
|
+
]>
|
|
611
|
+
: 'preserveBatchOrder' extends keyof Options
|
|
612
|
+
? Options['preserveBatchOrder'] extends true
|
|
613
|
+
? [Array<Resolve<ResponseItem | null>>, Array<Resolve<AllTableIndexCompositeAttributes<A,F,C,S>>>]
|
|
614
|
+
: [Array<Resolve<ResponseItem>>, Array<Resolve<AllTableIndexCompositeAttributes<A,F,C,S>>>]
|
|
615
|
+
: [Array<Resolve<ResponseItem>>, Array<Resolve<AllTableIndexCompositeAttributes<A,F,C,S>>>]
|
|
616
|
+
|
|
617
|
+
type GoGetTerminal<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseItem> = <Options extends GoQueryTerminalOptions<keyof ResponseItem>>(options?: Options) =>
|
|
618
|
+
Options extends GoQueryTerminalOptions<infer Attr>
|
|
619
|
+
? Promise<{
|
|
620
|
+
[
|
|
621
|
+
Name in keyof ResponseItem as Name extends Attr
|
|
622
|
+
? Name
|
|
623
|
+
: never
|
|
624
|
+
]: ResponseItem[Name]
|
|
625
|
+
} | null>
|
|
626
|
+
: Promise<ResponseItem | null>
|
|
627
|
+
|
|
628
|
+
export type GoQueryTerminal<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, Item> = <Options extends GoQueryTerminalOptions<keyof Item>>(options?: Options) =>
|
|
629
|
+
Options extends GoQueryTerminalOptions<infer Attr>
|
|
630
|
+
? Promise<Array<{
|
|
631
|
+
[
|
|
632
|
+
Name in keyof Item as Name extends Attr
|
|
633
|
+
? Name
|
|
634
|
+
: never
|
|
635
|
+
]: Item[Name]
|
|
636
|
+
}>>
|
|
637
|
+
: Promise<Array<Item>>
|
|
638
|
+
|
|
639
|
+
export type EntityParseSingleItem<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseItem> =
|
|
640
|
+
<Options extends ParseOptions<keyof ResponseItem>>(item: ParseSingleInput, options?: Options) =>
|
|
641
|
+
Options extends ParseOptions<infer Attr>
|
|
642
|
+
? {
|
|
643
|
+
[
|
|
644
|
+
Name in keyof ResponseItem as Name extends Attr
|
|
645
|
+
? Name
|
|
646
|
+
: never
|
|
647
|
+
]: ResponseItem[Name]
|
|
648
|
+
} | null
|
|
649
|
+
: ResponseItem | null
|
|
650
|
+
|
|
651
|
+
export type EntityParseMultipleItems<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseItem> =
|
|
652
|
+
<Options extends ParseOptions<keyof ResponseItem>>(item: ParseMultiInput, options?: Options) =>
|
|
653
|
+
Options extends ParseOptions<infer Attr>
|
|
654
|
+
? Array<{
|
|
655
|
+
[
|
|
656
|
+
Name in keyof ResponseItem as Name extends Attr
|
|
657
|
+
? Name
|
|
658
|
+
: never
|
|
659
|
+
]: ResponseItem[Name]
|
|
660
|
+
}>
|
|
661
|
+
: Array<ResponseItem>
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
export type PageQueryTerminal<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, Item, CompositeAttributes> = <Options extends PageQueryTerminalOptions<keyof Item>>(page?: (CompositeAttributes & OptionalDefaultEntityIdentifiers) | null, options?: Options) =>
|
|
665
|
+
Options extends GoQueryTerminalOptions<infer Attr>
|
|
666
|
+
? Promise<[
|
|
667
|
+
(CompositeAttributes & OptionalDefaultEntityIdentifiers) | null,
|
|
668
|
+
Array<{
|
|
669
|
+
[
|
|
670
|
+
Name in keyof Item as Name extends Attr
|
|
671
|
+
? Name
|
|
672
|
+
: never
|
|
673
|
+
]: Item[Name]
|
|
674
|
+
}>
|
|
675
|
+
]>
|
|
676
|
+
: Promise<[
|
|
677
|
+
(CompositeAttributes & OptionalDefaultEntityIdentifiers) | null,
|
|
678
|
+
Array<ResponseType>
|
|
679
|
+
]>;
|
|
680
|
+
|
|
681
|
+
export type ParamTerminal<A extends string, F extends string, C extends string, S extends Schema<A,F,C>, ResponseItem> = <P extends any = any, Options extends ParamTerminalOptions<keyof ResponseItem> = ParamTerminalOptions<keyof ResponseItem>>(options?: Options) => P;
|
|
682
|
+
|
|
513
683
|
export type GoRecord<ResponseType, Options = QueryOptions> = <T = ResponseType>(options?: Options) => Promise<T>;
|
|
514
684
|
|
|
515
685
|
export type BatchGoRecord<ResponseType, AlternateResponseType> = <O extends BulkOptions>(options?: O) =>
|
|
@@ -1037,18 +1207,6 @@ export type ItemAttribute<A extends Attribute> =
|
|
|
1037
1207
|
: never
|
|
1038
1208
|
: never
|
|
1039
1209
|
|
|
1040
|
-
type FormattedPutMapAttributes<A extends MapAttribute> = {
|
|
1041
|
-
[P in keyof A["properties"]]: A["properties"][P] extends infer M
|
|
1042
|
-
? M extends HiddenAttribute
|
|
1043
|
-
? false
|
|
1044
|
-
: M extends DefaultedAttribute
|
|
1045
|
-
? false
|
|
1046
|
-
: M extends RequiredAttribute
|
|
1047
|
-
? true
|
|
1048
|
-
: false
|
|
1049
|
-
: false
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
1210
|
export type ReturnedAttribute<A extends Attribute> =
|
|
1053
1211
|
A["type"] extends infer R
|
|
1054
1212
|
? R extends "string" ? string
|
|
@@ -1079,27 +1237,6 @@ export type ReturnedAttribute<A extends Attribute> =
|
|
|
1079
1237
|
: never
|
|
1080
1238
|
: never
|
|
1081
1239
|
}
|
|
1082
|
-
// SkipKeys<{
|
|
1083
|
-
// [P in keyof A["properties"]]: A["properties"][P] extends infer M
|
|
1084
|
-
// ? M extends Attribute
|
|
1085
|
-
// ? M extends HiddenAttribute
|
|
1086
|
-
// ? SkipValue
|
|
1087
|
-
// : M extends RequiredAttribute
|
|
1088
|
-
// ? ReturnedAttribute<M>
|
|
1089
|
-
// : SkipValue
|
|
1090
|
-
// : never
|
|
1091
|
-
// : never
|
|
1092
|
-
// }> & SkipKeys<{
|
|
1093
|
-
// [P in keyof A["properties"]]?: A["properties"][P] extends infer M
|
|
1094
|
-
// ? M extends Attribute
|
|
1095
|
-
// ? M extends HiddenAttribute
|
|
1096
|
-
// ? SkipValue
|
|
1097
|
-
// : M extends RequiredAttribute
|
|
1098
|
-
// ? SkipValue
|
|
1099
|
-
// : ReturnedAttribute<M> | undefined
|
|
1100
|
-
// : never
|
|
1101
|
-
// : never
|
|
1102
|
-
// }>
|
|
1103
1240
|
: never
|
|
1104
1241
|
: R extends "list"
|
|
1105
1242
|
? "items" extends keyof A
|
|
@@ -1151,27 +1288,6 @@ export type CreatedAttribute<A extends Attribute> =
|
|
|
1151
1288
|
: never
|
|
1152
1289
|
: never
|
|
1153
1290
|
}
|
|
1154
|
-
// ? SkipKeys<{
|
|
1155
|
-
// [P in keyof A["properties"]]: A["properties"][P] extends infer M
|
|
1156
|
-
// ? M extends Attribute
|
|
1157
|
-
// ? M extends HiddenAttribute
|
|
1158
|
-
// ? SkipValue
|
|
1159
|
-
// : M extends DefaultedAttribute
|
|
1160
|
-
// ? SkipValue
|
|
1161
|
-
// : M extends RequiredAttribute
|
|
1162
|
-
// ? CreatedAttribute<M>
|
|
1163
|
-
// : SkipValue
|
|
1164
|
-
// : never
|
|
1165
|
-
// : never
|
|
1166
|
-
// }> & SkipKeys<{
|
|
1167
|
-
// [P in keyof A["properties"]]?: A["properties"][P] extends infer M
|
|
1168
|
-
// ? M extends Attribute
|
|
1169
|
-
// ? M extends HiddenAttribute
|
|
1170
|
-
// ? SkipValue
|
|
1171
|
-
// : CreatedAttribute<M> | undefined
|
|
1172
|
-
// : never
|
|
1173
|
-
// : never
|
|
1174
|
-
// }>
|
|
1175
1291
|
: never
|
|
1176
1292
|
: R extends "list"
|
|
1177
1293
|
? "items" extends keyof A
|
|
@@ -1632,9 +1748,8 @@ export class Entity<A extends string, F extends string, C extends string, S exte
|
|
|
1632
1748
|
private config?: EntityConfiguration;
|
|
1633
1749
|
constructor(schema: S, config?: EntityConfiguration);
|
|
1634
1750
|
|
|
1635
|
-
get(key: AllTableIndexCompositeAttributes<A,F,C,S>): SingleRecordOperationOptions<A,F,C,S, ResponseItem<A,F,C,S
|
|
1636
|
-
get(key: AllTableIndexCompositeAttributes<A,F,C,S>[]):
|
|
1637
|
-
|
|
1751
|
+
get(key: AllTableIndexCompositeAttributes<A,F,C,S>): SingleRecordOperationOptions<A,F,C,S, ResponseItem<A,F,C,S>>;
|
|
1752
|
+
get(key: AllTableIndexCompositeAttributes<A,F,C,S>[]): BatchGetRecordOperationOptions<A,F,C,S, ResponseItem<A,F,C,S>>;
|
|
1638
1753
|
delete(key: AllTableIndexCompositeAttributes<A,F,C,S>): DeleteRecordOperationOptions<A,F,C,S, ResponseItem<A,F,C,S>>;
|
|
1639
1754
|
delete(key: AllTableIndexCompositeAttributes<A,F,C,S>[]): BulkRecordOperationOptions<A,F,C,S, AllTableIndexCompositeAttributes<A,F,C,S>[], AllTableIndexCompositeAttributes<A,F,C,S>[]>;
|
|
1640
1755
|
|
|
@@ -1671,8 +1786,26 @@ export class Entity<A extends string, F extends string, C extends string, S exte
|
|
|
1671
1786
|
scan: RecordsActionOptions<A,F,C,S, ResponseItem<A,F,C,S>[], TableIndexCompositeAttributes<A,F,C,S>>;
|
|
1672
1787
|
query: Queries<A,F,C,S>;
|
|
1673
1788
|
|
|
1674
|
-
parse
|
|
1675
|
-
|
|
1789
|
+
parse<Options extends ParseOptions<keyof ResponseItem<A,F,C,S>>>(item: ParseSingleInput, options?: Options):
|
|
1790
|
+
Options extends ParseOptions<infer Attr>
|
|
1791
|
+
? {
|
|
1792
|
+
[
|
|
1793
|
+
Name in keyof ResponseItem<A,F,C,S> as Name extends Attr
|
|
1794
|
+
? Name
|
|
1795
|
+
: never
|
|
1796
|
+
]: ResponseItem<A,F,C,S>[Name]
|
|
1797
|
+
} | null
|
|
1798
|
+
: ResponseItem<A,F,C,S> | null
|
|
1799
|
+
parse<Options extends ParseOptions<keyof ResponseItem<A,F,C,S>>>(item: ParseMultiInput, options?: Options):
|
|
1800
|
+
Options extends ParseOptions<infer Attr>
|
|
1801
|
+
? Array<{
|
|
1802
|
+
[
|
|
1803
|
+
Name in keyof ResponseItem<A,F,C,S> as Name extends Attr
|
|
1804
|
+
? Name
|
|
1805
|
+
: never
|
|
1806
|
+
]: ResponseItem<A,F,C,S>[Name]
|
|
1807
|
+
}>
|
|
1808
|
+
: Array<ResponseItem<A,F,C,S>>
|
|
1676
1809
|
setIdentifier(type: "entity" | "version", value: string): void;
|
|
1677
1810
|
client: any;
|
|
1678
1811
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electrodb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
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": {
|
|
7
|
-
"test": "
|
|
8
|
-
"test-ts": "mocha -r ts-node/register ./test/**.spec.ts",
|
|
9
|
-
"test-all": "mocha ./test/**.spec.js",
|
|
10
|
-
"test-all-local": "LOCAL_DYNAMO_ENDPOINT=http://localhost:8000 node ./test/init.js && LOCAL_DYNAMO_ENDPOINT=http://localhost:8000 mocha ./test/**.spec.js && LOCAL_DYNAMO_ENDPOINT=http://localhost:8000 npm run test-ts && npm run test-types",
|
|
7
|
+
"test": "npm run test-types && LOCAL_DYNAMO_ENDPOINT=http://localhost:8000 node ./test/init.js && LOCAL_DYNAMO_ENDPOINT=http://localhost:8000 mocha -r ts-node/register ./test/**.spec.*",
|
|
11
8
|
"test-types": "tsd",
|
|
12
|
-
"coverage": "nyc npm
|
|
13
|
-
"coverage-coveralls-local": "nyc npm
|
|
14
|
-
"coverage-html-local": "nyc npm
|
|
9
|
+
"coverage": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
|
|
10
|
+
"coverage-coveralls-local": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
|
|
11
|
+
"coverage-html-local": "nyc npm test && nyc report --reporter=html",
|
|
15
12
|
"build:browser": "browserify playground/browser.js -o playground/bundle.js"
|
|
16
13
|
},
|
|
17
14
|
"repository": {
|
|
@@ -43,7 +40,7 @@
|
|
|
43
40
|
"moment": "2.24.0",
|
|
44
41
|
"nyc": "^15.1.0",
|
|
45
42
|
"source-map-support": "^0.5.19",
|
|
46
|
-
"ts-node": "^10.8.
|
|
43
|
+
"ts-node": "^10.8.2",
|
|
47
44
|
"tsd": "^0.21.0",
|
|
48
45
|
"typescript": "^4.7.4",
|
|
49
46
|
"uuid": "7.0.1"
|
package/src/clauses.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { QueryTypes, MethodTypes, ItemOperations, ExpressionTypes, TableIndex } = require("./types");
|
|
1
|
+
const { QueryTypes, MethodTypes, ItemOperations, ExpressionTypes, TableIndex, TerminalOperation } = require("./types");
|
|
2
2
|
const {AttributeOperationProxy, UpdateOperations, FilterOperationNames} = require("./operations");
|
|
3
3
|
const {UpdateExpression} = require("./update");
|
|
4
4
|
const {FilterExpression} = require("./where");
|
|
@@ -579,6 +579,7 @@ let clauses = {
|
|
|
579
579
|
if (entity.client === undefined) {
|
|
580
580
|
throw new e.ElectroError(e.ErrorCodes.NoClientDefined, "No client defined on model");
|
|
581
581
|
}
|
|
582
|
+
options.terminalOperation = TerminalOperation.go;
|
|
582
583
|
let params = clauses.params.action(entity, state, options);
|
|
583
584
|
let {config} = entity._applyParameterOptions({}, state.getOptions(), options);
|
|
584
585
|
return entity.go(state.getMethod(), params, config);
|
|
@@ -595,11 +596,12 @@ let clauses = {
|
|
|
595
596
|
return Promise.reject(state.error);
|
|
596
597
|
}
|
|
597
598
|
try {
|
|
598
|
-
options.page = page;
|
|
599
|
-
options._isPagination = true;
|
|
600
599
|
if (entity.client === undefined) {
|
|
601
600
|
throw new e.ElectroError(e.ErrorCodes.NoClientDefined, "No client defined on model");
|
|
602
601
|
}
|
|
602
|
+
options.page = page;
|
|
603
|
+
options._isPagination = true;
|
|
604
|
+
options.terminalOperation = TerminalOperation.page;
|
|
603
605
|
let params = clauses.params.action(entity, state, options);
|
|
604
606
|
let {config} = entity._applyParameterOptions({}, state.getOptions(), options);
|
|
605
607
|
return entity.go(state.getMethod(), params, config);
|
package/src/entity.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { Schema } = require("./schema");
|
|
3
|
-
const { KeyCasing, TableIndex, FormatToReturnValues, ReturnValues, EntityVersions, ItemOperations, UnprocessedTypes, Pager, ElectroInstance, KeyTypes, QueryTypes, MethodTypes, Comparisons, ExpressionTypes, ModelVersions, ElectroInstanceTypes, MaxBatchItems } = require("./types");
|
|
3
|
+
const { KeyCasing, TableIndex, FormatToReturnValues, ReturnValues, EntityVersions, ItemOperations, UnprocessedTypes, Pager, ElectroInstance, KeyTypes, QueryTypes, MethodTypes, Comparisons, ExpressionTypes, ModelVersions, ElectroInstanceTypes, MaxBatchItems, TerminalOperation } = require("./types");
|
|
4
4
|
const { FilterFactory } = require("./filters");
|
|
5
5
|
const { FilterOperations } = require("./operations");
|
|
6
6
|
const { WhereFactory } = require("./where");
|
|
@@ -84,13 +84,14 @@ class Entity {
|
|
|
84
84
|
return pkMatch;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
ownsPager(pager, index) {
|
|
87
|
+
ownsPager(pager, index = TableIndex) {
|
|
88
88
|
if (pager === null) {
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
|
-
let
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
let tableIndexFacets = this.model.facets.byIndex[TableIndex];
|
|
92
|
+
// todo: is the fact it doesn't use the provided index a bug?
|
|
93
|
+
// feels like collections may have played a roll into why this is this way
|
|
94
|
+
let indexFacets = this.model.facets.byIndex[TableIndex];
|
|
94
95
|
|
|
95
96
|
// Unknown index
|
|
96
97
|
if (tableIndexFacets === undefined || indexFacets === undefined) {
|
|
@@ -260,6 +261,7 @@ class Entity {
|
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
async _exec(method, params, config = {}) {
|
|
264
|
+
const entity = this;
|
|
263
265
|
const notifyQuery = () => {
|
|
264
266
|
this.eventManager.trigger({
|
|
265
267
|
type: "query",
|
|
@@ -285,6 +287,7 @@ class Entity {
|
|
|
285
287
|
return results;
|
|
286
288
|
})
|
|
287
289
|
.catch(err => {
|
|
290
|
+
notifyQuery();
|
|
288
291
|
notifyResults(err, false);
|
|
289
292
|
err.__isAWSError = true;
|
|
290
293
|
throw err;
|
|
@@ -822,6 +825,8 @@ class Entity {
|
|
|
822
825
|
pages: undefined,
|
|
823
826
|
listeners: [],
|
|
824
827
|
preserveBatchOrder: false,
|
|
828
|
+
attributes: [],
|
|
829
|
+
terminalOperation: undefined,
|
|
825
830
|
};
|
|
826
831
|
|
|
827
832
|
config = options.reduce((config, option) => {
|
|
@@ -834,6 +839,14 @@ class Entity {
|
|
|
834
839
|
config.params.ReturnValues = FormatToReturnValues[format];
|
|
835
840
|
}
|
|
836
841
|
|
|
842
|
+
if (option.terminalOperation in TerminalOperation) {
|
|
843
|
+
config.terminalOperation = TerminalOperation[option.terminalOperation];
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (Array.isArray(option.attributes)) {
|
|
847
|
+
config.attributes = config.attributes.concat(option.attributes);
|
|
848
|
+
}
|
|
849
|
+
|
|
837
850
|
if (option.preserveBatchOrder === true) {
|
|
838
851
|
config.preserveBatchOrder = true;
|
|
839
852
|
}
|
|
@@ -1019,7 +1032,103 @@ class Entity {
|
|
|
1019
1032
|
throw new Error(`Invalid method: ${method}`);
|
|
1020
1033
|
}
|
|
1021
1034
|
let applied = this._applyParameterOptions(params, options, config);
|
|
1022
|
-
return this.
|
|
1035
|
+
return this._applyParameterExpressions(method, applied.parameters, applied.config, filter);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
_applyParameterExpressions(method, parameters, config, filter) {
|
|
1039
|
+
if (method !== MethodTypes.get) {
|
|
1040
|
+
return this._applyParameterExpressionTypes(parameters, filter);
|
|
1041
|
+
} else {
|
|
1042
|
+
parameters = this._applyProjectionExpressions({parameters, config});
|
|
1043
|
+
return this._applyParameterExpressionTypes(parameters, filter);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
_applyProjectionExpressions({parameters = {}, config = {}} = {}) {
|
|
1049
|
+
const attributes = config.attributes || [];
|
|
1050
|
+
if (attributes.length === 0) {
|
|
1051
|
+
return parameters;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
const requiresRawResponse = !!config.raw;
|
|
1055
|
+
const enforcesOwnership = !config.ignoreOwnership;
|
|
1056
|
+
const requiresUserInvolvedPagination = TerminalOperation[config.terminalOperation] === TerminalOperation.page;
|
|
1057
|
+
const isServerBound = TerminalOperation[config.terminalOperation] === TerminalOperation.go ||
|
|
1058
|
+
TerminalOperation[config.terminalOperation] === TerminalOperation.page;
|
|
1059
|
+
|
|
1060
|
+
// 1. Take stock of invalid attributes, if there are any this should be considered
|
|
1061
|
+
// unintentional and should throw to prevent unintended results
|
|
1062
|
+
// 2. Convert all attribute names to their respective "field" names
|
|
1063
|
+
const unknownAttributes = [];
|
|
1064
|
+
let attributeFields = new Set();
|
|
1065
|
+
for (const attributeName of attributes) {
|
|
1066
|
+
const fieldName = this.model.schema.getFieldName(attributeName);
|
|
1067
|
+
if (typeof fieldName !== "string") {
|
|
1068
|
+
unknownAttributes.push(attributeName);
|
|
1069
|
+
} else {
|
|
1070
|
+
attributeFields.add(fieldName);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// Stop doing work, prepare error message and throw
|
|
1075
|
+
if (attributeFields.size === 0 || unknownAttributes.length > 0) {
|
|
1076
|
+
let message = 'Unknown attributes provided in query options';
|
|
1077
|
+
if (unknownAttributes.length) {
|
|
1078
|
+
message += `: ${u.commaSeparatedString(unknownAttributes)}`;
|
|
1079
|
+
}
|
|
1080
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidOptions, message);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// add ExpressionAttributeNames if it doesn't exist already
|
|
1084
|
+
parameters.ExpressionAttributeNames = parameters.ExpressionAttributeNames || {};
|
|
1085
|
+
|
|
1086
|
+
if (
|
|
1087
|
+
// The response you're returning:
|
|
1088
|
+
// 1. is not expected to be raw
|
|
1089
|
+
!requiresRawResponse
|
|
1090
|
+
// 2. is making a request to the server
|
|
1091
|
+
&& isServerBound
|
|
1092
|
+
// 3. will expect entity identifiers down stream
|
|
1093
|
+
&& enforcesOwnership
|
|
1094
|
+
|
|
1095
|
+
) {
|
|
1096
|
+
// add entity identifiers to so items can be identified
|
|
1097
|
+
attributeFields.add(this.identifiers.entity);
|
|
1098
|
+
attributeFields.add(this.identifiers.version);
|
|
1099
|
+
|
|
1100
|
+
// if pagination is required you may enter into a scenario where
|
|
1101
|
+
// the LastEvaluatedKey doesn't belong to entity and one must be formed.
|
|
1102
|
+
// We must add the attributes necessary to make that key to not break
|
|
1103
|
+
// pagination. This stinks.
|
|
1104
|
+
if (
|
|
1105
|
+
requiresUserInvolvedPagination
|
|
1106
|
+
&& config.pager !== Pager.raw
|
|
1107
|
+
) {
|
|
1108
|
+
// LastEvaluatedKeys return the TableIndex keys and the keys for the SecondaryIndex
|
|
1109
|
+
let tableIndexFacets = this.model.facets.byIndex[TableIndex];
|
|
1110
|
+
let indexFacets = this.model.facets.byIndex[parameters.IndexName] || { all: [] };
|
|
1111
|
+
|
|
1112
|
+
for (const attribute of [...tableIndexFacets.all, ...indexFacets.all]) {
|
|
1113
|
+
const fieldName = this.model.schema.getFieldName(attribute.name);
|
|
1114
|
+
attributeFields.add(fieldName);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
for (const attributeField of attributeFields) {
|
|
1120
|
+
// prefix the ExpressionAttributeNames because some prefixes are not allowed
|
|
1121
|
+
parameters.ExpressionAttributeNames['#' + attributeField] = attributeField;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// if there is already a ProjectionExpression (e.g. config "params"), merge it
|
|
1125
|
+
if (typeof parameters.ProjectionExpression === 'string') {
|
|
1126
|
+
parameters.ProjectionExpression = [parameters.ProjectionExpression, ...Object.keys([parameters.ExpressionAttributeNames])].join(', ');
|
|
1127
|
+
} else {
|
|
1128
|
+
parameters.ProjectionExpression = Object.keys(parameters.ExpressionAttributeNames).join(', ');
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
return parameters;
|
|
1023
1132
|
}
|
|
1024
1133
|
|
|
1025
1134
|
_batchGetParams(state, config = {}) {
|
|
@@ -1411,7 +1520,7 @@ class Entity {
|
|
|
1411
1520
|
throw new Error(`Invalid query type: ${state.query.type}`);
|
|
1412
1521
|
}
|
|
1413
1522
|
let applied = this._applyParameterOptions(parameters, state.query.options, options);
|
|
1414
|
-
return applied
|
|
1523
|
+
return this._applyProjectionExpressions(applied);
|
|
1415
1524
|
}
|
|
1416
1525
|
|
|
1417
1526
|
_makeBetweenQueryParams(index, filter, pk, ...sk) {
|
package/src/schema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { CastTypes, ValueTypes, KeyCasing, AttributeTypes, AttributeMutationMethods, AttributeWildCard, PathTypes
|
|
1
|
+
const { CastTypes, ValueTypes, KeyCasing, AttributeTypes, AttributeMutationMethods, AttributeWildCard, PathTypes } = 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");
|
|
@@ -1263,7 +1263,7 @@ class Schema {
|
|
|
1263
1263
|
translateToFields(payload = {}) {
|
|
1264
1264
|
let record = {};
|
|
1265
1265
|
for (let [name, value] of Object.entries(payload)) {
|
|
1266
|
-
let field = this.
|
|
1266
|
+
let field = this.getFieldName(name);
|
|
1267
1267
|
if (value !== undefined) {
|
|
1268
1268
|
record[field] = value;
|
|
1269
1269
|
}
|
|
@@ -1271,6 +1271,12 @@ class Schema {
|
|
|
1271
1271
|
return record;
|
|
1272
1272
|
}
|
|
1273
1273
|
|
|
1274
|
+
getFieldName(name) {
|
|
1275
|
+
if (typeof name === 'string') {
|
|
1276
|
+
return this.translationForTable[name];
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1274
1280
|
checkCreate(payload = {}) {
|
|
1275
1281
|
let record = {};
|
|
1276
1282
|
for (let attribute of Object.values(this.attributes)) {
|
|
@@ -1320,13 +1326,18 @@ class Schema {
|
|
|
1320
1326
|
}
|
|
1321
1327
|
|
|
1322
1328
|
formatItemForRetrieval(item, config) {
|
|
1329
|
+
let returnAttributes = new Set(config.attributes || []);
|
|
1330
|
+
let hasUserSpecifiedReturnAttributes = returnAttributes.size > 0;
|
|
1323
1331
|
let remapped = this.translateFromFields(item, config);
|
|
1324
1332
|
let data = this._fulfillAttributeMutationMethod("get", remapped);
|
|
1325
|
-
if (this.hiddenAttributes.size > 0) {
|
|
1333
|
+
if (this.hiddenAttributes.size > 0 || hasUserSpecifiedReturnAttributes) {
|
|
1326
1334
|
for (let attribute of Object.keys(data)) {
|
|
1327
1335
|
if (this.hiddenAttributes.has(attribute)) {
|
|
1328
1336
|
delete data[attribute];
|
|
1329
1337
|
}
|
|
1338
|
+
if (hasUserSpecifiedReturnAttributes && !returnAttributes.has(attribute)) {
|
|
1339
|
+
delete data[attribute];
|
|
1340
|
+
}
|
|
1330
1341
|
}
|
|
1331
1342
|
}
|
|
1332
1343
|
return data;
|
package/src/types.js
CHANGED
|
@@ -186,6 +186,11 @@ const EventSubscriptionTypes = [
|
|
|
186
186
|
"results"
|
|
187
187
|
];
|
|
188
188
|
|
|
189
|
+
const TerminalOperation = {
|
|
190
|
+
go: 'go',
|
|
191
|
+
page: 'page',
|
|
192
|
+
}
|
|
193
|
+
|
|
189
194
|
module.exports = {
|
|
190
195
|
Pager,
|
|
191
196
|
KeyTypes,
|
|
@@ -210,6 +215,7 @@ module.exports = {
|
|
|
210
215
|
TraverserIndexes,
|
|
211
216
|
UnprocessedTypes,
|
|
212
217
|
AttributeWildCard,
|
|
218
|
+
TerminalOperation,
|
|
213
219
|
FormatToReturnValues,
|
|
214
220
|
AttributeProxySymbol,
|
|
215
221
|
ElectroInstanceTypes,
|
package/src/parse.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
function getPartDetail(part = "") {
|
|
2
|
-
let detail = {
|
|
3
|
-
expression: "",
|
|
4
|
-
name: "",
|
|
5
|
-
value: "",
|
|
6
|
-
};
|
|
7
|
-
if (part.includes("[")) {
|
|
8
|
-
if (!part.match(/\[\d\]/gi)) {
|
|
9
|
-
throw new Error(`Invalid path part "${part}" has bracket containing non-numeric characters.`);
|
|
10
|
-
}
|
|
11
|
-
let [name] = part.match(/.*(?=\[)/gi);
|
|
12
|
-
detail.name = `#${name}`;
|
|
13
|
-
detail.value = name;
|
|
14
|
-
} else {
|
|
15
|
-
detail.name = `#${part}`;
|
|
16
|
-
detail.value = part;
|
|
17
|
-
}
|
|
18
|
-
detail.expression = `#${part}`;
|
|
19
|
-
return detail;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function parse(path = "") {
|
|
23
|
-
if (typeof path !== "string" || !path.length) {
|
|
24
|
-
throw new Error("Path must be a string with a non-zero length");
|
|
25
|
-
}
|
|
26
|
-
let parts = path.split(/\./gi);
|
|
27
|
-
let attr = getPartDetail(parts[0]).value;
|
|
28
|
-
let target = getPartDetail(parts[parts.length-1]);
|
|
29
|
-
if (target.expression.includes("[")) {
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
let names = {};
|
|
33
|
-
let expressions = [];
|
|
34
|
-
for (let part of parts) {
|
|
35
|
-
let detail = getPartDetail(part);
|
|
36
|
-
names[detail.name] = detail.value;
|
|
37
|
-
expressions.push(detail.expression);
|
|
38
|
-
}
|
|
39
|
-
return {attr, path, names, target: target.value, expression: expressions.join(".")};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
module.exports = {
|
|
43
|
-
parse,
|
|
44
|
-
getPartDetail
|
|
45
|
-
};
|