electrodb 2.11.0 → 2.12.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/README.md +2 -2
- package/index.d.ts +152 -49
- package/package.json +1 -1
- package/src/entity.js +41 -9
- package/src/errors.js +6 -0
- package/src/operations.js +6 -8
- package/src/schema.js +0 -12
- package/src/validations.js +5 -0
package/README.md
CHANGED
|
@@ -46,10 +46,10 @@ _Please submit issues/feedback or reach out on Twitter [@tinkertamper](https://t
|
|
|
46
46
|
- [**Easily Query Across Entities**](https://electrodb.dev/en/core-concepts/single-table-relationships) - Define "collections" to create powerful/idiomatic queries that return multiple entities in a single request.
|
|
47
47
|
- [**Automatic Index Selection**](https://electrodb.dev/en/queries/find/) - Use `.find()` or `.match()` methods to dynamically and efficiently query based on defined sort key structures.
|
|
48
48
|
- [**Simplified Pagination API**](https://electrodb.dev/en/queries/pagination/) - ElectroDB generates url safe cursors for pagination, allows for fine grain automated pagination, and supports async iteration.
|
|
49
|
-
- [**TypeScript
|
|
49
|
+
- [**Strong TypeScript Inference**](https://electrodb.dev/en/reference/typescript/) - Strong **TypeScript** support for both Entities and Services now in Beta.
|
|
50
50
|
- [**Query Directly via the Terminal**](https://github.com/tywalch/electrocli#query-taskapp) - Execute queries against your `Entities`, `Services`, `Models` directly from the command line.
|
|
51
51
|
- [**Stand Up Rest Server for Entities**](https://github.com/tywalch/electrocli#query-taskapp) - Stand up a REST Server to interact with your `Entities`, `Services`, `Models` for easier prototyping.
|
|
52
|
-
- [**Use with your existing tables**](https://electrodb.dev/en/
|
|
52
|
+
- [**Use with your existing tables**](https://electrodb.dev/en/recipes/use-electrodb-with-existing-table/) - ElectroDB simplifies building DocumentClient parameters, so you can use it with existing tables/data.
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
package/index.d.ts
CHANGED
|
@@ -3216,6 +3216,27 @@ export interface MapAttribute {
|
|
|
3216
3216
|
readonly watch?: ReadonlyArray<string> | "*";
|
|
3217
3217
|
}
|
|
3218
3218
|
|
|
3219
|
+
export interface NestedCustomListAttribute {
|
|
3220
|
+
readonly type: "list";
|
|
3221
|
+
readonly items: CustomAttribute;
|
|
3222
|
+
readonly required?: boolean;
|
|
3223
|
+
readonly hidden?: boolean;
|
|
3224
|
+
readonly readOnly?: boolean;
|
|
3225
|
+
readonly get?: (
|
|
3226
|
+
val: Array<any>,
|
|
3227
|
+
item: any,
|
|
3228
|
+
) => Array<string> | undefined | void;
|
|
3229
|
+
readonly set?: (
|
|
3230
|
+
val?: Array<any>,
|
|
3231
|
+
item?: any,
|
|
3232
|
+
) => Array<any> | undefined | void;
|
|
3233
|
+
readonly default?: Array<any> | (() => Array<any>);
|
|
3234
|
+
readonly validate?:
|
|
3235
|
+
| ((val: Array<any>) => boolean)
|
|
3236
|
+
| ((val: Array<any>) => void)
|
|
3237
|
+
| ((val: Array<any>) => string | void);
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3219
3240
|
export interface NestedStringListAttribute {
|
|
3220
3241
|
readonly type: "list";
|
|
3221
3242
|
readonly items: {
|
|
@@ -3354,6 +3375,28 @@ export interface NestedMapListAttribute {
|
|
|
3354
3375
|
readonly field?: string;
|
|
3355
3376
|
}
|
|
3356
3377
|
|
|
3378
|
+
export interface NestedAnyListAttribute {
|
|
3379
|
+
readonly type: "list";
|
|
3380
|
+
readonly items: NestedAnyAttribute;
|
|
3381
|
+
readonly required?: boolean;
|
|
3382
|
+
readonly hidden?: boolean;
|
|
3383
|
+
readonly readOnly?: boolean;
|
|
3384
|
+
readonly get?: (
|
|
3385
|
+
val: Record<string, any>[],
|
|
3386
|
+
item: any,
|
|
3387
|
+
) => Record<string, any>[] | undefined | void;
|
|
3388
|
+
readonly set?: (
|
|
3389
|
+
val?: Record<string, any>[],
|
|
3390
|
+
item?: any,
|
|
3391
|
+
) => Record<string, any>[] | undefined | void;
|
|
3392
|
+
readonly default?: Record<string, any>[] | (() => Record<string, any>[]);
|
|
3393
|
+
readonly validate?:
|
|
3394
|
+
| ((val: Record<string, any>[]) => boolean)
|
|
3395
|
+
| ((val: Record<string, any>[]) => void)
|
|
3396
|
+
| ((val: Record<string, any>[]) => string | void);
|
|
3397
|
+
readonly field?: string;
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3357
3400
|
export interface MapListAttribute {
|
|
3358
3401
|
readonly type: "list";
|
|
3359
3402
|
readonly items: NestedMapAttribute;
|
|
@@ -3377,6 +3420,52 @@ export interface MapListAttribute {
|
|
|
3377
3420
|
readonly watch?: ReadonlyArray<string> | "*";
|
|
3378
3421
|
}
|
|
3379
3422
|
|
|
3423
|
+
export interface CustomListAttribute {
|
|
3424
|
+
readonly type: "list";
|
|
3425
|
+
readonly items: NestedCustomAttribute;
|
|
3426
|
+
readonly required?: boolean;
|
|
3427
|
+
readonly hidden?: boolean;
|
|
3428
|
+
readonly readOnly?: boolean;
|
|
3429
|
+
readonly get?: (
|
|
3430
|
+
val: Array<any>,
|
|
3431
|
+
item: any,
|
|
3432
|
+
) => Array<any> | undefined | void;
|
|
3433
|
+
readonly set?: (
|
|
3434
|
+
val?: Array<any>,
|
|
3435
|
+
item?: any,
|
|
3436
|
+
) => Array<any> | undefined | void;
|
|
3437
|
+
readonly default?: Array<any> | (() => Array<any>);
|
|
3438
|
+
readonly validate?:
|
|
3439
|
+
| ((val: Array<any>) => boolean)
|
|
3440
|
+
| ((val: Array<any>) => void)
|
|
3441
|
+
| ((val: Array<any>) => string | void);
|
|
3442
|
+
readonly field?: string;
|
|
3443
|
+
readonly watch?: ReadonlyArray<string> | "*";
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
export interface AnyListAttribute {
|
|
3447
|
+
readonly type: "list";
|
|
3448
|
+
readonly items: NestedAnyAttribute;
|
|
3449
|
+
readonly required?: boolean;
|
|
3450
|
+
readonly hidden?: boolean;
|
|
3451
|
+
readonly readOnly?: boolean;
|
|
3452
|
+
readonly get?: (
|
|
3453
|
+
val: Array<any>,
|
|
3454
|
+
item: any,
|
|
3455
|
+
) => Array<any> | undefined | void;
|
|
3456
|
+
readonly set?: (
|
|
3457
|
+
val?: Array<any>,
|
|
3458
|
+
item?: any,
|
|
3459
|
+
) => Array<any> | undefined | void;
|
|
3460
|
+
readonly default?: Array<any> | (() => Array<any>);
|
|
3461
|
+
readonly validate?:
|
|
3462
|
+
| ((val: Array<any>) => boolean)
|
|
3463
|
+
| ((val: Array<any>) => void)
|
|
3464
|
+
| ((val: Array<any>) => string | void);
|
|
3465
|
+
readonly field?: string;
|
|
3466
|
+
readonly watch?: ReadonlyArray<string> | "*";
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3380
3469
|
export interface NestedStringSetAttribute {
|
|
3381
3470
|
readonly type: "set";
|
|
3382
3471
|
readonly items: "string";
|
|
@@ -3563,13 +3652,6 @@ export interface NumberSetAttribute {
|
|
|
3563
3652
|
readonly watch?: ReadonlyArray<string> | "*";
|
|
3564
3653
|
}
|
|
3565
3654
|
|
|
3566
|
-
type StaticAttribute = {
|
|
3567
|
-
readonly type: "static";
|
|
3568
|
-
readonly hidden?: boolean;
|
|
3569
|
-
value: string | number | boolean;
|
|
3570
|
-
readonly field?: string;
|
|
3571
|
-
};
|
|
3572
|
-
|
|
3573
3655
|
type CustomAttributeTypeName<T> = { readonly [CustomAttributeSymbol]: T };
|
|
3574
3656
|
|
|
3575
3657
|
type OpaquePrimitiveTypeName<T extends string | number | boolean> =
|
|
@@ -3597,6 +3679,21 @@ type CustomAttribute = {
|
|
|
3597
3679
|
readonly watch?: ReadonlyArray<string> | "*";
|
|
3598
3680
|
};
|
|
3599
3681
|
|
|
3682
|
+
type NestedCustomAttribute = {
|
|
3683
|
+
readonly type: CustomAttributeTypeName<any> | OpaquePrimitiveTypeName<any>;
|
|
3684
|
+
readonly required?: boolean;
|
|
3685
|
+
readonly hidden?: boolean;
|
|
3686
|
+
readonly readOnly?: boolean;
|
|
3687
|
+
readonly get?: (val: any, item: any) => any | undefined | void;
|
|
3688
|
+
readonly set?: (val?: any, item?: any) => any | undefined | void;
|
|
3689
|
+
readonly default?: any | (() => any);
|
|
3690
|
+
readonly validate?:
|
|
3691
|
+
| ((val: any) => boolean)
|
|
3692
|
+
| ((val: any) => void)
|
|
3693
|
+
| ((val: any) => string | void);
|
|
3694
|
+
readonly field?: string;
|
|
3695
|
+
};
|
|
3696
|
+
|
|
3600
3697
|
export type Attribute =
|
|
3601
3698
|
| BooleanAttribute
|
|
3602
3699
|
| NumberAttribute
|
|
@@ -3609,7 +3706,8 @@ export type Attribute =
|
|
|
3609
3706
|
| StringListAttribute
|
|
3610
3707
|
| NumberListAttribute
|
|
3611
3708
|
| MapListAttribute
|
|
3612
|
-
|
|
|
3709
|
+
| AnyListAttribute
|
|
3710
|
+
| CustomListAttribute
|
|
3613
3711
|
| CustomAttribute
|
|
3614
3712
|
| EnumNumberSetAttribute
|
|
3615
3713
|
| EnumStringSetAttribute;
|
|
@@ -3621,12 +3719,14 @@ export type NestedAttributes =
|
|
|
3621
3719
|
| NestedAnyAttribute
|
|
3622
3720
|
| NestedMapAttribute
|
|
3623
3721
|
| NestedStringListAttribute
|
|
3722
|
+
| NestedCustomListAttribute
|
|
3624
3723
|
| NestedNumberListAttribute
|
|
3625
3724
|
| NestedMapListAttribute
|
|
3725
|
+
| NestedAnyListAttribute
|
|
3626
3726
|
| NestedStringSetAttribute
|
|
3627
3727
|
| NestedNumberSetAttribute
|
|
3628
3728
|
| NestedEnumAttribute
|
|
3629
|
-
|
|
|
3729
|
+
| NestedCustomAttribute
|
|
3630
3730
|
| NestedEnumNumberSetAttribute
|
|
3631
3731
|
| NestedEnumStringSetAttribute;
|
|
3632
3732
|
|
|
@@ -3658,6 +3758,7 @@ export interface Schema<A extends string, F extends string, C extends string> {
|
|
|
3658
3758
|
readonly scope?: string;
|
|
3659
3759
|
readonly type?: "clustered" | "isolated";
|
|
3660
3760
|
readonly collection?: AccessPatternCollection<C>;
|
|
3761
|
+
readonly condition?: (composite: Record<string, unknown>) => boolean;
|
|
3661
3762
|
readonly pk: {
|
|
3662
3763
|
readonly casing?: "upper" | "lower" | "none" | "default";
|
|
3663
3764
|
readonly field: string;
|
|
@@ -3813,51 +3914,53 @@ type PartialDefinedKeys<T> = {
|
|
|
3813
3914
|
};
|
|
3814
3915
|
|
|
3815
3916
|
export type ItemAttribute<A extends Attribute> =
|
|
3816
|
-
A["type"] extends
|
|
3817
|
-
? T
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
? string
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
?
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
?
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
?
|
|
3842
|
-
?
|
|
3843
|
-
?
|
|
3917
|
+
A["type"] extends infer T
|
|
3918
|
+
? T extends OpaquePrimitiveTypeName<infer OP>
|
|
3919
|
+
? OP
|
|
3920
|
+
: T extends CustomAttributeTypeName<infer CA>
|
|
3921
|
+
? CA
|
|
3922
|
+
: T extends infer R
|
|
3923
|
+
? R extends "string"
|
|
3924
|
+
? string
|
|
3925
|
+
: R extends "number"
|
|
3926
|
+
? number
|
|
3927
|
+
: R extends "boolean"
|
|
3928
|
+
? boolean
|
|
3929
|
+
: R extends ReadonlyArray<infer E>
|
|
3930
|
+
? E
|
|
3931
|
+
: R extends "map"
|
|
3932
|
+
? "properties" extends keyof A
|
|
3933
|
+
? {
|
|
3934
|
+
[P in keyof A["properties"]]: A["properties"][P] extends infer M
|
|
3935
|
+
? M extends Attribute
|
|
3936
|
+
? ItemAttribute<M>
|
|
3937
|
+
: never
|
|
3938
|
+
: never;
|
|
3939
|
+
}
|
|
3940
|
+
: never
|
|
3941
|
+
: R extends "list"
|
|
3942
|
+
? "items" extends keyof A
|
|
3943
|
+
? A["items"] extends infer I
|
|
3944
|
+
? I extends Attribute
|
|
3945
|
+
? Array<ItemAttribute<I>>
|
|
3946
|
+
: never
|
|
3844
3947
|
: never
|
|
3845
3948
|
: never
|
|
3846
|
-
:
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3949
|
+
: R extends "set"
|
|
3950
|
+
? "items" extends keyof A
|
|
3951
|
+
? A["items"] extends infer I
|
|
3952
|
+
? I extends "string"
|
|
3953
|
+
? string[]
|
|
3954
|
+
: I extends "number"
|
|
3955
|
+
? number[]
|
|
3956
|
+
: I extends ReadonlyArray<infer ENUM>
|
|
3957
|
+
? ENUM[]
|
|
3958
|
+
: never
|
|
3856
3959
|
: never
|
|
3857
3960
|
: never
|
|
3961
|
+
: R extends "any"
|
|
3962
|
+
? any
|
|
3858
3963
|
: never
|
|
3859
|
-
: R extends "any"
|
|
3860
|
-
? any
|
|
3861
3964
|
: never
|
|
3862
3965
|
: never;
|
|
3863
3966
|
|
package/package.json
CHANGED
package/src/entity.js
CHANGED
|
@@ -2412,7 +2412,7 @@ class Entity {
|
|
|
2412
2412
|
(!attribute || !attribute.indexes || attribute.indexes.length === 0)
|
|
2413
2413
|
) {
|
|
2414
2414
|
/*
|
|
2415
|
-
// this should be considered but is likely overkill at best and unexpected at worst.
|
|
2415
|
+
// this should be considered but is likely overkill at best and unexpected at worst.
|
|
2416
2416
|
// It also is likely symbolic of a deeper issue. That said maybe it could be helpful
|
|
2417
2417
|
// in the future? It is unclear, if this were added, whether this should get the
|
|
2418
2418
|
// default value and then call the setter on the defaultValue. That would at least
|
|
@@ -2880,12 +2880,18 @@ class Entity {
|
|
|
2880
2880
|
)}. If a composite attribute is readOnly and cannot be set, use the 'composite' chain method on update to supply the value for key formatting purposes.`,
|
|
2881
2881
|
);
|
|
2882
2882
|
}
|
|
2883
|
+
|
|
2883
2884
|
return complete;
|
|
2884
2885
|
}
|
|
2885
2886
|
|
|
2886
2887
|
_makeKeysFromAttributes(indexes, attributes) {
|
|
2887
2888
|
let indexKeys = {};
|
|
2888
2889
|
for (let [index, keyTypes] of Object.entries(indexes)) {
|
|
2890
|
+
const shouldMakeKeys = this.model.indexes[this.model.translations.indexes.fromIndexToAccessPattern[index]].condition(attributes);
|
|
2891
|
+
if (!shouldMakeKeys) {
|
|
2892
|
+
continue;
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2889
2895
|
let keys = this._makeIndexKeys({
|
|
2890
2896
|
index,
|
|
2891
2897
|
pkAttributes: attributes,
|
|
@@ -2912,6 +2918,10 @@ class Entity {
|
|
|
2912
2918
|
_makePutKeysFromAttributes(indexes, attributes) {
|
|
2913
2919
|
let indexKeys = {};
|
|
2914
2920
|
for (let index of indexes) {
|
|
2921
|
+
const shouldMakeKeys = this.model.indexes[this.model.translations.indexes.fromIndexToAccessPattern[index]].condition(attributes);
|
|
2922
|
+
if (!shouldMakeKeys) {
|
|
2923
|
+
continue;
|
|
2924
|
+
}
|
|
2915
2925
|
indexKeys[index] = this._makeIndexKeys({
|
|
2916
2926
|
index,
|
|
2917
2927
|
pkAttributes: attributes,
|
|
@@ -2984,6 +2994,7 @@ class Entity {
|
|
|
2984
2994
|
completeFacets.impactedIndexTypes,
|
|
2985
2995
|
{ ...set, ...keyAttributes },
|
|
2986
2996
|
);
|
|
2997
|
+
|
|
2987
2998
|
let updatedKeys = {};
|
|
2988
2999
|
let deletedKeys = [];
|
|
2989
3000
|
let indexKey = {};
|
|
@@ -3027,6 +3038,7 @@ class Entity {
|
|
|
3027
3038
|
_getIndexImpact(attributes = {}, included = {}) {
|
|
3028
3039
|
let includedFacets = Object.keys(included);
|
|
3029
3040
|
let impactedIndexes = {};
|
|
3041
|
+
let skippedIndexes = new Set();
|
|
3030
3042
|
let impactedIndexTypes = {};
|
|
3031
3043
|
let completedIndexes = [];
|
|
3032
3044
|
let facets = {};
|
|
@@ -3034,21 +3046,32 @@ class Entity {
|
|
|
3034
3046
|
if (attributes[attribute] !== undefined) {
|
|
3035
3047
|
facets[attribute] = attributes[attribute];
|
|
3036
3048
|
indexes.forEach(({ index, type }) => {
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3049
|
+
impactedIndexes[index] = impactedIndexes[index] || {};
|
|
3050
|
+
impactedIndexes[index][type] = impactedIndexes[index][type] || [];
|
|
3051
|
+
impactedIndexes[index][type].push(attribute);
|
|
3052
|
+
impactedIndexTypes[index] = impactedIndexTypes[index] || {};
|
|
3053
|
+
impactedIndexTypes[index][type] =
|
|
3054
|
+
this.model.translations.keys[index][type];
|
|
3043
3055
|
});
|
|
3044
3056
|
}
|
|
3045
3057
|
}
|
|
3046
3058
|
|
|
3059
|
+
for (const indexName in impactedIndexes) {
|
|
3060
|
+
const accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[indexName];
|
|
3061
|
+
const shouldMakeKeys = this.model.indexes[accessPattern].condition({ ...attributes, ...included });
|
|
3062
|
+
if (!shouldMakeKeys) {
|
|
3063
|
+
skippedIndexes.add(indexName);
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3047
3067
|
let incomplete = Object.entries(this.model.facets.byIndex)
|
|
3048
3068
|
.map(([index, { pk, sk }]) => {
|
|
3049
3069
|
let impacted = impactedIndexes[index];
|
|
3050
|
-
let impact = {
|
|
3051
|
-
|
|
3070
|
+
let impact = {
|
|
3071
|
+
index,
|
|
3072
|
+
missing: []
|
|
3073
|
+
};
|
|
3074
|
+
if (impacted && !skippedIndexes.has(index)) {
|
|
3052
3075
|
let missingPk =
|
|
3053
3076
|
impacted[KeyTypes.pk] && impacted[KeyTypes.pk].length !== pk.length;
|
|
3054
3077
|
let missingSk =
|
|
@@ -3846,6 +3869,14 @@ class Entity {
|
|
|
3846
3869
|
let indexType =
|
|
3847
3870
|
typeof index.type === "string" ? index.type : IndexTypes.isolated;
|
|
3848
3871
|
let indexScope = index.scope || "";
|
|
3872
|
+
if (index.index === undefined && v.isFunction(index.condition)) {
|
|
3873
|
+
throw new e.ElectroError(
|
|
3874
|
+
e.ErrorCodes.InvalidIndexCondition,
|
|
3875
|
+
`The index option 'condition' is only allowed on secondary indexes`,
|
|
3876
|
+
);
|
|
3877
|
+
}
|
|
3878
|
+
let indexCondition = index.condition || (() => true);
|
|
3879
|
+
|
|
3849
3880
|
if (indexType === "clustered") {
|
|
3850
3881
|
clusteredIndexes.add(accessPattern);
|
|
3851
3882
|
}
|
|
@@ -3953,6 +3984,7 @@ class Entity {
|
|
|
3953
3984
|
type: indexType,
|
|
3954
3985
|
index: indexName,
|
|
3955
3986
|
scope: indexScope,
|
|
3987
|
+
condition: indexCondition,
|
|
3956
3988
|
};
|
|
3957
3989
|
|
|
3958
3990
|
indexHasSubCollections[indexName] =
|
package/src/errors.js
CHANGED
|
@@ -211,6 +211,12 @@ const ErrorCodes = {
|
|
|
211
211
|
name: "DuplicateUpdateCompositesProvided",
|
|
212
212
|
sym: ErrorCode,
|
|
213
213
|
},
|
|
214
|
+
InvalidIndexCondition: {
|
|
215
|
+
code: 2011,
|
|
216
|
+
section: "invalid-index-option",
|
|
217
|
+
name: "InvalidIndexOption",
|
|
218
|
+
sym: ErrorCode,
|
|
219
|
+
},
|
|
214
220
|
InvalidAttribute: {
|
|
215
221
|
code: 3001,
|
|
216
222
|
section: "invalid-attribute",
|
package/src/operations.js
CHANGED
|
@@ -313,16 +313,13 @@ class AttributeOperationProxy {
|
|
|
313
313
|
return AttributeOperationProxy.pathProxy(() => {
|
|
314
314
|
const { commit, root, target, builder } = build();
|
|
315
315
|
const attribute = target.getChild(prop);
|
|
316
|
+
const nestedAny = attribute.type === AttributeTypes.any &&
|
|
317
|
+
// if the name doesn't match that's because we are nested under 'any'
|
|
318
|
+
attribute.name !== prop;
|
|
316
319
|
let field;
|
|
317
320
|
if (attribute === undefined) {
|
|
318
|
-
throw new Error(
|
|
319
|
-
|
|
320
|
-
);
|
|
321
|
-
} else if (
|
|
322
|
-
attribute === root &&
|
|
323
|
-
attribute.type === AttributeTypes.any
|
|
324
|
-
) {
|
|
325
|
-
// 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
|
|
321
|
+
throw new Error(`Invalid attribute "${prop}" at path "${target.path}.${prop}"`);
|
|
322
|
+
} else if (nestedAny) {
|
|
326
323
|
field = prop;
|
|
327
324
|
} else {
|
|
328
325
|
field = attribute.field;
|
|
@@ -331,6 +328,7 @@ class AttributeOperationProxy {
|
|
|
331
328
|
return {
|
|
332
329
|
root,
|
|
333
330
|
builder,
|
|
331
|
+
nestedAny,
|
|
334
332
|
target: attribute,
|
|
335
333
|
commit: () => {
|
|
336
334
|
const paths = commit();
|
package/src/schema.js
CHANGED
|
@@ -1496,18 +1496,6 @@ class Schema {
|
|
|
1496
1496
|
case AttributeTypes.set:
|
|
1497
1497
|
normalized[name] = new SetAttribute(definition);
|
|
1498
1498
|
break;
|
|
1499
|
-
case AttributeTypes.any:
|
|
1500
|
-
if (attributeHasParent) {
|
|
1501
|
-
throw new e.ElectroError(
|
|
1502
|
-
e.ErrorCodes.InvalidAttributeDefinition,
|
|
1503
|
-
`Invalid attribute "${definition.name}" defined within "${
|
|
1504
|
-
parent.parentPath
|
|
1505
|
-
}". Attributes with type ${u.commaSeparatedString([
|
|
1506
|
-
AttributeTypes.any,
|
|
1507
|
-
AttributeTypes.custom,
|
|
1508
|
-
])} are only supported as root level attributes.`,
|
|
1509
|
-
);
|
|
1510
|
-
}
|
|
1511
1499
|
default:
|
|
1512
1500
|
normalized[name] = new Attribute(definition);
|
|
1513
1501
|
}
|