electrodb 2.4.1 → 2.5.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/src/client.js CHANGED
@@ -1,12 +1,13 @@
1
1
  const lib = require('@aws-sdk/lib-dynamodb')
2
+ const util = require('@aws-sdk/lib-dynamodb/dist-cjs/commands/utils')
2
3
  const { isFunction } = require('./validations');
3
4
  const { ElectroError, ErrorCodes } = require('./errors');
4
-
5
5
  const DocumentClientVersions = {
6
6
  v2: 'v2',
7
7
  v3: 'v3',
8
8
  electro: 'electro',
9
9
  };
10
+ const unmarshallOutput = util.unmarshallOutput || ((val) => val);
10
11
 
11
12
  const v3Methods = ['send'];
12
13
  const v2Methods = ['get', 'put', 'update', 'delete', 'batchWrite', 'batchGet', 'scan', 'query', 'createSet', 'transactWrite', 'transactGet'];
@@ -15,6 +16,99 @@ const supportedClientVersions = {
15
16
  [DocumentClientVersions.v3]: v3Methods,
16
17
  }
17
18
 
19
+ class DocumentClientV2Wrapper {
20
+ static init(client) {
21
+ return new DocumentClientV2Wrapper(client, lib);
22
+ }
23
+
24
+ constructor(client, lib) {
25
+ this.client = client;
26
+ this.lib = lib;
27
+ this.__v = 'v2';
28
+ }
29
+
30
+ get(params) {
31
+ return this.client.get(params);
32
+ }
33
+
34
+ put(params) {
35
+ return this.client.put(params);
36
+ }
37
+
38
+ update(params) {
39
+ return this.client.update(params);
40
+ }
41
+
42
+ delete(params) {
43
+ return this.client.delete(params);
44
+ }
45
+
46
+ batchWrite(params) {
47
+ return this.client.batchWrite(params);
48
+ }
49
+
50
+ batchGet(params) {
51
+ return this.client.batchGet(params);
52
+ }
53
+
54
+ scan(params) {
55
+ return this.client.scan(params);
56
+ }
57
+
58
+ query(params) {
59
+ return this.client.query(params);
60
+ }
61
+
62
+ _transact(transactionRequest) {
63
+ let cancellationReasons;
64
+ transactionRequest.on('extractError', (response) => {
65
+ try {
66
+ cancellationReasons = JSON.parse(response.httpResponse.body.toString()).CancellationReasons;
67
+ } catch (err) {}
68
+ });
69
+
70
+ return {
71
+ async promise() {
72
+ return transactionRequest.promise()
73
+ .catch((err) => {
74
+ if (err) {
75
+ if (Array.isArray(cancellationReasons)) {
76
+ return {
77
+ canceled: cancellationReasons
78
+ .map(reason => {
79
+ if (reason.Item) {
80
+ return unmarshallOutput(reason, [{ key: "Item" }]);
81
+ }
82
+ return reason;
83
+ })
84
+ };
85
+ }
86
+ throw err;
87
+ }
88
+ });
89
+ }
90
+ }
91
+ }
92
+
93
+ transactWrite(params) {
94
+ const transactionRequest = this.client.transactWrite(params);
95
+ return this._transact(transactionRequest);
96
+ }
97
+
98
+ transactGet(params) {
99
+ const transactionRequest = this.client.transactGet(params);
100
+ return this._transact(transactionRequest);
101
+ }
102
+
103
+ createSet(value, ...rest) {
104
+ if (Array.isArray(value)) {
105
+ return this.client.createSet(value, ...rest);
106
+ } else {
107
+ return this.client.createSet([value], ...rest);
108
+ }
109
+ }
110
+ }
111
+
18
112
  class DocumentClientV3Wrapper {
19
113
  static init(client) {
20
114
  return new DocumentClientV3Wrapper(client, lib);
@@ -23,6 +117,7 @@ class DocumentClientV3Wrapper {
23
117
  constructor(client, lib) {
24
118
  this.client = client;
25
119
  this.lib = lib;
120
+ this.__v = 'v3';
26
121
  }
27
122
 
28
123
  promiseWrap(fn) {
@@ -81,16 +176,49 @@ class DocumentClientV3Wrapper {
81
176
  return this.client.send(command);
82
177
  });
83
178
  }
179
+
84
180
  transactWrite(params) {
85
181
  return this.promiseWrap(async () => {
86
182
  const command = new this.lib.TransactWriteCommand(params);
87
- return this.client.send(command);
183
+ return this.client.send(command)
184
+ .then((result) => {
185
+ return result;
186
+ })
187
+ .catch(err => {
188
+ if (err.CancellationReasons) {
189
+ return {
190
+ canceled: err.CancellationReasons.map(reason => {
191
+ if (reason.Item) {
192
+ return unmarshallOutput(reason, [{ key: "Item" }]);
193
+ }
194
+ return reason;
195
+ })
196
+ }
197
+ }
198
+ throw err;
199
+ });
88
200
  });
89
201
  }
90
202
  transactGet(params) {
91
203
  return this.promiseWrap(async () => {
92
204
  const command = new this.lib.TransactGetCommand(params);
93
- return this.client.send(command);
205
+ return this.client.send(command)
206
+ .then((result) => {
207
+ return result;
208
+ })
209
+ .catch(err => {
210
+ if (err.CancellationReasons) {
211
+ return {
212
+ canceled: err.CancellationReasons.map(reason => {
213
+ if (reason.Item) {
214
+ return unmarshallOutput(reason, [{ key: "Item" }]);
215
+ }
216
+ return reason;
217
+ })
218
+ }
219
+ }
220
+ throw err;
221
+ });
94
222
  });
95
223
  }
96
224
  createSet(value) {
@@ -103,7 +231,9 @@ class DocumentClientV3Wrapper {
103
231
  }
104
232
 
105
233
  function identifyClientVersion(client = {}) {
106
- if (client instanceof DocumentClientV3Wrapper) return DocumentClientVersions.electro;
234
+ if (client instanceof DocumentClientV3Wrapper || client instanceof DocumentClientV2Wrapper) {
235
+ return DocumentClientVersions.electro;
236
+ }
107
237
  for (const [version, methods] of Object.entries(supportedClientVersions)) {
108
238
  const hasMethods = methods.every(method => {
109
239
  return method in client && isFunction(client[method]);
@@ -121,6 +251,7 @@ function normalizeClient(client) {
121
251
  case DocumentClientVersions.v3:
122
252
  return DocumentClientV3Wrapper.init(client);
123
253
  case DocumentClientVersions.v2:
254
+ return DocumentClientV2Wrapper.init(client);
124
255
  case DocumentClientVersions.electro:
125
256
  return client;
126
257
  default:
@@ -136,6 +267,7 @@ function normalizeConfig(config = {}) {
136
267
  }
137
268
 
138
269
  module.exports = {
270
+ util,
139
271
  v2Methods,
140
272
  v3Methods,
141
273
  normalizeClient,
@@ -144,4 +276,5 @@ module.exports = {
144
276
  DocumentClientVersions,
145
277
  supportedClientVersions,
146
278
  DocumentClientV3Wrapper,
279
+ DocumentClientV2Wrapper,
147
280
  };
package/src/entity.js CHANGED
@@ -24,6 +24,7 @@ const { AllPages,
24
24
  IndexTypes,
25
25
  PartialComparisons,
26
26
  MethodTypeTranslation,
27
+ TransactionCommitSymbol,
27
28
  } = require("./types");
28
29
  const { FilterFactory } = require("./filters");
29
30
  const { FilterOperations } = require("./operations");
@@ -35,6 +36,7 @@ const c = require('./client');
35
36
  const u = require("./util");
36
37
  const e = require("./errors");
37
38
  const { validate } = require("jsonschema");
39
+ const v = require('./validations');
38
40
 
39
41
  class Entity {
40
42
  constructor(model, config = {}) {
@@ -229,6 +231,10 @@ class Entity {
229
231
  return validations.model(model);
230
232
  }
231
233
 
234
+ check(compositeAttributes = {}) {
235
+ return this._makeChain(TableIndex, this._clausesWithFilters, clauses.index).check(compositeAttributes);
236
+ }
237
+
232
238
  get(facets = {}) {
233
239
  let index = TableIndex;
234
240
  if (Array.isArray(facets)) {
@@ -285,6 +291,16 @@ class Entity {
285
291
  return this._makeChain(index, this._clausesWithFilters, clauses.index, options).remove(facets);
286
292
  }
287
293
 
294
+ async transactWrite(parameters, config) {
295
+ let response = await this._exec(MethodTypes.transactWrite, parameters, config);
296
+ return response;
297
+ }
298
+
299
+ async transactGet(parameters, config) {
300
+ let response = await this._exec(MethodTypes.transactGet, parameters, config);
301
+ return response;
302
+ }
303
+
288
304
  async go(method, parameters = {}, config = {}) {
289
305
  let stackTrace;
290
306
  if (!config.originalErr) {
@@ -486,7 +502,7 @@ class Entity {
486
502
  case FormatToReturnValues.all_old:
487
503
  case FormatToReturnValues.updated_new:
488
504
  case FormatToReturnValues.updated_old:
489
- return this.formatResponse(response, config);
505
+ return this.formatResponse(response, TableIndex, config);
490
506
  case FormatToReturnValues.default:
491
507
  default:
492
508
  return this._formatDefaultResponse(method, parameters.IndexName, parameters, config, response);
@@ -583,7 +599,7 @@ class Entity {
583
599
  for (let i = 0; i < responses.length; i++) {
584
600
  const item = responses[i];
585
601
  const slot = orderMaintainer.getOrder(item);
586
- const formatted = this.formatResponse({Item: item}, index, config);
602
+ const formatted = this.formatResponse({ Item: item }, index, config);
587
603
  if (slot !== -1) {
588
604
  resultsAll[slot] = formatted.data;
589
605
  } else {
@@ -617,6 +633,8 @@ class Entity {
617
633
  if (Object.keys(results).length === 0) {
618
634
  results = null;
619
635
  }
636
+ } else if (!config._objectOnEmpty) {
637
+ results = null;
620
638
  }
621
639
  } else if (response.Items) {
622
640
  results = [];
@@ -881,7 +899,7 @@ class Entity {
881
899
  return pager
882
900
  }
883
901
 
884
- _applyParameterOptions(params, ...options) {
902
+ _normalizeExecutionOptions({ provided = [], context = {} } = {}) {
885
903
  let config = {
886
904
  includeKeys: false,
887
905
  originalErr: false,
@@ -909,7 +927,7 @@ class Entity {
909
927
  order: undefined,
910
928
  };
911
929
 
912
- config = options.reduce((config, option) => {
930
+ return provided.filter(Boolean).reduce((config, option) => {
913
931
  if (typeof option.order === 'string') {
914
932
  switch (option.order.toLowerCase()) {
915
933
  case 'asc':
@@ -929,11 +947,15 @@ class Entity {
929
947
  throw new e.ElectroError(e.ErrorCodes.InvalidOptions, `Invalid value for query option "format" provided: "${option.format}". Allowed values include ${u.commaSeparatedString(Object.keys(ReturnValues))}.`);
930
948
  }
931
949
  config.response = format;
932
- config.params.ReturnValues = FormatToReturnValues[format];
950
+ if (context.operation === MethodTypes.transactWrite) {
951
+ config.params.ReturnValuesOnConditionCheckFailure = FormatToReturnValues[format];
952
+ } else {
953
+ config.params.ReturnValues = FormatToReturnValues[format];
954
+ }
933
955
  }
934
956
 
935
957
  if (option.formatCursor) {
936
- const isValid = ['serialize', 'deserialize'].every(method =>
958
+ const isValid = ['serialize', 'deserialize'].every(method =>
937
959
  method in option.formatCursor &&
938
960
  validations.isFunction(option.formatCursor[method])
939
961
  );
@@ -1058,16 +1080,18 @@ class Entity {
1058
1080
  config.params = Object.assign({}, config.params, option.params);
1059
1081
  return config;
1060
1082
  }, config);
1083
+ }
1061
1084
 
1085
+ _applyParameterOptions({ params = {}, options = {} } = {}) {
1062
1086
  let parameters = Object.assign({}, params);
1063
1087
 
1064
- for (let customParameter of Object.keys(config.params)) {
1065
- if (config.params[customParameter] !== undefined) {
1066
- parameters[customParameter] = config.params[customParameter];
1088
+ for (let customParameter of Object.keys(options.params || {})) {
1089
+ if (options.params[customParameter] !== undefined) {
1090
+ parameters[customParameter] = options.params[customParameter];
1067
1091
  }
1068
1092
  }
1069
1093
 
1070
- return { parameters, config };
1094
+ return parameters;
1071
1095
  }
1072
1096
 
1073
1097
  addListeners(logger) {
@@ -1117,10 +1141,11 @@ class Entity {
1117
1141
  }
1118
1142
  /* istanbul ignore next */
1119
1143
  _params(state, config = {}) {
1120
- let { keys = {}, method = "", put = {}, update = {}, filter = {}, options = {}, updateProxy, upsert } = state.query;
1144
+ const { keys = {}, method = "", put = {}, update = {}, filter = {}, upsert } = state.query;
1121
1145
  let consolidatedQueryFacets = this._consolidateQueryFacets(keys.sk);
1122
1146
  let params = {};
1123
1147
  switch (method) {
1148
+ case MethodTypes.check:
1124
1149
  case MethodTypes.get:
1125
1150
  case MethodTypes.delete:
1126
1151
  case MethodTypes.remove:
@@ -1148,8 +1173,13 @@ class Entity {
1148
1173
  default:
1149
1174
  throw new Error(`Invalid method: ${method}`);
1150
1175
  }
1151
- let applied = this._applyParameterOptions(params, options, config);
1152
- return this._applyParameterExpressions(method, applied.parameters, applied.config, filter);
1176
+
1177
+ let appliedParameters = this._applyParameterOptions({
1178
+ params,
1179
+ options: config,
1180
+ });
1181
+
1182
+ return this._applyParameterExpressions(method, appliedParameters, config, filter);
1153
1183
  }
1154
1184
 
1155
1185
  _applyParameterExpressions(method, parameters, config, filter) {
@@ -1251,12 +1281,19 @@ class Entity {
1251
1281
  _batchGetParams(state, config = {}) {
1252
1282
  let table = config.table || this.getTableName();
1253
1283
  let userDefinedParams = config.params || {};
1284
+
1285
+ // TableName is added when the config provided includes "table"
1286
+ // this is evaluated upstream so we remove it to avoid forming
1287
+ // bad syntax. Code should reconsider how this is applied to
1288
+ // make this cleaner :(
1289
+ delete userDefinedParams.TableName;
1290
+
1254
1291
  let records = [];
1255
1292
  for (let itemState of state.subStates) {
1256
1293
  let method = itemState.query.method;
1257
1294
  let params = this._params(itemState, config);
1258
1295
  if (method === MethodTypes.get) {
1259
- let {Key} = params;
1296
+ let { Key } = params;
1260
1297
  records.push(Key);
1261
1298
  }
1262
1299
  }
@@ -1356,11 +1393,7 @@ class Entity {
1356
1393
  ),
1357
1394
  FilterExpression: `begins_with(#${pkField}, :${pkField})`,
1358
1395
  };
1359
- params.ExpressionAttributeNames["#" + this.identifiers.entity] = this.identifiers.entity;
1360
- params.ExpressionAttributeNames["#" + this.identifiers.version] = this.identifiers.version;
1361
- params.ExpressionAttributeValues[":" + this.identifiers.entity] = this.getName();
1362
- params.ExpressionAttributeValues[":" + this.identifiers.version] = this.getVersion();
1363
- params.FilterExpression = `${params.FilterExpression} AND #${this.identifiers.entity} = :${this.identifiers.entity} AND #${this.identifiers.version} = :${this.identifiers.version}`;
1396
+
1364
1397
  if (hasSortKey) {
1365
1398
  let skField = this.model.indexes[accessPattern].sk.field;
1366
1399
  params.FilterExpression = `${params.FilterExpression} AND begins_with(#${skField}, :${skField})`;
@@ -1380,7 +1413,7 @@ class Entity {
1380
1413
  });
1381
1414
  let Key = this._makeParameterKey(index, keys.pk, ...keys.sk);
1382
1415
  let TableName = this.getTableName();
1383
- return {Key, TableName};
1416
+ return { Key, TableName };
1384
1417
  }
1385
1418
 
1386
1419
  _removeAttributes(item, keys) {
@@ -1691,8 +1724,16 @@ class Entity {
1691
1724
  default:
1692
1725
  throw new Error(`Invalid query type: ${state.query.type}`);
1693
1726
  }
1694
- let applied = this._applyParameterOptions(parameters, state.query.options, options);
1695
- return this._applyProjectionExpressions(applied);
1727
+
1728
+ const appliedParameters = this._applyParameterOptions({
1729
+ params: parameters,
1730
+ options,
1731
+ });
1732
+
1733
+ return this._applyProjectionExpressions({
1734
+ parameters: appliedParameters,
1735
+ config: options,
1736
+ });
1696
1737
  }
1697
1738
 
1698
1739
  _makeBetweenQueryParams(index, filter, pk, ...sk) {
@@ -2293,7 +2334,6 @@ class Entity {
2293
2334
  indexType,
2294
2335
  isCollection = false,
2295
2336
  }) {
2296
-
2297
2337
  this._validateIndex(index);
2298
2338
  const excludePostfix = indexType === IndexTypes.clustered && isCollection;
2299
2339
  const transforms = this._makeKeyTransforms(queryType);
@@ -3115,7 +3155,49 @@ class Entity {
3115
3155
  }
3116
3156
  }
3117
3157
 
3158
+ function getEntityIdentifiers(entities) {
3159
+ let identifiers = [];
3160
+ for (let alias of Object.keys(entities)) {
3161
+ let entity = entities[alias];
3162
+ let name = entity.model.entity;
3163
+ let version = entity.model.version;
3164
+ identifiers.push({
3165
+ name,
3166
+ alias,
3167
+ version,
3168
+ entity,
3169
+ nameField: entity.identifiers.entity,
3170
+ versionField: entity.identifiers.version
3171
+ });
3172
+ }
3173
+ return identifiers;
3174
+ }
3175
+
3176
+ function matchToEntityAlias({ paramItem, identifiers, record } = {}) {
3177
+ let entity;
3178
+ let entityAlias;
3179
+
3180
+ if (paramItem && v.isFunction(paramItem[TransactionCommitSymbol])) {
3181
+ const committed = paramItem[TransactionCommitSymbol]();
3182
+ entity = committed.entity;
3183
+ }
3184
+
3185
+ for (let {name, version, nameField, versionField, alias} of identifiers) {
3186
+ if (entity && entity.model.entity === name && entity.model.version === version) {
3187
+ entityAlias = alias;
3188
+ break;
3189
+ } else if (record[nameField] !== undefined && record[nameField] === name && record[versionField] !== undefined && record[versionField] === version) {
3190
+ entityAlias = alias;
3191
+ break;
3192
+ }
3193
+ }
3194
+
3195
+ return entityAlias;
3196
+ }
3197
+
3118
3198
  module.exports = {
3119
3199
  Entity,
3120
3200
  clauses,
3201
+ getEntityIdentifiers,
3202
+ matchToEntityAlias,
3121
3203
  };
package/src/filters.js CHANGED
@@ -76,7 +76,7 @@ class FilterFactory {
76
76
  let filterParents = Object.entries(injected)
77
77
  .filter(clause => {
78
78
  let [name, { children }] = clause;
79
- return children.includes("go");
79
+ return children.find(child => ['go', 'commit'].includes(child));
80
80
  })
81
81
  .map(([name]) => name);
82
82
  let modelFilters = Object.keys(filters);
@@ -86,7 +86,7 @@ class FilterFactory {
86
86
  injected[name] = {
87
87
  name: name,
88
88
  action: this.buildClause(filter),
89
- children: ["params", "go", "filter", ...modelFilters],
89
+ children: ["params", "go", "commit", "filter", ...modelFilters],
90
90
  };
91
91
  }
92
92
  filterChildren.push("filter");
@@ -95,7 +95,7 @@ class FilterFactory {
95
95
  action: (entity, state, fn) => {
96
96
  return this.buildClause(fn)(entity, state);
97
97
  },
98
- children: ["params", "go", "filter", ...modelFilters],
98
+ children: ["params", "go", "commit", "filter", ...modelFilters],
99
99
  };
100
100
  for (let parent of filterParents) {
101
101
  injected[parent] = { ...injected[parent] };
package/src/service.js CHANGED
@@ -1,14 +1,15 @@
1
- const { Entity } = require("./entity");
1
+ const { Entity, getEntityIdentifiers, matchToEntityAlias } = require("./entity");
2
2
  const { clauses } = require("./clauses");
3
- const { KeyCasing, ServiceVersions, Pager, ElectroInstance, ElectroInstanceTypes, ModelVersions, IndexTypes } = require("./types");
3
+ const { TableIndex, TransactionMethods, KeyCasing, ServiceVersions, Pager, ElectroInstance, ElectroInstanceTypes, ModelVersions, IndexTypes } = require("./types");
4
4
  const { FilterFactory } = require("./filters");
5
5
  const { FilterOperations } = require("./operations");
6
6
  const { WhereFactory } = require("./where");
7
- const { getInstanceType, getModelVersion, applyBetaModelOverrides } = require("./util");
8
7
  const v = require("./validations");
9
8
  const c = require('./client');
10
9
  const e = require("./errors");
11
10
  const u = require("./util");
11
+ const txn = require("./transaction");
12
+ const { getInstanceType, getModelVersion, applyBetaModelOverrides } = require("./util");
12
13
 
13
14
  const ConstructorTypes = {
14
15
  beta: "beta",
@@ -68,6 +69,22 @@ class Service {
68
69
  this.compositeAttributes = {};
69
70
  this.collections = {};
70
71
  this.identifiers = {};
72
+ this.transaction = {
73
+ get: (fn) => {
74
+ return txn.createTransaction({
75
+ fn,
76
+ getEntities: () => this.entities,
77
+ method: TransactionMethods.transactGet,
78
+ });
79
+ },
80
+ write: (fn) => {
81
+ return txn.createTransaction({
82
+ fn,
83
+ getEntities: () => this.entities,
84
+ method: TransactionMethods.transactWrite,
85
+ });
86
+ }
87
+ };
71
88
  this._instance = ElectroInstance.service;
72
89
  this._instanceType = ElectroInstanceTypes.service;
73
90
  }
@@ -94,6 +111,22 @@ class Service {
94
111
  this.compositeAttributes = {};
95
112
  this.collections = {};
96
113
  this.identifiers = {};
114
+ this.transaction = {
115
+ get: (fn) => {
116
+ return txn.createTransaction({
117
+ fn,
118
+ getEntities: () => this.entities,
119
+ method: TransactionMethods.transactGet,
120
+ });
121
+ },
122
+ write: (fn) => {
123
+ return txn.createTransaction({
124
+ fn,
125
+ getEntities: () => this.entities,
126
+ method: TransactionMethods.transactWrite,
127
+ });
128
+ }
129
+ };
97
130
  this._instance = ElectroInstance.service;
98
131
  this._instanceType = ElectroInstanceTypes.service;
99
132
  }
@@ -270,53 +303,39 @@ class Service {
270
303
  }
271
304
  }
272
305
 
273
- _getEntityIdentifiers(entities) {
274
- let identifiers = [];
275
- for (let alias of Object.keys(entities)) {
276
- let entity = entities[alias];
277
- let name = entity.model.entity;
278
- let version = entity.model.version;
279
- identifiers.push({
280
- name,
281
- alias,
282
- version,
283
- entity,
284
- nameField: entity.identifiers.entity,
285
- versionField: entity.identifiers.version
286
- });
287
- }
288
- return identifiers;
289
- }
290
-
291
- cleanseRetrievedData(collection = "", entities, data = {}, config = {}) {
306
+ cleanseRetrievedData(index = TableIndex, entities, data = {}, config = {}) {
292
307
  if (config.raw) {
293
308
  return data;
294
309
  }
310
+ const identifiers = getEntityIdentifiers(entities);
311
+
295
312
  data.Items = data.Items || [];
296
- let index = this.collectionSchema[collection].index;
297
- let results = {};
298
- let identifiers = this._getEntityIdentifiers(entities);
313
+
314
+ const results = {};
299
315
  for (let {alias} of identifiers) {
300
316
  results[alias] = [];
301
317
  }
302
- for (let record of data.Items) {
303
- let entityAlias;
304
- for (let {name, version, nameField, versionField, alias} of identifiers) {
305
- if (record[nameField] !== undefined && record[nameField] === name && record[versionField] !== undefined && record[versionField] === version) {
306
- entityAlias = alias;
307
- break;
308
- }
318
+
319
+ for (let i = 0; i < data.Items.length; i++) {
320
+ const record = data.Items[i];
321
+
322
+ if (!record) {
323
+ continue;
309
324
  }
325
+
326
+ const entityAlias = matchToEntityAlias({identifiers, record});
327
+
310
328
  if (!entityAlias) {
311
329
  continue;
312
330
  }
313
331
  // pager=false because we don't want the entity trying to parse the lastEvaluatedKey
314
- let items = this.collectionSchema[collection].entities[entityAlias].formatResponse({Item: record}, index, {
332
+ let formatted = entities[entityAlias].formatResponse({Item: record}, index, {
315
333
  ...config,
316
334
  pager: false,
317
335
  parse: undefined
318
336
  });
319
- results[entityAlias].push(items.data);
337
+
338
+ results[entityAlias].push(formatted.data);
320
339
  }
321
340
  return results;
322
341
  }
@@ -364,7 +383,7 @@ class Service {
364
383
  name = "",
365
384
  initialClauses = {},
366
385
  }, facets = {}) {
367
- const { entities, attributes, identifiers, indexType } = this.collectionSchema[name];
386
+ const { entities, attributes, identifiers, indexType, index } = this.collectionSchema[name];
368
387
  const compositeAttributes = this.compositeAttributes[name];
369
388
  const allEntities = Object.values(entities);
370
389
  const entity = allEntities[0];
@@ -381,7 +400,10 @@ class Service {
381
400
  let options = {
382
401
  // expressions, // DynamoDB doesnt return what I expect it would when provided with these entity filters
383
402
  parse: (options, data) => {
384
- return this.cleanseRetrievedData(name, entities, data, options);
403
+ if (options.raw) {
404
+ return data;
405
+ }
406
+ return this.cleanseRetrievedData(index, entities, data, options);
385
407
  },
386
408
  formatCursor: {
387
409
  serialize: (key) => {
@@ -391,13 +413,18 @@ class Service {
391
413
  return this.expectCursorOwner(cursor).deserializeCursor(cursor);
392
414
  }
393
415
  },
394
- expressions: {
416
+ identifiers: {
395
417
  names: identifiers.names || {},
396
418
  values: identifiers.values || {},
397
419
  expression: allEntities.length > 1
398
420
  ? `(${expression})`
399
421
  : expression
400
422
  },
423
+ expressions: {
424
+ names: {},
425
+ values: {},
426
+ expression: '',
427
+ },
401
428
  attributes,
402
429
  entities,
403
430
  indexType,
@@ -730,4 +757,6 @@ class Service {
730
757
  }
731
758
  }
732
759
 
733
- module.exports = { Service };
760
+ module.exports = {
761
+ Service,
762
+ };