electrodb 2.5.1 → 2.6.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/index.d.ts +101 -11
- package/output +168 -0
- package/package.json +3 -3
- package/src/clauses.js +25 -4
- package/src/entity.js +556 -96
- package/src/errors.js +18 -0
- package/src/service.js +78 -6
- package/src/update.js +24 -4
- package/src/util.js +5 -0
package/src/entity.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { Schema } = require("./schema");
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
AllPages,
|
|
4
5
|
KeyCasing,
|
|
5
6
|
TableIndex,
|
|
6
7
|
FormatToReturnValues,
|
|
@@ -35,7 +36,6 @@ const validations = require("./validations");
|
|
|
35
36
|
const c = require('./client');
|
|
36
37
|
const u = require("./util");
|
|
37
38
|
const e = require("./errors");
|
|
38
|
-
const { validate } = require("jsonschema");
|
|
39
39
|
const v = require('./validations');
|
|
40
40
|
|
|
41
41
|
class Entity {
|
|
@@ -59,6 +59,21 @@ class Entity {
|
|
|
59
59
|
this._clausesWithFilters = this._whereBuilder.injectWhereClauses(this._clausesWithFilters);
|
|
60
60
|
|
|
61
61
|
this.query = {};
|
|
62
|
+
this.conversions = {
|
|
63
|
+
fromComposite: {
|
|
64
|
+
toKeys: (composite, options = {}) => this._fromCompositeToKeys({ provided: composite }, options),
|
|
65
|
+
toCursor: (composite) => this._fromCompositeToCursor({ provided: composite }, { strict: 'all' }),
|
|
66
|
+
},
|
|
67
|
+
fromKeys: {
|
|
68
|
+
toCursor: (keys) => this._fromKeysToCursor({provided: keys}, {}),
|
|
69
|
+
toComposite: (keys) => this._fromKeysToComposite({ provided: keys }),
|
|
70
|
+
},
|
|
71
|
+
fromCursor: {
|
|
72
|
+
toKeys: (cursor) => this._fromCursorToKeys({provided: cursor}),
|
|
73
|
+
toComposite: (cursor) => this._fromCursorToComposite({provided: cursor}),
|
|
74
|
+
},
|
|
75
|
+
byAccessPattern: {}
|
|
76
|
+
};
|
|
62
77
|
for (let accessPattern in this.model.indexes) {
|
|
63
78
|
let index = this.model.indexes[accessPattern].index;
|
|
64
79
|
this.query[accessPattern] = (...values) => {
|
|
@@ -67,7 +82,24 @@ class Entity {
|
|
|
67
82
|
}
|
|
68
83
|
return this._makeChain(index, this._clausesWithFilters, clauses.index, options).query(...values);
|
|
69
84
|
};
|
|
85
|
+
|
|
86
|
+
this.conversions.byAccessPattern[accessPattern] = {
|
|
87
|
+
fromKeys: {
|
|
88
|
+
toCursor: (keys) => this._fromKeysToCursorByIndex({indexName: index, provided: keys}),
|
|
89
|
+
toComposite: (keys) => this._fromKeysToCompositeByIndex({indexName: index, provided: keys}),
|
|
90
|
+
},
|
|
91
|
+
fromCursor: {
|
|
92
|
+
toKeys: (cursor) => this._fromCursorToKeysByIndex({indexName: index, provided: cursor}),
|
|
93
|
+
toComposite: (cursor) => this._fromCursorToCompositeByIndex({indexName: index, provided: cursor}),
|
|
94
|
+
},
|
|
95
|
+
fromComposite: {
|
|
96
|
+
toCursor: (composite) => this._fromCompositeToCursorByIndex({indexName: index, provided: composite}, { strict: 'all' }),
|
|
97
|
+
toKeys: (composite, options = {}) => this._fromCompositeToKeysByIndex({indexName: index, provided: composite}, options),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
70
101
|
}
|
|
102
|
+
|
|
71
103
|
this.config.identifiers = config.identifiers || {};
|
|
72
104
|
this.identifiers = {
|
|
73
105
|
entity: this.config.identifiers.entity || "__edb_e__",
|
|
@@ -98,6 +130,36 @@ class Entity {
|
|
|
98
130
|
return this.model.version;
|
|
99
131
|
}
|
|
100
132
|
|
|
133
|
+
// ownsItem(item) {
|
|
134
|
+
// return (
|
|
135
|
+
// item &&
|
|
136
|
+
// this.getName() === item[this.identifiers.entity] &&
|
|
137
|
+
// this.getVersion() === item[this.identifiers.version] &&
|
|
138
|
+
// validations.isStringHasLength(item[this.identifiers.entity]) &&
|
|
139
|
+
// validations.isStringHasLength(item[this.identifiers.version])
|
|
140
|
+
// ) || !!this.ownsKeys(item)
|
|
141
|
+
// }
|
|
142
|
+
|
|
143
|
+
// ownsKeys({keys = {}}) {
|
|
144
|
+
// let {pk, sk} = this.model.prefixes[TableIndex];
|
|
145
|
+
// let hasSK = this.model.lookup.indexHasSortKeys[TableIndex];
|
|
146
|
+
// let pkMatch = typeof keys[pk.field] === "string" && keys[pk.field].startsWith(pk.prefix);
|
|
147
|
+
// let skMatch = pkMatch && !hasSK;
|
|
148
|
+
// if (pkMatch && hasSK) {
|
|
149
|
+
// skMatch = typeof keys[sk.field] === "string" && keys[sk.field].startsWith(sk.prefix);
|
|
150
|
+
// }
|
|
151
|
+
//
|
|
152
|
+
// return (pkMatch && skMatch &&
|
|
153
|
+
// this._formatKeysToItem(TableIndex, key) !== null);
|
|
154
|
+
// }
|
|
155
|
+
|
|
156
|
+
// ownsCursor({ cursor }) {
|
|
157
|
+
// if (typeof cursor === 'string') {
|
|
158
|
+
// cursor = u.cursorFormatter.deserialize(cursor);
|
|
159
|
+
// }
|
|
160
|
+
// return this.ownsKeys({ keys: cursor });
|
|
161
|
+
// }
|
|
162
|
+
|
|
101
163
|
ownsItem(item) {
|
|
102
164
|
return (
|
|
103
165
|
item &&
|
|
@@ -108,21 +170,43 @@ class Entity {
|
|
|
108
170
|
)
|
|
109
171
|
}
|
|
110
172
|
|
|
111
|
-
|
|
173
|
+
_attributesIncludeKeys(attributes = []) {
|
|
174
|
+
let {pk, sk} = this.model.prefixes[TableIndex];
|
|
175
|
+
let pkFound = false;
|
|
176
|
+
let skFound = false;
|
|
177
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
178
|
+
const attribute = attributes[i];
|
|
179
|
+
if (attribute === sk.field) {
|
|
180
|
+
skFound = true;
|
|
181
|
+
}
|
|
182
|
+
if (attribute === pk.field) {
|
|
183
|
+
skFound = true;
|
|
184
|
+
}
|
|
185
|
+
if (pkFound && skFound) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
ownsKeys(key = {}) {
|
|
112
193
|
let {pk, sk} = this.model.prefixes[TableIndex];
|
|
113
194
|
let hasSK = this.model.lookup.indexHasSortKeys[TableIndex];
|
|
114
195
|
let pkMatch = typeof key[pk.field] === "string" && key[pk.field].startsWith(pk.prefix);
|
|
196
|
+
let skMatch = pkMatch && !hasSK;
|
|
115
197
|
if (pkMatch && hasSK) {
|
|
116
|
-
|
|
198
|
+
skMatch = typeof key[sk.field] === "string" && key[sk.field].startsWith(sk.prefix);
|
|
117
199
|
}
|
|
118
|
-
|
|
200
|
+
|
|
201
|
+
return (pkMatch && skMatch &&
|
|
202
|
+
this._formatKeysToItem(TableIndex, key) !== null);
|
|
119
203
|
}
|
|
120
204
|
|
|
121
205
|
ownsCursor(cursor) {
|
|
122
206
|
if (typeof cursor === 'string') {
|
|
123
207
|
cursor = u.cursorFormatter.deserialize(cursor);
|
|
124
208
|
}
|
|
125
|
-
return this.
|
|
209
|
+
return this.ownsKeys(cursor);
|
|
126
210
|
}
|
|
127
211
|
|
|
128
212
|
serializeCursor(key) {
|
|
@@ -445,11 +529,54 @@ class Entity {
|
|
|
445
529
|
return { data: resultsAll, unprocessed: unprocessedAll };
|
|
446
530
|
}
|
|
447
531
|
|
|
532
|
+
async hydrate(index, keys = [], config) {
|
|
533
|
+
const items = [];
|
|
534
|
+
const validKeys = [];
|
|
535
|
+
for (let i = 0; i < keys.length; i++) {
|
|
536
|
+
const key = keys[i];
|
|
537
|
+
const item = this._formatKeysToItem(index, key);
|
|
538
|
+
if (item !== null) {
|
|
539
|
+
items.push(item);
|
|
540
|
+
validKeys.push(key);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const results = await this.get(items).go({
|
|
545
|
+
...config,
|
|
546
|
+
hydrate: false,
|
|
547
|
+
parse: undefined,
|
|
548
|
+
hydrator: undefined,
|
|
549
|
+
_isCollectionQuery: false,
|
|
550
|
+
preserveBatchOrder: true,
|
|
551
|
+
ignoreOwnership: config._providedIgnoreOwnership
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
const unprocessed = [];
|
|
555
|
+
const data = [];
|
|
556
|
+
|
|
557
|
+
for (let i = 0; i < results.data.length; i++) {
|
|
558
|
+
const key = validKeys[i];
|
|
559
|
+
const item = results.data[i];
|
|
560
|
+
if (!item) {
|
|
561
|
+
if (key) {
|
|
562
|
+
unprocessed.push(key);
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
data.push(item);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return {
|
|
570
|
+
unprocessed,
|
|
571
|
+
data,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
448
575
|
async executeQuery(method, parameters, config = {}) {
|
|
449
576
|
let results = config._isCollectionQuery
|
|
450
577
|
? {}
|
|
451
578
|
: [];
|
|
452
|
-
let ExclusiveStartKey = this._formatExclusiveStartKey(config);
|
|
579
|
+
let ExclusiveStartKey = this._formatExclusiveStartKey({config, indexName: parameters.IndexName });
|
|
453
580
|
if (ExclusiveStartKey === null) {
|
|
454
581
|
ExclusiveStartKey = undefined;
|
|
455
582
|
}
|
|
@@ -457,13 +584,20 @@ class Entity {
|
|
|
457
584
|
let max = this._normalizeLimitValue(config.limit);
|
|
458
585
|
let iterations = 0;
|
|
459
586
|
let count = 0;
|
|
587
|
+
let hydratedUnprocessed = [];
|
|
588
|
+
const shouldHydrate = config.hydrate && method === MethodTypes.query;
|
|
460
589
|
do {
|
|
461
590
|
let limit = max === undefined
|
|
462
591
|
? parameters.Limit
|
|
463
592
|
: max - count;
|
|
464
|
-
let response = await this._exec(method, {ExclusiveStartKey, ...parameters, Limit: limit}, config);
|
|
593
|
+
let response = await this._exec(method, { ExclusiveStartKey, ...parameters, Limit: limit }, config);
|
|
465
594
|
ExclusiveStartKey = response.LastEvaluatedKey;
|
|
466
|
-
response = this.formatResponse(response, parameters.IndexName,
|
|
595
|
+
response = this.formatResponse(response, parameters.IndexName, {
|
|
596
|
+
...config,
|
|
597
|
+
includeKeys: shouldHydrate || config.includeKeys,
|
|
598
|
+
ignoreOwnership: shouldHydrate || config.ignoreOwnership,
|
|
599
|
+
});
|
|
600
|
+
|
|
467
601
|
if (config.raw) {
|
|
468
602
|
return response;
|
|
469
603
|
} else if (config._isCollectionQuery) {
|
|
@@ -471,14 +605,26 @@ class Entity {
|
|
|
471
605
|
if (max) {
|
|
472
606
|
count += response.data[entity].length;
|
|
473
607
|
}
|
|
608
|
+
let items = response.data[entity];
|
|
609
|
+
if (shouldHydrate && items.length) {
|
|
610
|
+
const hydrated = await config.hydrator(entity, parameters.IndexName, items, config);
|
|
611
|
+
items = hydrated.data;
|
|
612
|
+
hydratedUnprocessed = hydratedUnprocessed.concat(hydrated.unprocessed);
|
|
613
|
+
}
|
|
474
614
|
results[entity] = results[entity] || [];
|
|
475
|
-
results[entity] = [...results[entity], ...
|
|
615
|
+
results[entity] = [...results[entity], ...items];
|
|
476
616
|
}
|
|
477
617
|
} else if (Array.isArray(response.data)) {
|
|
478
618
|
if (max) {
|
|
479
619
|
count += response.data.length;
|
|
480
620
|
}
|
|
481
|
-
|
|
621
|
+
let items = response.data;
|
|
622
|
+
if (shouldHydrate) {
|
|
623
|
+
const hydrated = await this.hydrate(parameters.IndexName, items, config);
|
|
624
|
+
items = hydrated.data;
|
|
625
|
+
hydratedUnprocessed = hydratedUnprocessed.concat(hydrated.unprocessed);
|
|
626
|
+
}
|
|
627
|
+
results = [...results, ...items];
|
|
482
628
|
} else {
|
|
483
629
|
return response;
|
|
484
630
|
}
|
|
@@ -490,6 +636,14 @@ class Entity {
|
|
|
490
636
|
);
|
|
491
637
|
|
|
492
638
|
const cursor = this._formatReturnPager(config, ExclusiveStartKey);
|
|
639
|
+
|
|
640
|
+
if (shouldHydrate) {
|
|
641
|
+
return {
|
|
642
|
+
cursor,
|
|
643
|
+
data: results,
|
|
644
|
+
unprocessed: hydratedUnprocessed,
|
|
645
|
+
};
|
|
646
|
+
}
|
|
493
647
|
return { data: results, cursor };
|
|
494
648
|
}
|
|
495
649
|
|
|
@@ -628,7 +782,11 @@ class Entity {
|
|
|
628
782
|
results = response;
|
|
629
783
|
} else {
|
|
630
784
|
if (response.Item) {
|
|
631
|
-
if (
|
|
785
|
+
if (
|
|
786
|
+
(config.ignoreOwnership && config.attributes && config.attributes.length > 0 && !this._attributesIncludeKeys(config.attributes)) ||
|
|
787
|
+
((config.ignoreOwnership || config.hydrate) && this.ownsKeys(response.Item)) ||
|
|
788
|
+
this.ownsItem(response.Item)
|
|
789
|
+
) {
|
|
632
790
|
results = this.model.schema.formatItemForRetrieval(response.Item, config);
|
|
633
791
|
if (Object.keys(results).length === 0) {
|
|
634
792
|
results = null;
|
|
@@ -639,7 +797,11 @@ class Entity {
|
|
|
639
797
|
} else if (response.Items) {
|
|
640
798
|
results = [];
|
|
641
799
|
for (let item of response.Items) {
|
|
642
|
-
if (
|
|
800
|
+
if (
|
|
801
|
+
(config.ignoreOwnership && config.attributes && config.attributes.length > 0 && !this._attributesIncludeKeys(config.attributes)) ||
|
|
802
|
+
((config.ignoreOwnership || config.hydrate) && this.ownsKeys(item)) ||
|
|
803
|
+
this.ownsItem(item)
|
|
804
|
+
) {
|
|
643
805
|
let record = this.model.schema.formatItemForRetrieval(item, config);
|
|
644
806
|
if (Object.keys(record).length > 0) {
|
|
645
807
|
results.push(record);
|
|
@@ -675,7 +837,6 @@ class Entity {
|
|
|
675
837
|
}
|
|
676
838
|
}
|
|
677
839
|
|
|
678
|
-
|
|
679
840
|
parse(item, options = {}) {
|
|
680
841
|
if (item === undefined || item === null) {
|
|
681
842
|
return null;
|
|
@@ -687,6 +848,216 @@ class Entity {
|
|
|
687
848
|
return this.formatResponse(item, TableIndex, config);
|
|
688
849
|
}
|
|
689
850
|
|
|
851
|
+
_fromCompositeToKeys({provided}, options = {}) {
|
|
852
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
853
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
let keys = {};
|
|
857
|
+
const secondaryIndexStrictMode = options.strict === 'all' || options.strict === 'pk' ? 'pk' : 'none';
|
|
858
|
+
for (const { index } of Object.values(this.model.indexes)) {
|
|
859
|
+
const indexKeys = this._fromCompositeToKeysByIndex({ indexName: index, provided }, {
|
|
860
|
+
strict: index === TableIndex ? options.strict : secondaryIndexStrictMode,
|
|
861
|
+
});
|
|
862
|
+
if (indexKeys) {
|
|
863
|
+
keys = {
|
|
864
|
+
...keys,
|
|
865
|
+
...indexKeys,
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
if (Object.keys(keys).length === 0) {
|
|
872
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
return keys;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
_fromCompositeToCursor({provided}, options = {}) {
|
|
879
|
+
const keys = this._fromCompositeToKeys({provided}, options);
|
|
880
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
881
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
882
|
+
}
|
|
883
|
+
return u.cursorFormatter.serialize(keys);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
_fromKeysToCursor({provided}, options = {}) {
|
|
887
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
888
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Invalid keys provided');
|
|
889
|
+
}
|
|
890
|
+
return u.cursorFormatter.serialize(provided);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
_fromKeysToComposite({provided}, options = {}) {
|
|
894
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
895
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys could not be used to form composite attributes');
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
let keys = {};
|
|
899
|
+
for (const { index } of Object.values(this.model.indexes)) {
|
|
900
|
+
const composite = this._fromKeysToCompositeByIndex({indexName: index, provided}, options);
|
|
901
|
+
if (composite) {
|
|
902
|
+
for (const attribute in composite) {
|
|
903
|
+
if (keys[attribute] === undefined) {
|
|
904
|
+
keys[attribute] = composite[attribute];
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
if (Object.keys(keys).length === 0) {
|
|
911
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys could not be used to form composite attributes');
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
return keys;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
_fromCursorToKeys({provided}, options = {}) {
|
|
918
|
+
if (typeof provided !== 'string') {
|
|
919
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return u.cursorFormatter.deserialize(provided);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
_fromCursorToComposite({provided}, options = {}) {
|
|
926
|
+
if (typeof provided !== 'string') {
|
|
927
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const keys = this._fromCursorToKeys({provided}, options);
|
|
931
|
+
if (!keys){
|
|
932
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return this._fromKeysToComposite({provided: keys}, options);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
_fromCompositeToCursorByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
939
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
940
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
const keys = this._formatSuppliedPager(indexName, provided, {
|
|
944
|
+
relaxedPk: false,
|
|
945
|
+
relaxedSk: false,
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
return this._fromKeysToCursorByIndex({indexName, provided: keys}, options);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
_fromCompositeToKeysByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
952
|
+
return this._formatSuppliedPager(indexName, provided, {
|
|
953
|
+
relaxedPk: options.strict !== 'pk' && options.strict !== 'all',
|
|
954
|
+
relaxedSk: options.strict !== 'all',
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
_fromCursorToKeysByIndex({ provided }, options = {}) {
|
|
959
|
+
if (typeof provided !== 'string' || provided.length < 1) {
|
|
960
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
return u.cursorFormatter.deserialize(provided);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
_fromKeysToCursorByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
967
|
+
const isValidTableIndex = this._verifyKeys({indexName: TableIndex, provided});
|
|
968
|
+
const isValidIndex = this._verifyKeys({indexName, provided});
|
|
969
|
+
if (!isValidTableIndex) {
|
|
970
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys did not include valid properties for the primary index');
|
|
971
|
+
} else if (!isValidIndex) {
|
|
972
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys did not include valid properties for the index "${indexName}"`);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
const keys = this._trimKeysToIndex({ indexName, provided });
|
|
976
|
+
|
|
977
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
978
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys not defined`);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
return u.cursorFormatter.serialize(provided);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
_fromKeysToCompositeByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
985
|
+
let allKeys = {};
|
|
986
|
+
|
|
987
|
+
const indexKeys = this._deconstructIndex({ index: indexName, keys: provided });
|
|
988
|
+
if (!indexKeys) {
|
|
989
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys did not include valid properties for the index "${indexName}"`);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
allKeys = {
|
|
993
|
+
...indexKeys,
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
let tableKeys;
|
|
997
|
+
if (indexName !== TableIndex) {
|
|
998
|
+
tableKeys = this._deconstructIndex({index: TableIndex, keys: provided});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
if (tableKeys === null) {
|
|
1002
|
+
return allKeys;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
allKeys = {
|
|
1006
|
+
...allKeys,
|
|
1007
|
+
...tableKeys,
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
if (Object.keys(allKeys).length === 0) {
|
|
1011
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys could not be used to form composite attributes');
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
return allKeys;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
_fromCursorToCompositeByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
1018
|
+
const keys = this._fromCursorToKeysByIndex({indexName, provided}, options);
|
|
1019
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1020
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
1021
|
+
}
|
|
1022
|
+
return this._fromKeysToCompositeByIndex({indexName, provided: keys}, options);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
_trimKeysToIndex({indexName = TableIndex, provided}) {
|
|
1026
|
+
if (!provided) {
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
const pkName = this.model.translations.keys[indexName].pk;
|
|
1031
|
+
const skName = this.model.translations.keys[indexName].sk;
|
|
1032
|
+
const tablePKName = this.model.translations.keys[TableIndex].pk;
|
|
1033
|
+
const tableSKName = this.model.translations.keys[TableIndex].sk;
|
|
1034
|
+
|
|
1035
|
+
const keys = {
|
|
1036
|
+
[pkName]: provided[pkName],
|
|
1037
|
+
[skName]: provided[skName],
|
|
1038
|
+
[tablePKName]: provided[tablePKName],
|
|
1039
|
+
[tableSKName]: provided[tableSKName],
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
return keys;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
_verifyKeys({indexName, provided}) {
|
|
1050
|
+
if (!provided) {
|
|
1051
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys not defined`);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
const pkName = this.model.translations.keys[indexName].pk;
|
|
1055
|
+
const skName = this.model.translations.keys[indexName].sk;
|
|
1056
|
+
|
|
1057
|
+
return provided[pkName] !== undefined &&
|
|
1058
|
+
(!skName || provided[skName] !== undefined);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
690
1061
|
_formatReturnPager(config, lastEvaluatedKey) {
|
|
691
1062
|
let page = lastEvaluatedKey || null;
|
|
692
1063
|
if (config.raw || config.pager === Pager.raw) {
|
|
@@ -695,12 +1066,22 @@ class Entity {
|
|
|
695
1066
|
return config.formatCursor.serialize(page) || null;
|
|
696
1067
|
}
|
|
697
1068
|
|
|
698
|
-
_formatExclusiveStartKey(config) {
|
|
1069
|
+
_formatExclusiveStartKey({config, indexName = TableIndex}) {
|
|
699
1070
|
let exclusiveStartKey = config.cursor;
|
|
700
1071
|
if (config.raw || config.pager === Pager.raw) {
|
|
701
|
-
return exclusiveStartKey || null;
|
|
1072
|
+
return this._trimKeysToIndex({ provided: exclusiveStartKey, indexName }) || null;
|
|
1073
|
+
}
|
|
1074
|
+
let keys;
|
|
1075
|
+
if (config.pager === Pager.item) {
|
|
1076
|
+
keys = this._fromCompositeToKeysByIndex({indexName, provided: exclusiveStartKey});
|
|
1077
|
+
} else {
|
|
1078
|
+
keys = config.formatCursor.deserialize(exclusiveStartKey);
|
|
1079
|
+
}
|
|
1080
|
+
if (!keys) {
|
|
1081
|
+
return null;
|
|
702
1082
|
}
|
|
703
|
-
|
|
1083
|
+
|
|
1084
|
+
return this._trimKeysToIndex({provided: keys, indexName}) || null;
|
|
704
1085
|
}
|
|
705
1086
|
|
|
706
1087
|
setClient(client) {
|
|
@@ -782,121 +1163,154 @@ class Entity {
|
|
|
782
1163
|
return value;
|
|
783
1164
|
}
|
|
784
1165
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
return null;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
let accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[index];
|
|
791
|
-
let {prefix, isCustom} = this.model.prefixes[index][keyType];
|
|
792
|
-
let {facets} = this.model.indexes[accessPattern][keyType];
|
|
1166
|
+
_createKeyDeconstructor(prefixes = {}, labels = [], attributes = {}) {
|
|
1167
|
+
let {prefix, isCustom, postfix} = prefixes;
|
|
793
1168
|
let names = [];
|
|
794
1169
|
let types = [];
|
|
795
|
-
let pattern = `^${this._regexpEscape(prefix)}`;
|
|
796
|
-
let labels = this.model.facets.labels[index][keyType] || [];
|
|
1170
|
+
let pattern = `^${this._regexpEscape(prefix || '')}`;
|
|
797
1171
|
for (let {name, label} of labels) {
|
|
798
|
-
let attr =
|
|
1172
|
+
let attr = attributes[name];
|
|
1173
|
+
if (isCustom && !name && label) {
|
|
1174
|
+
// this case is for when someone uses a direct attribute reference but with a postfix (zoinks ;P)
|
|
1175
|
+
pattern += `${this._regexpEscape(label)}`;
|
|
1176
|
+
} else if (isCustom) {
|
|
1177
|
+
pattern += `${this._regexpEscape(label === undefined ? "" : label)}(.+)`;
|
|
1178
|
+
} else {
|
|
1179
|
+
pattern += `#${this._regexpEscape(label === undefined ? name : label)}_(.+)`;
|
|
1180
|
+
}
|
|
1181
|
+
names.push(name);
|
|
799
1182
|
if (attr) {
|
|
800
|
-
if (isCustom) {
|
|
801
|
-
pattern += `${this._regexpEscape(label === undefined ? "" : label)}(.+)`;
|
|
802
|
-
} else {
|
|
803
|
-
pattern += `#${this._regexpEscape(label === undefined ? name : label)}_(.+)`;
|
|
804
|
-
}
|
|
805
|
-
names.push(name);
|
|
806
1183
|
types.push(attr.type);
|
|
807
1184
|
}
|
|
808
1185
|
}
|
|
1186
|
+
if (typeof postfix === 'string') {
|
|
1187
|
+
pattern += this._regexpEscape(postfix);
|
|
1188
|
+
}
|
|
809
1189
|
pattern += "$";
|
|
810
|
-
|
|
811
|
-
let
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
let value = match[i+1];
|
|
817
|
-
let type = types[i];
|
|
818
|
-
switch (type) {
|
|
819
|
-
case "number":
|
|
820
|
-
value = parseFloat(value);
|
|
821
|
-
break;
|
|
822
|
-
case "boolean":
|
|
823
|
-
value = value === "true";
|
|
824
|
-
break;
|
|
825
|
-
}
|
|
826
|
-
results[key] = value;
|
|
827
|
-
}
|
|
828
|
-
} else {
|
|
829
|
-
if (Object.keys(backupFacets || {}).length === 0) {
|
|
830
|
-
// this can occur when a scan is performed but returns no results given the current filters or record timing
|
|
831
|
-
return {};
|
|
1190
|
+
|
|
1191
|
+
let regex = new RegExp(pattern, "i");
|
|
1192
|
+
|
|
1193
|
+
return ({ key } = {}) => {
|
|
1194
|
+
if (!['string', 'number'].includes(typeof key)) {
|
|
1195
|
+
return null;
|
|
832
1196
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1197
|
+
key = `${key}`;
|
|
1198
|
+
let match = key.match(regex);
|
|
1199
|
+
let results = {};
|
|
1200
|
+
if (match) {
|
|
1201
|
+
for (let i = 0; i < names.length; i++) {
|
|
1202
|
+
let key = names[i];
|
|
1203
|
+
let value = match[i + 1];
|
|
1204
|
+
let type = types[i];
|
|
1205
|
+
switch (type) {
|
|
1206
|
+
case "number": {
|
|
1207
|
+
value = parseFloat(value);
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
case "boolean": {
|
|
1211
|
+
value = value === "true";
|
|
1212
|
+
break;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
if (key && value !== undefined) {
|
|
1216
|
+
results[key] = value;
|
|
1217
|
+
}
|
|
838
1218
|
}
|
|
1219
|
+
} else {
|
|
1220
|
+
results = null;
|
|
839
1221
|
}
|
|
1222
|
+
|
|
1223
|
+
return results;
|
|
840
1224
|
}
|
|
841
|
-
return results;
|
|
842
1225
|
}
|
|
843
1226
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1227
|
+
_deconstructIndex({index = TableIndex, keys = {}} = {}) {
|
|
1228
|
+
const hasIndex = !!this.model.translations.keys[index];
|
|
1229
|
+
if (!hasIndex) {
|
|
1230
|
+
return null;
|
|
1231
|
+
}
|
|
847
1232
|
let pkName = this.model.translations.keys[index].pk;
|
|
848
1233
|
let skName = this.model.translations.keys[index].sk;
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
if (
|
|
853
|
-
|
|
1234
|
+
const indexHasSortKey = this.model.lookup.indexHasSortKeys[index];
|
|
1235
|
+
const deconstructors = this.model.keys.deconstructors[index];
|
|
1236
|
+
const pk = keys[pkName];
|
|
1237
|
+
if (pk === undefined) {
|
|
1238
|
+
return null;
|
|
1239
|
+
}
|
|
1240
|
+
const pkComposites = deconstructors.pk({key: pk});
|
|
1241
|
+
if (pkComposites === null) {
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
let skComposites = {};
|
|
1245
|
+
if (indexHasSortKey) {
|
|
1246
|
+
const sk = keys[skName];
|
|
1247
|
+
if (!sk) {
|
|
1248
|
+
return null;
|
|
1249
|
+
}
|
|
1250
|
+
skComposites = deconstructors.sk({key: sk});
|
|
1251
|
+
if (skComposites === null) {
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
return {
|
|
1256
|
+
...pkComposites,
|
|
1257
|
+
...skComposites,
|
|
854
1258
|
}
|
|
855
|
-
return facets;
|
|
856
1259
|
}
|
|
857
1260
|
|
|
858
|
-
_formatKeysToItem(index = TableIndex,
|
|
859
|
-
if (
|
|
860
|
-
return
|
|
1261
|
+
_formatKeysToItem(index = TableIndex, keys) {
|
|
1262
|
+
if (keys === null || typeof keys !== "object" || Object.keys(keys).length === 0) {
|
|
1263
|
+
return keys;
|
|
861
1264
|
}
|
|
862
1265
|
let tableIndex = TableIndex;
|
|
863
|
-
let
|
|
1266
|
+
let indexParts = this._deconstructIndex({index, keys});
|
|
1267
|
+
if (indexParts === null) {
|
|
1268
|
+
return null;
|
|
1269
|
+
}
|
|
864
1270
|
// lastEvaluatedKeys from query calls include the index pk/sk as well as the table index's pk/sk
|
|
865
1271
|
if (index !== tableIndex) {
|
|
866
|
-
|
|
1272
|
+
const tableIndexParts = this._deconstructIndex({index: tableIndex, keys});
|
|
1273
|
+
if (tableIndexParts === null) {
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1276
|
+
indexParts = { ...indexParts, ...tableIndexParts };
|
|
867
1277
|
}
|
|
868
|
-
let
|
|
869
|
-
let
|
|
870
|
-
if (
|
|
1278
|
+
let noPartsFound = Object.keys(indexParts).length === 0;
|
|
1279
|
+
let partsAreIncomplete = this.model.facets.byIndex[tableIndex].all.find(facet => indexParts[facet.name] === undefined);
|
|
1280
|
+
if (noPartsFound || partsAreIncomplete) {
|
|
871
1281
|
// In this case no suitable record could be found be the deconstructed pager.
|
|
872
1282
|
// This can be valid in cases where a scan is performed but returns no results.
|
|
873
1283
|
return null;
|
|
874
1284
|
}
|
|
875
1285
|
|
|
876
|
-
return
|
|
1286
|
+
return indexParts;
|
|
877
1287
|
}
|
|
878
1288
|
|
|
879
|
-
_constructPagerIndex(index = TableIndex, item) {
|
|
880
|
-
let pkAttributes = this._expectFacets(item, this.model.facets.byIndex[index].pk);
|
|
881
|
-
let skAttributes = this._expectFacets(item, this.model.facets.byIndex[index].sk);
|
|
1289
|
+
_constructPagerIndex(index = TableIndex, item, options = {}) {
|
|
1290
|
+
let pkAttributes = options.relaxedPk ? item : this._expectFacets(item, this.model.facets.byIndex[index].pk);
|
|
1291
|
+
let skAttributes = options.relaxedSk ? item : this._expectFacets(item, this.model.facets.byIndex[index].sk);
|
|
1292
|
+
|
|
882
1293
|
let keys = this._makeIndexKeys({
|
|
883
1294
|
index,
|
|
884
1295
|
pkAttributes,
|
|
885
1296
|
skAttributes: [skAttributes],
|
|
886
1297
|
});
|
|
1298
|
+
|
|
887
1299
|
return this._makeParameterKey(index, keys.pk, ...keys.sk);
|
|
888
1300
|
}
|
|
889
1301
|
|
|
890
|
-
_formatSuppliedPager(index = TableIndex, item) {
|
|
1302
|
+
_formatSuppliedPager(index = TableIndex, item, options = {}) {
|
|
891
1303
|
if (typeof item !== "object" || Object.keys(item).length === 0) {
|
|
892
1304
|
return item;
|
|
893
1305
|
}
|
|
1306
|
+
|
|
894
1307
|
let tableIndex = TableIndex;
|
|
895
|
-
let pager = this._constructPagerIndex(index, item);
|
|
1308
|
+
let pager = this._constructPagerIndex(index, item, options);
|
|
896
1309
|
if (index !== tableIndex) {
|
|
897
|
-
pager = {...pager, ...this._constructPagerIndex(tableIndex, item)}
|
|
1310
|
+
pager = {...pager, ...this._constructPagerIndex(tableIndex, item, options)};
|
|
898
1311
|
}
|
|
899
|
-
|
|
1312
|
+
|
|
1313
|
+
return pager;
|
|
900
1314
|
}
|
|
901
1315
|
|
|
902
1316
|
_normalizeExecutionOptions({ provided = [], context = {} } = {}) {
|
|
@@ -916,6 +1330,7 @@ class Entity {
|
|
|
916
1330
|
cursor: null,
|
|
917
1331
|
data: 'attributes',
|
|
918
1332
|
ignoreOwnership: false,
|
|
1333
|
+
_providedIgnoreOwnership: false,
|
|
919
1334
|
_isPagination: false,
|
|
920
1335
|
_isCollectionQuery: false,
|
|
921
1336
|
pages: 1,
|
|
@@ -925,6 +1340,8 @@ class Entity {
|
|
|
925
1340
|
terminalOperation: undefined,
|
|
926
1341
|
formatCursor: u.cursorFormatter,
|
|
927
1342
|
order: undefined,
|
|
1343
|
+
hydrate: false,
|
|
1344
|
+
hydrator: (_entity, _indexName, items) => items,
|
|
928
1345
|
};
|
|
929
1346
|
|
|
930
1347
|
return provided.filter(Boolean).reduce((config, option) => {
|
|
@@ -1060,6 +1477,7 @@ class Entity {
|
|
|
1060
1477
|
|
|
1061
1478
|
if (option.ignoreOwnership) {
|
|
1062
1479
|
config.ignoreOwnership = option.ignoreOwnership;
|
|
1480
|
+
config._providedIgnoreOwnership = option.ignoreOwnership;
|
|
1063
1481
|
}
|
|
1064
1482
|
|
|
1065
1483
|
if (option.listeners) {
|
|
@@ -1076,6 +1494,15 @@ class Entity {
|
|
|
1076
1494
|
}
|
|
1077
1495
|
}
|
|
1078
1496
|
|
|
1497
|
+
if (option.hydrate) {
|
|
1498
|
+
config.hydrate = true;
|
|
1499
|
+
config.ignoreOwnership = true;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
if (validations.isFunction(option.hydrator)) {
|
|
1503
|
+
config.hydrator = option.hydrator;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1079
1506
|
config.page = Object.assign({}, config.page, option.page);
|
|
1080
1507
|
config.params = Object.assign({}, config.params, option.params);
|
|
1081
1508
|
return config;
|
|
@@ -1520,12 +1947,12 @@ class Entity {
|
|
|
1520
1947
|
};
|
|
1521
1948
|
}
|
|
1522
1949
|
|
|
1523
|
-
_makeUpsertParams({update, upsert} = {}, pk, sk) {
|
|
1950
|
+
_makeUpsertParams({ update, upsert } = {}, pk, sk) {
|
|
1524
1951
|
const { updatedKeys, setAttributes, indexKey } = this._getPutKeys(pk, sk && sk.facets, upsert.data);
|
|
1525
1952
|
const upsertAttributes = this.model.schema.translateToFields(setAttributes);
|
|
1526
1953
|
const keyNames = Object.keys(indexKey);
|
|
1527
|
-
update.set(this.identifiers.entity, this.getName());
|
|
1528
|
-
update.set(this.identifiers.version, this.getVersion());
|
|
1954
|
+
// update.set(this.identifiers.entity, this.getName());
|
|
1955
|
+
// update.set(this.identifiers.version, this.getVersion());
|
|
1529
1956
|
for (const field of [...Object.keys(upsertAttributes), ...Object.keys(updatedKeys)]) {
|
|
1530
1957
|
const value = u.getFirstDefined(upsertAttributes[field], updatedKeys[field]);
|
|
1531
1958
|
if (!keyNames.includes(field)) {
|
|
@@ -2238,7 +2665,11 @@ class Entity {
|
|
|
2238
2665
|
const subCollections = this.model.subCollections[collection];
|
|
2239
2666
|
const index = this.model.translations.collections.fromCollectionToIndex[collection];
|
|
2240
2667
|
const accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[index];
|
|
2668
|
+
const prefixes = this.model.prefixes[index];
|
|
2241
2669
|
const prefix = this._makeCollectionPrefix(subCollections);
|
|
2670
|
+
if (prefixes.sk && prefixes.sk.isCustom) {
|
|
2671
|
+
return '';
|
|
2672
|
+
}
|
|
2242
2673
|
return this._formatKeyCasing(accessPattern, prefix);
|
|
2243
2674
|
}
|
|
2244
2675
|
|
|
@@ -2293,7 +2724,8 @@ class Entity {
|
|
|
2293
2724
|
if (!prefixes) {
|
|
2294
2725
|
throw new Error(`Invalid index: ${index}`);
|
|
2295
2726
|
}
|
|
2296
|
-
let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk, {excludeLabelTail: true});
|
|
2727
|
+
// let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk, { excludeLabelTail: true });
|
|
2728
|
+
let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk);
|
|
2297
2729
|
let pk = partitionKey.key;
|
|
2298
2730
|
let sk = [];
|
|
2299
2731
|
let fulfilled = false;
|
|
@@ -2388,6 +2820,7 @@ class Entity {
|
|
|
2388
2820
|
key: supplied[facets[0]],
|
|
2389
2821
|
};
|
|
2390
2822
|
}
|
|
2823
|
+
|
|
2391
2824
|
let key = prefix;
|
|
2392
2825
|
let foundCount = 0;
|
|
2393
2826
|
for (let i = 0; i < labels.length; i++) {
|
|
@@ -2425,9 +2858,11 @@ class Entity {
|
|
|
2425
2858
|
key += postfix;
|
|
2426
2859
|
}
|
|
2427
2860
|
|
|
2861
|
+
const transformedKey = transform(u.formatKeyCasing(key, casing));
|
|
2862
|
+
|
|
2428
2863
|
return {
|
|
2429
2864
|
fulfilled,
|
|
2430
|
-
key:
|
|
2865
|
+
key: transformedKey,
|
|
2431
2866
|
};
|
|
2432
2867
|
}
|
|
2433
2868
|
|
|
@@ -3125,6 +3560,17 @@ class Entity {
|
|
|
3125
3560
|
indexes[indexAccessPattern.fromIndexToAccessPattern[indexName]].pk.labels = facets.labels[indexName].pk;
|
|
3126
3561
|
indexes[indexAccessPattern.fromIndexToAccessPattern[indexName]].sk.labels = facets.labels[indexName].sk;
|
|
3127
3562
|
}
|
|
3563
|
+
const deconstructors = {};
|
|
3564
|
+
for (const indexName of Object.keys(facets.labels)) {
|
|
3565
|
+
const keyTypes = prefixes[indexName] || {};
|
|
3566
|
+
deconstructors[indexName] = {};
|
|
3567
|
+
for (const keyType in keyTypes) {
|
|
3568
|
+
const prefixes = keyTypes[keyType];
|
|
3569
|
+
const labels = facets.labels[indexName][keyType] || [];
|
|
3570
|
+
const attributes = schema.attributes;
|
|
3571
|
+
deconstructors[indexName][keyType] = this._createKeyDeconstructor(prefixes, labels, attributes);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3128
3574
|
|
|
3129
3575
|
return {
|
|
3130
3576
|
name,
|
|
@@ -3150,6 +3596,9 @@ class Entity {
|
|
|
3150
3596
|
indexes: indexAccessPattern,
|
|
3151
3597
|
collections: indexCollection,
|
|
3152
3598
|
},
|
|
3599
|
+
keys: {
|
|
3600
|
+
deconstructors,
|
|
3601
|
+
},
|
|
3153
3602
|
original: model,
|
|
3154
3603
|
};
|
|
3155
3604
|
}
|
|
@@ -3173,20 +3622,31 @@ function getEntityIdentifiers(entities) {
|
|
|
3173
3622
|
return identifiers;
|
|
3174
3623
|
}
|
|
3175
3624
|
|
|
3176
|
-
function matchToEntityAlias({ paramItem, identifiers, record } = {}) {
|
|
3625
|
+
function matchToEntityAlias({ paramItem, identifiers, record, entities = {}, allowMatchOnKeys = false } = {}) {
|
|
3177
3626
|
let entity;
|
|
3178
|
-
let entityAlias;
|
|
3179
|
-
|
|
3180
3627
|
if (paramItem && v.isFunction(paramItem[TransactionCommitSymbol])) {
|
|
3181
3628
|
const committed = paramItem[TransactionCommitSymbol]();
|
|
3182
3629
|
entity = committed.entity;
|
|
3183
3630
|
}
|
|
3184
3631
|
|
|
3632
|
+
let entityAlias;
|
|
3185
3633
|
for (let {name, version, nameField, versionField, alias} of identifiers) {
|
|
3186
3634
|
if (entity && entity.model.entity === name && entity.model.version === version) {
|
|
3187
3635
|
entityAlias = alias;
|
|
3188
3636
|
break;
|
|
3189
|
-
} else if (record[nameField] !== undefined && record[
|
|
3637
|
+
} else if (record[nameField] !== undefined && record[versionField] !== undefined && record[nameField] === name && record[versionField] === version) {
|
|
3638
|
+
entityAlias = alias;
|
|
3639
|
+
break;
|
|
3640
|
+
// } else if (allowMatchOnKeys && entities[alias] && entities[alias].ownsKeys({keys: record})) {
|
|
3641
|
+
// if (entityAlias) {
|
|
3642
|
+
// if (alias !== entityAlias) {
|
|
3643
|
+
// throw new Error('Key ownership found to be not distinct');
|
|
3644
|
+
// }
|
|
3645
|
+
// } else {
|
|
3646
|
+
// entityAlias = alias;
|
|
3647
|
+
// }
|
|
3648
|
+
// }
|
|
3649
|
+
} else if (entities[alias] && entities[alias].ownsKeys(record)) {
|
|
3190
3650
|
entityAlias = alias;
|
|
3191
3651
|
break;
|
|
3192
3652
|
}
|