Skip to content

Instantly share code, notes, and snippets.

@njamaleddine
Last active November 21, 2018 04:02
Show Gist options
  • Select an option

  • Save njamaleddine/269d63a5fa4dc6350cb0ae8c8cfc32c4 to your computer and use it in GitHub Desktop.

Select an option

Save njamaleddine/269d63a5fa4dc6350cb0ae8c8cfc32c4 to your computer and use it in GitHub Desktop.
fun with dynamodb (also install and start scripts for local dev)
const AWS = require('aws-sdk');
const moment = require('moment');
const config = require('../config');
const dynamodb = new AWS.DynamoDB({
apiVersion: config.dynamodb.apiVersion,
endpoint: config.dynamodb.endpoint,
region: config.dynamodb.region,
maxRetries: config.dynamodb.maxRetries,
retryDelayOptions: {
base: config.dynamodb.retryDelayOptions.base,
},
});
const documentClient = new AWS.DynamoDB.DocumentClient({ service: dynamodb });
/**
* @description Maps JavaScript types to DynamoDB types
* @param {*} Any - JavaScript Primitive or Object Type part of the JSON spec
* @returns {*} new field mapped to a supported DynamoDB type
*/
function mapToDb(field) {
const nullTypes = ['', null, undefined];
if (nullTypes.includes(field)) {
return null;
} if (field instanceof moment) {
return field.toDate().toISOString();
} if (field instanceof Date) {
return field.toISOString();
} if (field instanceof Array) {
return field.map(item => mapToDb(item));
} if (typeof field === 'object') {
const newObject = {};
Object.keys(field).forEach((key) => {
newObject[key] = mapToDb(field[key]);
});
return newObject;
}
// passthrough for every other type
return field;
}
/**
* @description Maps the fields of a JavaScript Object to DynamoDB types
* @param {Object}
* @returns {Object} new Object with the mapped types
*/
function getTableNameForEnv(table) {
const environment = config.env ? config.env : 'local';
return `${environment}.${table}`;
}
module.exports = {
dynamodb,
documentClient,
mapToDb,
getTableNameForEnv,
};
/* global expect, describe, test */
const moment = require('moment');
const { mapToDb } = require('./dynamodb');
describe('mapToDb', () => {
test('it converts empty strings to null', () => {
expect(mapToDb('')).toEqual(null);
});
test('it converts undefined to null', () => {
expect(mapToDb(undefined)).toEqual(null);
});
test('it converts null to null', () => {
expect(mapToDb(null)).toEqual(null);
});
test('it converts Dates to an iso8601 datetime string', () => {
const date = new Date('2018-10-01');
expect(mapToDb(date)).toEqual('2018-10-01T00:00:00.000Z');
});
test('it converts a moment instance to an iso8601 datetime string', () => {
const momentInstance = moment('2018-10-01');
expect(mapToDb(momentInstance)).toEqual('2018-10-01T00:00:00.000Z');
});
test('it converts fields of an Array to DynamoDB types', () => {
const array = ['', new Date('2018-10-01')];
const dynamoArray = [null, '2018-10-01T00:00:00.000Z'];
expect(mapToDb(array)).toEqual(dynamoArray);
});
test('it converts a flat object to a dynamodb object', () => {
const obj = {
name: 'Bob',
hometown: '',
dateJoined: new Date('2018-10-11'),
};
const expectedDynamoObject = {
name: 'Bob',
hometown: null,
dateJoined: '2018-10-11T00:00:00.000Z',
};
expect(mapToDb(obj)).toEqual(expectedDynamoObject);
});
test('it converts object fields to DynamoDB types', () => {
const obj = {
name: 'Bob',
hometown: '',
dateJoined: new Date('2018-10-11'),
locations: [
{
name: 'Tokyo',
arrival: new Date('2017-01-01'),
},
],
};
const expectedDynamoObject = {
name: 'Bob',
hometown: null,
dateJoined: '2018-10-11T00:00:00.000Z',
locations: [
{
name: 'Tokyo',
arrival: '2017-01-01T00:00:00.000Z',
},
],
};
expect(mapToDb(obj)).toEqual(expectedDynamoObject);
});
test('it converts a multi-level nested object to a DynamoDB object', () => {
const obj = {
name: 'Bob',
hometown: '',
dateJoined: new Date('2018-10-11'),
skills: {
js: {
node: {
notes: '',
dateLearned: new Date('2018-10-11'),
},
},
},
countries: [
{
name: 'Japan',
cities: {
name: 'Tokyo',
arrival: new Date('2017-01-01'),
},
},
{
name: 'Spain',
cities: {
name: 'Madrid',
arrival: new Date('2015-12-01'),
},
},
],
};
const expectedDynamoObject = {
name: 'Bob',
hometown: null,
dateJoined: '2018-10-11T00:00:00.000Z',
skills: {
js: {
node: {
notes: null,
dateLearned: '2018-10-11T00:00:00.000Z',
},
},
},
countries: [
{
name: 'Japan',
cities: {
name: 'Tokyo',
arrival: '2017-01-01T00:00:00.000Z',
},
},
{
name: 'Spain',
cities: {
name: 'Madrid',
arrival: '2015-12-01T00:00:00.000Z',
},
},
],
};
expect(mapToDb(obj)).toEqual(expectedDynamoObject);
});
});
#!/bin/bash
# Setup script for Local Dynamodb
# https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html
DYNAMODB_LOCAL_TAR_URL="https://s3-us-west-2.amazonaws.com/dynamodb-local/dynamodb_local_latest.tar.gz"
PRIVATE_DIRECTORY=".private"
SETUP_DIRECTORY="$PRIVATE_DIRECTORY/setup"
LOCAL_DYNAMODB_DIRECTORY="$SETUP_DIRECTORY/DynamoDBLocal_lib"
LOCAL_DYNAMODB_JAR_FILE="$SETUP_DIRECTORY/DynamoDBLocal.jar"
if [ -f "$LOCAL_DYNAMODB_JAR_FILE" ] && [ -d "$LOCAL_DYNAMODB_DIRECTORY" ]; then
# Exit setup if local dynamodb exists
exit 1
else
echo "$LOCAL_DYNAMODB_JAR_FILE does not exist, starting setup"
fi
if [ ! -d "$SETUP_DIRECTORY" ]; then
echo "No $SETUP_DIRECTORY directory, creating one ..."
mkdir -p $SETUP_DIRECTORY
fi
echo "Downloading local dynamodb to $SETUP_DIRECTORY ..."
curl $DYNAMODB_LOCAL_TAR_URL -o "$SETUP_DIRECTORY/dynamodb_local_latest.tar.gz"
tar -xvzf $SETUP_DIRECTORY/dynamodb_local_latest.tar.gz -C $SETUP_DIRECTORY
echo "Done setting up local dynamodb environment!"
SETUP_DIRECTORY=".private/setup/"
LOCAL_DYNAMODB_DIRECTORY="$SETUP_DIRECTORY/DynamoDBLocal_lib"
LOCAL_DYNAMODB_JAR_FILE="$SETUP_DIRECTORY/DynamoDBLocal.jar"
if [ ! -f "$LOCAL_DYNAMODB_JAR_FILE" ] || [ ! -d "$LOCAL_DYNAMODB_DIRECTORY" ]; then
scripts/local_dynamodb/install.sh
fi
echo "Starting local dynamodb ..."
java -Djava.library.path=$LOCAL_DYNAMODB_DIRECTORY -jar "$SETUP_DIRECTORY/DynamoDBLocal.jar" -sharedDb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment