@amazon-dax-sdk/lib-dax
Version:
Amazon DAX Document Client for JavaScript
364 lines (347 loc) • 9.45 kB
JavaScript
/*
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
* use this file except in compliance with the License. A copy of the License
* is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
;
const {marshall, unmarshall} = require('@aws-sdk/util-dynamodb');
const ALL_VALUES = {};
const ALL_MEMBERS = [];
const NEXT_LEVEL = '*';
const SELF = null;
class Util {
/**
* Whether to convert the top level container
* if it is a map or list.
*
* Default is true when using the DynamoDBDocumentClient,
* but false if directly using the marshall function (backwards compatibility).
*/
static marshallingOptions() {
return {convertTopLevelContainer: true};
}
/**
* When true, skip wrapping the data in `{ M: data }` before converting.
*
* Default is true when using the DynamoDBDocumentClient,
* but false if directly using the unmarshall function (backwards compatibility).
*/
static unmarshallOptions() {
return {convertWithoutMapWrapper: true};
}
// Copied from client-dax
static deepCopy(obj) {
if(obj === undefined || obj === null || typeof(obj) !== 'object') {
return obj;
}
if(Array.isArray(obj)) {
return obj.map((e) => Util.deepCopy(e));
}
if(Buffer.isBuffer(obj)) {
return Buffer.from(obj);
}
let clone = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)) {
clone[prop] = Util.deepCopy(obj[prop]);
}
}
return clone;
}
// Copied from AWS-SDK-V3 Code for Marshalling & Unmarshalling an Object Code Reference :- https://github.com/aws/aws-sdk-js-v3/blob/main/lib/lib-dynamodb/src/commands/utils.ts
static processObj(obj, processFunc, keyNodes) {
if(obj !== undefined) {
if(keyNodes == null) {
return processFunc(obj);
} else {
const keys = Object.keys(keyNodes);
const goToNextLevel = keys.length === 1 && keys[0] === NEXT_LEVEL;
const someChildren = keys.length >= 1 && !goToNextLevel;
const allChildren = keys.length === 0;
if(someChildren) {
return this.processKeysInObj(obj, processFunc, keyNodes);
} else if(allChildren) {
return this.processAllKeysInObj(obj, processFunc, SELF);
} else if(goToNextLevel) {
return Object.entries(obj ?? {}).reduce((acc, [k, v]) => {
if(typeof v !== 'function') {
acc[k] = this.processObj(v, processFunc, keyNodes[NEXT_LEVEL]);
}
return acc;
}, (Array.isArray(obj) ? [] : {}));
}
}
}
return undefined;
}
static processKeysInObj(obj, processFunc, keyNodes) {
let accumulator;
if(Array.isArray(obj)) {
accumulator = obj.filter((item) => typeof item !== 'function');
} else {
accumulator = {};
for(const [k, v] of Object.entries(obj)) {
if(typeof v !== 'function') {
accumulator[k] = v;
}
}
}
for(const [nodeKey, nodes] of Object.entries(keyNodes)) {
if(typeof obj[nodeKey] === 'function') {
continue;
}
const processedValue = this.processObj(obj[nodeKey], processFunc, nodes);
if(processedValue !== undefined && typeof processedValue !== 'function') {
accumulator[nodeKey] = processedValue;
}
}
return accumulator;
}
static processAllKeysInObj(obj, processFunc, keyNodes) {
if(Array.isArray(obj)) {
return obj.filter((item) => typeof item !== 'function').map((item) => this.processObj(item, processFunc, keyNodes));
}
return Object.entries(obj).reduce((acc, [key, value]) => {
if(typeof value === 'function') {
return acc;
}
const processedValue = this.processObj(value, processFunc, keyNodes);
if(processedValue !== undefined && typeof processedValue !== 'function') {
acc[key] = processedValue;
}
return acc;
}, {});
}
static marshallInput(obj, keyNodes, options) {
const marshallFunc = (toMarshall) => marshall(toMarshall, options);
return this.processKeysInObj(obj, marshallFunc, keyNodes);
}
static unmarshallOutput(obj, keyNodes, options) {
const unmarshallFunc = (toMarshall) => unmarshall(toMarshall, options);
return this.processKeysInObj(obj, unmarshallFunc, keyNodes);
}
/*
* Mapping Copied from AWS-JS-SDK-V3
* Referenace of Input and Output Keynodes are Taken through https://github.com/aws/aws-sdk-js-v3/tree/main/lib/lib-dynamodb/src/commands
*/
static inputKeyNodes(operation) {
const inputKeyMap = {
batchGet: {
RequestItems: {
'*': {
Keys: {
'*': ALL_VALUES,
},
},
},
},
batchWrite: {
RequestItems: {
'*': {
'*': {
PutRequest: {
Item: ALL_VALUES,
},
DeleteRequest: {
Key: ALL_VALUES,
},
},
},
},
},
delete: {
Key: ALL_VALUES,
Expected: {
'*': {
Value: SELF,
AttributeValueList: ALL_MEMBERS,
},
},
ExpressionAttributeValues: ALL_VALUES,
},
get: {
Key: ALL_VALUES,
},
put: {
Item: ALL_VALUES,
Expected: {
'*': {
Value: SELF,
AttributeValueList: ALL_MEMBERS,
},
},
ExpressionAttributeValues: ALL_VALUES,
},
query: {
KeyConditions: {
'*': {
AttributeValueList: ALL_MEMBERS,
},
},
QueryFilter: {
'*': {
AttributeValueList: ALL_MEMBERS,
},
},
ExclusiveStartKey: ALL_VALUES,
ExpressionAttributeValues: ALL_VALUES,
},
scan: {
ScanFilter: {
'*': {
AttributeValueList: ALL_MEMBERS,
},
},
ExclusiveStartKey: ALL_VALUES,
ExpressionAttributeValues: ALL_VALUES,
},
transactGet: {
TransactItems: {
'*': {
Get: {
Key: ALL_VALUES,
},
},
},
},
transactWrite: {
TransactItems: {
'*': {
ConditionCheck: {
Key: ALL_VALUES,
ExpressionAttributeValues: ALL_VALUES,
},
Put: {
Item: ALL_VALUES,
ExpressionAttributeValues: ALL_VALUES,
},
Delete: {
Key: ALL_VALUES,
ExpressionAttributeValues: ALL_VALUES,
},
Update: {
Key: ALL_VALUES,
ExpressionAttributeValues: ALL_VALUES,
},
},
},
},
update: {
Key: ALL_VALUES,
AttributeUpdates: {
'*': {
Value: SELF,
},
},
Expected: {
'*': {
Value: SELF,
AttributeValueList: ALL_MEMBERS,
},
},
ExpressionAttributeValues: ALL_VALUES,
},
};
return inputKeyMap[operation];
}
// Mapping Copied from AWS-JS-SDK-V3
static outputKeyNodes(operation) {
const outputKeyMap = {
batchGet: {
Responses: {
'*': {
'*': ALL_VALUES,
},
},
UnprocessedKeys: {
'*': {
Keys: {
'*': ALL_VALUES,
},
},
},
},
batchWrite: {
UnprocessedItems: {
'*': {
'*': {
PutRequest: {
Item: ALL_VALUES,
},
DeleteRequest: {
Key: ALL_VALUES,
},
},
},
},
ItemCollectionMetrics: {
'*': {
'*': {
ItemCollectionKey: ALL_VALUES,
},
},
},
},
delete: {
Attributes: ALL_VALUES,
ItemCollectionMetrics: {
ItemCollectionKey: ALL_VALUES,
},
},
get: {
Item: ALL_VALUES,
},
put: {
Attributes: ALL_VALUES,
ItemCollectionMetrics: {
ItemCollectionKey: ALL_VALUES,
},
},
query: {
Items: {
'*': ALL_VALUES,
},
LastEvaluatedKey: ALL_VALUES,
},
scan: {
Items: {
'*': ALL_VALUES,
},
LastEvaluatedKey: ALL_VALUES,
},
transactGet: {
Responses: {
'*': {
Item: ALL_VALUES,
},
},
},
transactWrite: {
ItemCollectionMetrics: {
'*': {
'*': {
ItemCollectionKey: ALL_VALUES,
},
},
},
},
update: {
Attributes: ALL_VALUES,
ItemCollectionMetrics: {
ItemCollectionKey: ALL_VALUES,
},
},
};
return outputKeyMap[operation];
}
}
module.exports = Util;