electrodb 2.5.1 → 2.6.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/index.d.ts +101 -11
- package/output +168 -0
- package/package.json +3 -3
- package/src/clauses.js +25 -4
- package/src/entity.js +561 -92
- 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,10 +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
|
: [];
|
|
579
|
+
// let ExclusiveStartKey = this._formatExclusiveStartKey({config, indexName: parameters.IndexName });
|
|
452
580
|
let ExclusiveStartKey = this._formatExclusiveStartKey(config);
|
|
453
581
|
if (ExclusiveStartKey === null) {
|
|
454
582
|
ExclusiveStartKey = undefined;
|
|
@@ -457,13 +585,20 @@ class Entity {
|
|
|
457
585
|
let max = this._normalizeLimitValue(config.limit);
|
|
458
586
|
let iterations = 0;
|
|
459
587
|
let count = 0;
|
|
588
|
+
let hydratedUnprocessed = [];
|
|
589
|
+
const shouldHydrate = config.hydrate && method === MethodTypes.query;
|
|
460
590
|
do {
|
|
461
591
|
let limit = max === undefined
|
|
462
592
|
? parameters.Limit
|
|
463
593
|
: max - count;
|
|
464
|
-
let response = await this._exec(method, {ExclusiveStartKey, ...parameters, Limit: limit}, config);
|
|
594
|
+
let response = await this._exec(method, { ExclusiveStartKey, ...parameters, Limit: limit }, config);
|
|
465
595
|
ExclusiveStartKey = response.LastEvaluatedKey;
|
|
466
|
-
response = this.formatResponse(response, parameters.IndexName,
|
|
596
|
+
response = this.formatResponse(response, parameters.IndexName, {
|
|
597
|
+
...config,
|
|
598
|
+
includeKeys: shouldHydrate || config.includeKeys,
|
|
599
|
+
ignoreOwnership: shouldHydrate || config.ignoreOwnership,
|
|
600
|
+
});
|
|
601
|
+
|
|
467
602
|
if (config.raw) {
|
|
468
603
|
return response;
|
|
469
604
|
} else if (config._isCollectionQuery) {
|
|
@@ -471,14 +606,26 @@ class Entity {
|
|
|
471
606
|
if (max) {
|
|
472
607
|
count += response.data[entity].length;
|
|
473
608
|
}
|
|
609
|
+
let items = response.data[entity];
|
|
610
|
+
if (shouldHydrate && items.length) {
|
|
611
|
+
const hydrated = await config.hydrator(entity, parameters.IndexName, items, config);
|
|
612
|
+
items = hydrated.data;
|
|
613
|
+
hydratedUnprocessed = hydratedUnprocessed.concat(hydrated.unprocessed);
|
|
614
|
+
}
|
|
474
615
|
results[entity] = results[entity] || [];
|
|
475
|
-
results[entity] = [...results[entity], ...
|
|
616
|
+
results[entity] = [...results[entity], ...items];
|
|
476
617
|
}
|
|
477
618
|
} else if (Array.isArray(response.data)) {
|
|
478
619
|
if (max) {
|
|
479
620
|
count += response.data.length;
|
|
480
621
|
}
|
|
481
|
-
|
|
622
|
+
let items = response.data;
|
|
623
|
+
if (shouldHydrate) {
|
|
624
|
+
const hydrated = await this.hydrate(parameters.IndexName, items, config);
|
|
625
|
+
items = hydrated.data;
|
|
626
|
+
hydratedUnprocessed = hydratedUnprocessed.concat(hydrated.unprocessed);
|
|
627
|
+
}
|
|
628
|
+
results = [...results, ...items];
|
|
482
629
|
} else {
|
|
483
630
|
return response;
|
|
484
631
|
}
|
|
@@ -490,6 +637,14 @@ class Entity {
|
|
|
490
637
|
);
|
|
491
638
|
|
|
492
639
|
const cursor = this._formatReturnPager(config, ExclusiveStartKey);
|
|
640
|
+
|
|
641
|
+
if (shouldHydrate) {
|
|
642
|
+
return {
|
|
643
|
+
cursor,
|
|
644
|
+
data: results,
|
|
645
|
+
unprocessed: hydratedUnprocessed,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
493
648
|
return { data: results, cursor };
|
|
494
649
|
}
|
|
495
650
|
|
|
@@ -628,7 +783,11 @@ class Entity {
|
|
|
628
783
|
results = response;
|
|
629
784
|
} else {
|
|
630
785
|
if (response.Item) {
|
|
631
|
-
if (
|
|
786
|
+
if (
|
|
787
|
+
(config.ignoreOwnership && config.attributes && config.attributes.length > 0 && !this._attributesIncludeKeys(config.attributes)) ||
|
|
788
|
+
((config.ignoreOwnership || config.hydrate) && this.ownsKeys(response.Item)) ||
|
|
789
|
+
this.ownsItem(response.Item)
|
|
790
|
+
) {
|
|
632
791
|
results = this.model.schema.formatItemForRetrieval(response.Item, config);
|
|
633
792
|
if (Object.keys(results).length === 0) {
|
|
634
793
|
results = null;
|
|
@@ -639,7 +798,11 @@ class Entity {
|
|
|
639
798
|
} else if (response.Items) {
|
|
640
799
|
results = [];
|
|
641
800
|
for (let item of response.Items) {
|
|
642
|
-
if (
|
|
801
|
+
if (
|
|
802
|
+
(config.ignoreOwnership && config.attributes && config.attributes.length > 0 && !this._attributesIncludeKeys(config.attributes)) ||
|
|
803
|
+
((config.ignoreOwnership || config.hydrate) && this.ownsKeys(item)) ||
|
|
804
|
+
this.ownsItem(item)
|
|
805
|
+
) {
|
|
643
806
|
let record = this.model.schema.formatItemForRetrieval(item, config);
|
|
644
807
|
if (Object.keys(record).length > 0) {
|
|
645
808
|
results.push(record);
|
|
@@ -675,7 +838,6 @@ class Entity {
|
|
|
675
838
|
}
|
|
676
839
|
}
|
|
677
840
|
|
|
678
|
-
|
|
679
841
|
parse(item, options = {}) {
|
|
680
842
|
if (item === undefined || item === null) {
|
|
681
843
|
return null;
|
|
@@ -687,6 +849,216 @@ class Entity {
|
|
|
687
849
|
return this.formatResponse(item, TableIndex, config);
|
|
688
850
|
}
|
|
689
851
|
|
|
852
|
+
_fromCompositeToKeys({provided}, options = {}) {
|
|
853
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
854
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
let keys = {};
|
|
858
|
+
const secondaryIndexStrictMode = options.strict === 'all' || options.strict === 'pk' ? 'pk' : 'none';
|
|
859
|
+
for (const { index } of Object.values(this.model.indexes)) {
|
|
860
|
+
const indexKeys = this._fromCompositeToKeysByIndex({ indexName: index, provided }, {
|
|
861
|
+
strict: index === TableIndex ? options.strict : secondaryIndexStrictMode,
|
|
862
|
+
});
|
|
863
|
+
if (indexKeys) {
|
|
864
|
+
keys = {
|
|
865
|
+
...keys,
|
|
866
|
+
...indexKeys,
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
if (Object.keys(keys).length === 0) {
|
|
873
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
return keys;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
_fromCompositeToCursor({provided}, options = {}) {
|
|
880
|
+
const keys = this._fromCompositeToKeys({provided}, options);
|
|
881
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
882
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
883
|
+
}
|
|
884
|
+
return u.cursorFormatter.serialize(keys);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
_fromKeysToCursor({provided}, options = {}) {
|
|
888
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
889
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Invalid keys provided');
|
|
890
|
+
}
|
|
891
|
+
return u.cursorFormatter.serialize(provided);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
_fromKeysToComposite({provided}, options = {}) {
|
|
895
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
896
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys could not be used to form composite attributes');
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
let keys = {};
|
|
900
|
+
for (const { index } of Object.values(this.model.indexes)) {
|
|
901
|
+
const composite = this._fromKeysToCompositeByIndex({indexName: index, provided}, options);
|
|
902
|
+
if (composite) {
|
|
903
|
+
for (const attribute in composite) {
|
|
904
|
+
if (keys[attribute] === undefined) {
|
|
905
|
+
keys[attribute] = composite[attribute];
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
if (Object.keys(keys).length === 0) {
|
|
912
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys could not be used to form composite attributes');
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
return keys;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
_fromCursorToKeys({provided}, options = {}) {
|
|
919
|
+
if (typeof provided !== 'string') {
|
|
920
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
return u.cursorFormatter.deserialize(provided);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
_fromCursorToComposite({provided}, options = {}) {
|
|
927
|
+
if (typeof provided !== 'string') {
|
|
928
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const keys = this._fromCursorToKeys({provided}, options);
|
|
932
|
+
if (!keys){
|
|
933
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return this._fromKeysToComposite({provided: keys}, options);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
_fromCompositeToCursorByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
940
|
+
if (!provided || Object.keys(provided).length === 0) {
|
|
941
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCompositeProvided, 'Invalid conversion composite provided');
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const keys = this._formatSuppliedPager(indexName, provided, {
|
|
945
|
+
relaxedPk: false,
|
|
946
|
+
relaxedSk: false,
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
return this._fromKeysToCursorByIndex({indexName, provided: keys}, options);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
_fromCompositeToKeysByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
953
|
+
return this._formatSuppliedPager(indexName, provided, {
|
|
954
|
+
relaxedPk: options.strict !== 'pk' && options.strict !== 'all',
|
|
955
|
+
relaxedSk: options.strict !== 'all',
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
_fromCursorToKeysByIndex({ provided }, options = {}) {
|
|
960
|
+
if (typeof provided !== 'string' || provided.length < 1) {
|
|
961
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
return u.cursorFormatter.deserialize(provided);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
_fromKeysToCursorByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
968
|
+
const isValidTableIndex = this._verifyKeys({indexName: TableIndex, provided});
|
|
969
|
+
const isValidIndex = this._verifyKeys({indexName, provided});
|
|
970
|
+
if (!isValidTableIndex) {
|
|
971
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys did not include valid properties for the primary index');
|
|
972
|
+
} else if (!isValidIndex) {
|
|
973
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys did not include valid properties for the index "${indexName}"`);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
const keys = this._trimKeysToIndex({ indexName, provided });
|
|
977
|
+
|
|
978
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
979
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys not defined`);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return u.cursorFormatter.serialize(provided);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
_fromKeysToCompositeByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
986
|
+
let allKeys = {};
|
|
987
|
+
|
|
988
|
+
const indexKeys = this._deconstructIndex({ index: indexName, keys: provided });
|
|
989
|
+
if (!indexKeys) {
|
|
990
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys did not include valid properties for the index "${indexName}"`);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
allKeys = {
|
|
994
|
+
...indexKeys,
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
let tableKeys;
|
|
998
|
+
if (indexName !== TableIndex) {
|
|
999
|
+
tableKeys = this._deconstructIndex({index: TableIndex, keys: provided});
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
if (tableKeys === null) {
|
|
1003
|
+
return allKeys;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
allKeys = {
|
|
1007
|
+
...allKeys,
|
|
1008
|
+
...tableKeys,
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
if (Object.keys(allKeys).length === 0) {
|
|
1012
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, 'Provided keys could not be used to form composite attributes');
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
return allKeys;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
_fromCursorToCompositeByIndex({indexName = TableIndex, provided}, options = {}) {
|
|
1019
|
+
const keys = this._fromCursorToKeysByIndex({indexName, provided}, options);
|
|
1020
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1021
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionCursorProvided, 'Invalid conversion cursor provided');
|
|
1022
|
+
}
|
|
1023
|
+
return this._fromKeysToCompositeByIndex({indexName, provided: keys}, options);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
_trimKeysToIndex({indexName = TableIndex, provided}) {
|
|
1027
|
+
if (!provided) {
|
|
1028
|
+
return null;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
const pkName = this.model.translations.keys[indexName].pk;
|
|
1032
|
+
const skName = this.model.translations.keys[indexName].sk;
|
|
1033
|
+
const tablePKName = this.model.translations.keys[TableIndex].pk;
|
|
1034
|
+
const tableSKName = this.model.translations.keys[TableIndex].sk;
|
|
1035
|
+
|
|
1036
|
+
const keys = {
|
|
1037
|
+
[pkName]: provided[pkName],
|
|
1038
|
+
[skName]: provided[skName],
|
|
1039
|
+
[tablePKName]: provided[tablePKName],
|
|
1040
|
+
[tableSKName]: provided[tableSKName],
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1044
|
+
return null;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
return keys;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
_verifyKeys({indexName, provided}) {
|
|
1051
|
+
if (!provided) {
|
|
1052
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidConversionKeysProvided, `Provided keys not defined`);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
const pkName = this.model.translations.keys[indexName].pk;
|
|
1056
|
+
const skName = this.model.translations.keys[indexName].sk;
|
|
1057
|
+
|
|
1058
|
+
return provided[pkName] !== undefined &&
|
|
1059
|
+
(!skName || provided[skName] !== undefined);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
690
1062
|
_formatReturnPager(config, lastEvaluatedKey) {
|
|
691
1063
|
let page = lastEvaluatedKey || null;
|
|
692
1064
|
if (config.raw || config.pager === Pager.raw) {
|
|
@@ -695,6 +1067,24 @@ class Entity {
|
|
|
695
1067
|
return config.formatCursor.serialize(page) || null;
|
|
696
1068
|
}
|
|
697
1069
|
|
|
1070
|
+
// _formatExclusiveStartKey({config, indexName = TableIndex}) {
|
|
1071
|
+
// let exclusiveStartKey = config.cursor;
|
|
1072
|
+
// if (config.raw || config.pager === Pager.raw) {
|
|
1073
|
+
// return this._trimKeysToIndex({ provided: exclusiveStartKey, indexName }) || null;
|
|
1074
|
+
// }
|
|
1075
|
+
// let keys;
|
|
1076
|
+
// if (config.pager === Pager.item) {
|
|
1077
|
+
// keys = this._fromCompositeToKeysByIndex({indexName, provided: exclusiveStartKey});
|
|
1078
|
+
// } else {
|
|
1079
|
+
// keys = config.formatCursor.deserialize(exclusiveStartKey);
|
|
1080
|
+
// }
|
|
1081
|
+
// if (!keys) {
|
|
1082
|
+
// return null;
|
|
1083
|
+
// }
|
|
1084
|
+
//
|
|
1085
|
+
// return this._trimKeysToIndex({provided: keys, indexName}) || null;
|
|
1086
|
+
// }
|
|
1087
|
+
|
|
698
1088
|
_formatExclusiveStartKey(config) {
|
|
699
1089
|
let exclusiveStartKey = config.cursor;
|
|
700
1090
|
if (config.raw || config.pager === Pager.raw) {
|
|
@@ -782,121 +1172,154 @@ class Entity {
|
|
|
782
1172
|
return value;
|
|
783
1173
|
}
|
|
784
1174
|
|
|
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];
|
|
1175
|
+
_createKeyDeconstructor(prefixes = {}, labels = [], attributes = {}) {
|
|
1176
|
+
let {prefix, isCustom, postfix} = prefixes;
|
|
793
1177
|
let names = [];
|
|
794
1178
|
let types = [];
|
|
795
|
-
let pattern = `^${this._regexpEscape(prefix)}`;
|
|
796
|
-
let labels = this.model.facets.labels[index][keyType] || [];
|
|
1179
|
+
let pattern = `^${this._regexpEscape(prefix || '')}`;
|
|
797
1180
|
for (let {name, label} of labels) {
|
|
798
|
-
let attr =
|
|
1181
|
+
let attr = attributes[name];
|
|
1182
|
+
if (isCustom && !name && label) {
|
|
1183
|
+
// this case is for when someone uses a direct attribute reference but with a postfix (zoinks ;P)
|
|
1184
|
+
pattern += `${this._regexpEscape(label)}`;
|
|
1185
|
+
} else if (isCustom) {
|
|
1186
|
+
pattern += `${this._regexpEscape(label === undefined ? "" : label)}(.+)`;
|
|
1187
|
+
} else {
|
|
1188
|
+
pattern += `#${this._regexpEscape(label === undefined ? name : label)}_(.+)`;
|
|
1189
|
+
}
|
|
1190
|
+
names.push(name);
|
|
799
1191
|
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
1192
|
types.push(attr.type);
|
|
807
1193
|
}
|
|
808
1194
|
}
|
|
1195
|
+
if (typeof postfix === 'string') {
|
|
1196
|
+
pattern += this._regexpEscape(postfix);
|
|
1197
|
+
}
|
|
809
1198
|
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 {};
|
|
1199
|
+
|
|
1200
|
+
let regex = new RegExp(pattern, "i");
|
|
1201
|
+
|
|
1202
|
+
return ({ key } = {}) => {
|
|
1203
|
+
if (!['string', 'number'].includes(typeof key)) {
|
|
1204
|
+
return null;
|
|
832
1205
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1206
|
+
key = `${key}`;
|
|
1207
|
+
let match = key.match(regex);
|
|
1208
|
+
let results = {};
|
|
1209
|
+
if (match) {
|
|
1210
|
+
for (let i = 0; i < names.length; i++) {
|
|
1211
|
+
let key = names[i];
|
|
1212
|
+
let value = match[i + 1];
|
|
1213
|
+
let type = types[i];
|
|
1214
|
+
switch (type) {
|
|
1215
|
+
case "number": {
|
|
1216
|
+
value = parseFloat(value);
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
case "boolean": {
|
|
1220
|
+
value = value === "true";
|
|
1221
|
+
break;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (key && value !== undefined) {
|
|
1225
|
+
results[key] = value;
|
|
1226
|
+
}
|
|
838
1227
|
}
|
|
1228
|
+
} else {
|
|
1229
|
+
results = null;
|
|
839
1230
|
}
|
|
1231
|
+
|
|
1232
|
+
return results;
|
|
840
1233
|
}
|
|
841
|
-
return results;
|
|
842
1234
|
}
|
|
843
1235
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1236
|
+
_deconstructIndex({index = TableIndex, keys = {}} = {}) {
|
|
1237
|
+
const hasIndex = !!this.model.translations.keys[index];
|
|
1238
|
+
if (!hasIndex) {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
847
1241
|
let pkName = this.model.translations.keys[index].pk;
|
|
848
1242
|
let skName = this.model.translations.keys[index].sk;
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
if (
|
|
853
|
-
|
|
1243
|
+
const indexHasSortKey = this.model.lookup.indexHasSortKeys[index];
|
|
1244
|
+
const deconstructors = this.model.keys.deconstructors[index];
|
|
1245
|
+
const pk = keys[pkName];
|
|
1246
|
+
if (pk === undefined) {
|
|
1247
|
+
return null;
|
|
1248
|
+
}
|
|
1249
|
+
const pkComposites = deconstructors.pk({key: pk});
|
|
1250
|
+
if (pkComposites === null) {
|
|
1251
|
+
return null;
|
|
1252
|
+
}
|
|
1253
|
+
let skComposites = {};
|
|
1254
|
+
if (indexHasSortKey) {
|
|
1255
|
+
const sk = keys[skName];
|
|
1256
|
+
if (!sk) {
|
|
1257
|
+
return null;
|
|
1258
|
+
}
|
|
1259
|
+
skComposites = deconstructors.sk({key: sk});
|
|
1260
|
+
if (skComposites === null) {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return {
|
|
1265
|
+
...pkComposites,
|
|
1266
|
+
...skComposites,
|
|
854
1267
|
}
|
|
855
|
-
return facets;
|
|
856
1268
|
}
|
|
857
1269
|
|
|
858
|
-
_formatKeysToItem(index = TableIndex,
|
|
859
|
-
if (
|
|
860
|
-
return
|
|
1270
|
+
_formatKeysToItem(index = TableIndex, keys) {
|
|
1271
|
+
if (keys === null || typeof keys !== "object" || Object.keys(keys).length === 0) {
|
|
1272
|
+
return keys;
|
|
861
1273
|
}
|
|
862
1274
|
let tableIndex = TableIndex;
|
|
863
|
-
let
|
|
1275
|
+
let indexParts = this._deconstructIndex({index, keys});
|
|
1276
|
+
if (indexParts === null) {
|
|
1277
|
+
return null;
|
|
1278
|
+
}
|
|
864
1279
|
// lastEvaluatedKeys from query calls include the index pk/sk as well as the table index's pk/sk
|
|
865
1280
|
if (index !== tableIndex) {
|
|
866
|
-
|
|
1281
|
+
const tableIndexParts = this._deconstructIndex({index: tableIndex, keys});
|
|
1282
|
+
if (tableIndexParts === null) {
|
|
1283
|
+
return null;
|
|
1284
|
+
}
|
|
1285
|
+
indexParts = { ...indexParts, ...tableIndexParts };
|
|
867
1286
|
}
|
|
868
|
-
let
|
|
869
|
-
let
|
|
870
|
-
if (
|
|
1287
|
+
let noPartsFound = Object.keys(indexParts).length === 0;
|
|
1288
|
+
let partsAreIncomplete = this.model.facets.byIndex[tableIndex].all.find(facet => indexParts[facet.name] === undefined);
|
|
1289
|
+
if (noPartsFound || partsAreIncomplete) {
|
|
871
1290
|
// In this case no suitable record could be found be the deconstructed pager.
|
|
872
1291
|
// This can be valid in cases where a scan is performed but returns no results.
|
|
873
1292
|
return null;
|
|
874
1293
|
}
|
|
875
1294
|
|
|
876
|
-
return
|
|
1295
|
+
return indexParts;
|
|
877
1296
|
}
|
|
878
1297
|
|
|
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);
|
|
1298
|
+
_constructPagerIndex(index = TableIndex, item, options = {}) {
|
|
1299
|
+
let pkAttributes = options.relaxedPk ? item : this._expectFacets(item, this.model.facets.byIndex[index].pk);
|
|
1300
|
+
let skAttributes = options.relaxedSk ? item : this._expectFacets(item, this.model.facets.byIndex[index].sk);
|
|
1301
|
+
|
|
882
1302
|
let keys = this._makeIndexKeys({
|
|
883
1303
|
index,
|
|
884
1304
|
pkAttributes,
|
|
885
1305
|
skAttributes: [skAttributes],
|
|
886
1306
|
});
|
|
1307
|
+
|
|
887
1308
|
return this._makeParameterKey(index, keys.pk, ...keys.sk);
|
|
888
1309
|
}
|
|
889
1310
|
|
|
890
|
-
_formatSuppliedPager(index = TableIndex, item) {
|
|
1311
|
+
_formatSuppliedPager(index = TableIndex, item, options = {}) {
|
|
891
1312
|
if (typeof item !== "object" || Object.keys(item).length === 0) {
|
|
892
1313
|
return item;
|
|
893
1314
|
}
|
|
1315
|
+
|
|
894
1316
|
let tableIndex = TableIndex;
|
|
895
|
-
let pager = this._constructPagerIndex(index, item);
|
|
1317
|
+
let pager = this._constructPagerIndex(index, item, options);
|
|
896
1318
|
if (index !== tableIndex) {
|
|
897
|
-
pager = {...pager, ...this._constructPagerIndex(tableIndex, item)}
|
|
1319
|
+
pager = {...pager, ...this._constructPagerIndex(tableIndex, item, options)};
|
|
898
1320
|
}
|
|
899
|
-
|
|
1321
|
+
|
|
1322
|
+
return pager;
|
|
900
1323
|
}
|
|
901
1324
|
|
|
902
1325
|
_normalizeExecutionOptions({ provided = [], context = {} } = {}) {
|
|
@@ -916,6 +1339,7 @@ class Entity {
|
|
|
916
1339
|
cursor: null,
|
|
917
1340
|
data: 'attributes',
|
|
918
1341
|
ignoreOwnership: false,
|
|
1342
|
+
_providedIgnoreOwnership: false,
|
|
919
1343
|
_isPagination: false,
|
|
920
1344
|
_isCollectionQuery: false,
|
|
921
1345
|
pages: 1,
|
|
@@ -925,6 +1349,8 @@ class Entity {
|
|
|
925
1349
|
terminalOperation: undefined,
|
|
926
1350
|
formatCursor: u.cursorFormatter,
|
|
927
1351
|
order: undefined,
|
|
1352
|
+
hydrate: false,
|
|
1353
|
+
hydrator: (_entity, _indexName, items) => items,
|
|
928
1354
|
};
|
|
929
1355
|
|
|
930
1356
|
return provided.filter(Boolean).reduce((config, option) => {
|
|
@@ -1060,6 +1486,7 @@ class Entity {
|
|
|
1060
1486
|
|
|
1061
1487
|
if (option.ignoreOwnership) {
|
|
1062
1488
|
config.ignoreOwnership = option.ignoreOwnership;
|
|
1489
|
+
config._providedIgnoreOwnership = option.ignoreOwnership;
|
|
1063
1490
|
}
|
|
1064
1491
|
|
|
1065
1492
|
if (option.listeners) {
|
|
@@ -1076,6 +1503,15 @@ class Entity {
|
|
|
1076
1503
|
}
|
|
1077
1504
|
}
|
|
1078
1505
|
|
|
1506
|
+
if (option.hydrate) {
|
|
1507
|
+
config.hydrate = true;
|
|
1508
|
+
config.ignoreOwnership = true;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
if (validations.isFunction(option.hydrator)) {
|
|
1512
|
+
config.hydrator = option.hydrator;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1079
1515
|
config.page = Object.assign({}, config.page, option.page);
|
|
1080
1516
|
config.params = Object.assign({}, config.params, option.params);
|
|
1081
1517
|
return config;
|
|
@@ -1520,12 +1956,12 @@ class Entity {
|
|
|
1520
1956
|
};
|
|
1521
1957
|
}
|
|
1522
1958
|
|
|
1523
|
-
_makeUpsertParams({update, upsert} = {}, pk, sk) {
|
|
1959
|
+
_makeUpsertParams({ update, upsert } = {}, pk, sk) {
|
|
1524
1960
|
const { updatedKeys, setAttributes, indexKey } = this._getPutKeys(pk, sk && sk.facets, upsert.data);
|
|
1525
1961
|
const upsertAttributes = this.model.schema.translateToFields(setAttributes);
|
|
1526
1962
|
const keyNames = Object.keys(indexKey);
|
|
1527
|
-
update.set(this.identifiers.entity, this.getName());
|
|
1528
|
-
update.set(this.identifiers.version, this.getVersion());
|
|
1963
|
+
// update.set(this.identifiers.entity, this.getName());
|
|
1964
|
+
// update.set(this.identifiers.version, this.getVersion());
|
|
1529
1965
|
for (const field of [...Object.keys(upsertAttributes), ...Object.keys(updatedKeys)]) {
|
|
1530
1966
|
const value = u.getFirstDefined(upsertAttributes[field], updatedKeys[field]);
|
|
1531
1967
|
if (!keyNames.includes(field)) {
|
|
@@ -2238,7 +2674,11 @@ class Entity {
|
|
|
2238
2674
|
const subCollections = this.model.subCollections[collection];
|
|
2239
2675
|
const index = this.model.translations.collections.fromCollectionToIndex[collection];
|
|
2240
2676
|
const accessPattern = this.model.translations.indexes.fromIndexToAccessPattern[index];
|
|
2677
|
+
const prefixes = this.model.prefixes[index];
|
|
2241
2678
|
const prefix = this._makeCollectionPrefix(subCollections);
|
|
2679
|
+
if (prefixes.sk && prefixes.sk.isCustom) {
|
|
2680
|
+
return '';
|
|
2681
|
+
}
|
|
2242
2682
|
return this._formatKeyCasing(accessPattern, prefix);
|
|
2243
2683
|
}
|
|
2244
2684
|
|
|
@@ -2293,7 +2733,8 @@ class Entity {
|
|
|
2293
2733
|
if (!prefixes) {
|
|
2294
2734
|
throw new Error(`Invalid index: ${index}`);
|
|
2295
2735
|
}
|
|
2296
|
-
let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk, {excludeLabelTail: true});
|
|
2736
|
+
// let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk, { excludeLabelTail: true });
|
|
2737
|
+
let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk);
|
|
2297
2738
|
let pk = partitionKey.key;
|
|
2298
2739
|
let sk = [];
|
|
2299
2740
|
let fulfilled = false;
|
|
@@ -2388,6 +2829,7 @@ class Entity {
|
|
|
2388
2829
|
key: supplied[facets[0]],
|
|
2389
2830
|
};
|
|
2390
2831
|
}
|
|
2832
|
+
|
|
2391
2833
|
let key = prefix;
|
|
2392
2834
|
let foundCount = 0;
|
|
2393
2835
|
for (let i = 0; i < labels.length; i++) {
|
|
@@ -2425,9 +2867,11 @@ class Entity {
|
|
|
2425
2867
|
key += postfix;
|
|
2426
2868
|
}
|
|
2427
2869
|
|
|
2870
|
+
const transformedKey = transform(u.formatKeyCasing(key, casing));
|
|
2871
|
+
|
|
2428
2872
|
return {
|
|
2429
2873
|
fulfilled,
|
|
2430
|
-
key:
|
|
2874
|
+
key: transformedKey,
|
|
2431
2875
|
};
|
|
2432
2876
|
}
|
|
2433
2877
|
|
|
@@ -3125,6 +3569,17 @@ class Entity {
|
|
|
3125
3569
|
indexes[indexAccessPattern.fromIndexToAccessPattern[indexName]].pk.labels = facets.labels[indexName].pk;
|
|
3126
3570
|
indexes[indexAccessPattern.fromIndexToAccessPattern[indexName]].sk.labels = facets.labels[indexName].sk;
|
|
3127
3571
|
}
|
|
3572
|
+
const deconstructors = {};
|
|
3573
|
+
for (const indexName of Object.keys(facets.labels)) {
|
|
3574
|
+
const keyTypes = prefixes[indexName] || {};
|
|
3575
|
+
deconstructors[indexName] = {};
|
|
3576
|
+
for (const keyType in keyTypes) {
|
|
3577
|
+
const prefixes = keyTypes[keyType];
|
|
3578
|
+
const labels = facets.labels[indexName][keyType] || [];
|
|
3579
|
+
const attributes = schema.attributes;
|
|
3580
|
+
deconstructors[indexName][keyType] = this._createKeyDeconstructor(prefixes, labels, attributes);
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3128
3583
|
|
|
3129
3584
|
return {
|
|
3130
3585
|
name,
|
|
@@ -3150,6 +3605,9 @@ class Entity {
|
|
|
3150
3605
|
indexes: indexAccessPattern,
|
|
3151
3606
|
collections: indexCollection,
|
|
3152
3607
|
},
|
|
3608
|
+
keys: {
|
|
3609
|
+
deconstructors,
|
|
3610
|
+
},
|
|
3153
3611
|
original: model,
|
|
3154
3612
|
};
|
|
3155
3613
|
}
|
|
@@ -3173,20 +3631,31 @@ function getEntityIdentifiers(entities) {
|
|
|
3173
3631
|
return identifiers;
|
|
3174
3632
|
}
|
|
3175
3633
|
|
|
3176
|
-
function matchToEntityAlias({ paramItem, identifiers, record } = {}) {
|
|
3634
|
+
function matchToEntityAlias({ paramItem, identifiers, record, entities = {}, allowMatchOnKeys = false } = {}) {
|
|
3177
3635
|
let entity;
|
|
3178
|
-
let entityAlias;
|
|
3179
|
-
|
|
3180
3636
|
if (paramItem && v.isFunction(paramItem[TransactionCommitSymbol])) {
|
|
3181
3637
|
const committed = paramItem[TransactionCommitSymbol]();
|
|
3182
3638
|
entity = committed.entity;
|
|
3183
3639
|
}
|
|
3184
3640
|
|
|
3641
|
+
let entityAlias;
|
|
3185
3642
|
for (let {name, version, nameField, versionField, alias} of identifiers) {
|
|
3186
3643
|
if (entity && entity.model.entity === name && entity.model.version === version) {
|
|
3187
3644
|
entityAlias = alias;
|
|
3188
3645
|
break;
|
|
3189
|
-
} else if (record[nameField] !== undefined && record[
|
|
3646
|
+
} else if (record[nameField] !== undefined && record[versionField] !== undefined && record[nameField] === name && record[versionField] === version) {
|
|
3647
|
+
entityAlias = alias;
|
|
3648
|
+
break;
|
|
3649
|
+
// } else if (allowMatchOnKeys && entities[alias] && entities[alias].ownsKeys({keys: record})) {
|
|
3650
|
+
// if (entityAlias) {
|
|
3651
|
+
// if (alias !== entityAlias) {
|
|
3652
|
+
// throw new Error('Key ownership found to be not distinct');
|
|
3653
|
+
// }
|
|
3654
|
+
// } else {
|
|
3655
|
+
// entityAlias = alias;
|
|
3656
|
+
// }
|
|
3657
|
+
// }
|
|
3658
|
+
} else if (entities[alias] && entities[alias].ownsKeys(record)) {
|
|
3190
3659
|
entityAlias = alias;
|
|
3191
3660
|
break;
|
|
3192
3661
|
}
|