UNPKG

@amazon-dax-sdk/lib-dax

Version:

Amazon DAX Document Client for JavaScript

364 lines (347 loc) 9.45 kB
/* * 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. */ 'use strict'; 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;