Skip to content

Instantly share code, notes, and snippets.

@neftaly
Created January 16, 2018 01:24
Show Gist options
  • Select an option

  • Save neftaly/504d6ea7b438cd9dc1cd0e1e28e65b89 to your computer and use it in GitHub Desktop.

Select an option

Save neftaly/504d6ea7b438cd9dc1cd0e1e28e65b89 to your computer and use it in GitHub Desktop.
DynamoDB backup (v3) raw file to/from JSON
const R = require('ramda');
const typeEncoder = (mode, type) => {
if (mode !== 'fromDynamo' && mode !== 'toDynamo') {
throw new Error('Invalid mode: ' + mode);
}
const numberEncoder = mode === 'fromDynamo' ? Number : String;
switch (R.toUpper(type)) {
case 'S': return String;
case 'N': return numberEncoder;
case 'B': return Buffer;
case 'NULLVALUE':
case 'NULL': return R.always(mode === 'fromDynamo' ? null : true);
case 'BOOL': return Boolean;
case 'SS': return R.map(String);
case 'NS': return R.map(numberEncoder);
case 'BS': return R.map(Buffer);
case 'L':
case 'M':
return mode === 'fromDynamo' ? fromDynamo : R.map(toDynamo);
default: throw new Error('Unknown type: ' + type);
}
};
// Get Dynamo type from JS value
// :: jsValue => dynamoType
const getType = value => {
const getSetType = R.compose(
R.unless(R.identity, R.always('l')),
R.reduce((prior, current) => {
const set = current + 'S';
const list = R.reduced('l');
if (prior && prior !== set) return list;
return R.contains(set, ['sS', 'nS', 'bS']) ? set : list;
}, false),
R.map(getType)
);
const constructor = value === null ? value : value.constructor;
switch (constructor) {
case String: return 's';
case Number: return 'n';
case Buffer: return 'b';
case null: return 'nULLValue';
case Boolean: return 'bOOL';
case Array: return getSetType(value);
case Object: return 'm';
default: throw new Error('Unknown type: ' + constructor);
}
};
// Convert from JS to DynamoDB
// :: jsMap => dynamoMap
const toDynamo = value => {
if (value === undefined) {
return undefined;
}
const type = getType(value);
const newValue = typeEncoder('toDynamo', type)(value);
return { [type]: newValue };
};
// Convert from DynamoDB to JS
// :: dynamoMap => jsMap
const fromDynamo = R.compose(
R.map(row => {
const type = R.compose(R.head, R.keys)(row);
const value = row[type];
return typeEncoder('fromDynamo', type)(value);
}),
R.defaultTo({})
);
// Convert from DDB string to JS
const lineToJS = fromDynamo;
// :: string => object
const toJS = R.compose(
R.map(lineToJS),
R.match(/[^\r\n]+/g)
);
// Convert from JS to DDB string
const lineFromJS = R.compose(
JSON.stringify,
R.prop('m'),
toDynamo
);
// :: object => string
const fromJS = R.compose(
R.join('\n'),
R.map(lineFromJS),
R.values
);
module.exports = {
toJS,
fromJS,
lineToJS,
lineFroms
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment