dynamodb-admin
Advanced tools
Comparing version 3.0.3 to 3.1.0
const express = require('express') | ||
const _ = require('lodash') | ||
const {promisify} = require('es6-promisify') | ||
@@ -8,3 +7,4 @@ const path = require('path') | ||
const errorhandler = require('errorhandler') | ||
const { extractKey, extractKeysForItems, parseKey } = require('./util') | ||
const { extractKey, extractKeysForItems, parseKey, doSearch } = require('./util') | ||
const { purgeTable } = require('./actions/purgeTable') | ||
const bodyParser = require('body-parser') | ||
@@ -229,2 +229,10 @@ const pickBy = require('lodash/pickBy') | ||
app.delete('/tables/:TableName/all', (req, res, next) => { | ||
purgeTable(req.params.TableName, dynamodb) | ||
.then(() => { | ||
res.status(200).end() | ||
}) | ||
.catch(next) | ||
}) | ||
app.get('/tables/:TableName/get', (req, res) => { | ||
@@ -274,93 +282,33 @@ const TableName = req.params.TableName | ||
const doSearch = (docClient, tableName, scanParams, limit, startKey, done, progress, | ||
readOperation = 'scan') => { | ||
limit = typeof limit !== 'undefined' ? limit : null | ||
startKey = typeof startKey !== 'undefined' ? startKey : null | ||
let params = { TableName: tableName } | ||
if (typeof scanParams !== 'undefined' && scanParams) { | ||
params = _.assign(params, scanParams) | ||
} | ||
if (limit != null) {params.Limit = limit} | ||
if (startKey != null) {params.ExclusiveStartKey = startKey} | ||
const items = [] | ||
const processNextBite = function(err, items, nextKey) { | ||
if (!err && nextKey) { | ||
params.ExclusiveStartKey = nextKey | ||
getNextBite(params, items, processNextBite) | ||
} else { | ||
if (done) {done(err, items)} | ||
const getPage = (docClient, keySchema, TableName, scanParams, pageSize, | ||
startKey) => { | ||
const pageItems = [] | ||
function onNewItems(items, lastStartKey) { | ||
for (let i = 0; i < items.length && pageItems.length < pageSize + 1; i++) { | ||
pageItems.push(items[i]) | ||
} | ||
// If there is more items to query (!lastStartKey) then don't stop until | ||
// we are over pageSize count. Stopping at exactly pageSize count would | ||
// not extract key of last item later and make pagination not work. | ||
return pageItems.length > pageSize || !lastStartKey | ||
} | ||
const readMethod = { | ||
scan: docClient.scan, | ||
query: docClient.query | ||
}[readOperation].bind(docClient) | ||
return doSearch(docClient, TableName, scanParams, 10, startKey, onNewItems) | ||
.then(items => { | ||
let nextKey = null | ||
const getNextBite = function(params, items, callback) { | ||
readMethod(params, function(err, data) { | ||
if (err !== null) { | ||
callback(err, items, null) | ||
return | ||
if (items.length > pageSize) { | ||
items = items.slice(0, pageSize) | ||
nextKey = extractKey(items[pageSize - 1], keySchema) | ||
} | ||
if (data && data.Items && data.Items.length > 0) { | ||
items = items.concat(data.Items) | ||
return { | ||
pageItems: items, | ||
nextKey, | ||
} | ||
let lastStartKey = null | ||
if (data) { | ||
lastStartKey = data.LastEvaluatedKey | ||
} | ||
if (progress) { | ||
const stop = progress(err, data.Items, lastStartKey) | ||
if (!stop) { | ||
callback(err, items, lastStartKey) | ||
} else { | ||
if (done) { | ||
done(err, items) | ||
} | ||
} | ||
} else { | ||
callback(err, items, lastStartKey) | ||
} | ||
}) | ||
} | ||
getNextBite(params, items, processNextBite) | ||
} | ||
const getPage = (docClient, keySchema, TableName, scanParams, pageSize, startKey, | ||
done) => { | ||
let pageItems = [] | ||
doSearch( | ||
docClient, | ||
TableName, | ||
scanParams, | ||
10, | ||
startKey, | ||
err => { | ||
let nextKey = null | ||
if (_.size(pageItems) > pageSize) { | ||
pageItems = pageItems.slice(0, pageSize) | ||
nextKey = extractKey(pageItems[pageSize - 1], keySchema) | ||
} | ||
done(pageItems, err, nextKey) | ||
}, | ||
function(err, items, lastStartKey) { | ||
for ( | ||
let i = 0; | ||
i < items.length && _.size(pageItems) < pageSize + 1; | ||
i++ | ||
) { | ||
pageItems.push(items[i]) | ||
} | ||
// If there is more items to query (!lastStartKey) then don't stop until | ||
// we are over pageSize count. Stopping at exactly pageSize count would | ||
// not extract key of last item later and make pagination not work. | ||
return _.size(pageItems) > pageSize || !lastStartKey | ||
} | ||
) | ||
} | ||
app.get('/tables/:TableName', (req, res, next) => { | ||
@@ -452,10 +400,7 @@ const TableName = req.params.TableName | ||
getPage( | ||
docClient, | ||
description.Table.KeySchema, | ||
TableName, | ||
params, | ||
25, | ||
startKey, | ||
function(pageItems, err, nextKey) { | ||
return getPage(docClient, description.Table.KeySchema, TableName, | ||
params, 25, startKey) | ||
.then(results => { | ||
const {pageItems, nextKey} = results | ||
const nextKeyParam = nextKey | ||
@@ -465,7 +410,15 @@ ? encodeURIComponent(JSON.stringify(nextKey)) | ||
const Items = pageItems.map(item => Object.assign({}, item, { | ||
__key: extractKey(item, description.Table.KeySchema) | ||
})) | ||
const UniqueKeys = extractKeysForItems(Items) | ||
const primaryKeys = description.Table.KeySchema.map( | ||
schema => schema.AttributeName) | ||
// Primary keys are listed first. | ||
const uniqueKeys = [ | ||
...primaryKeys, | ||
...extractKeysForItems(pageItems).filter(key => !primaryKeys.includes(key)), | ||
] | ||
// Append the item key. | ||
for (const item of pageItems) { | ||
item.__key = extractKey(item, description.Table.KeySchema) | ||
} | ||
const data = Object.assign({}, description, { | ||
@@ -480,8 +433,9 @@ query: req.query, | ||
filterQueryString: querystring.stringify(filters), | ||
Items, | ||
UniqueKeys, | ||
Items: pageItems, | ||
primaryKeys, | ||
uniqueKeys, | ||
}) | ||
res.json(data) | ||
} | ||
) | ||
}) | ||
}) | ||
@@ -624,3 +578,8 @@ .catch(next) | ||
app.use((err, req, res, next) => { | ||
console.error(err) | ||
next(err) | ||
}) | ||
return app | ||
} |
@@ -0,1 +1,3 @@ | ||
const { promisify } = require('es6-promisify') | ||
exports.extractKey = function(item, KeySchema) { | ||
@@ -35,2 +37,81 @@ return KeySchema.reduce((prev, current) => { | ||
exports.doSearch = doSearch | ||
/** | ||
* Invokes a database scan | ||
* | ||
* @param {Object} docClient The AWS DynamoDB client | ||
* @param {String} tableName The table name | ||
* @param {Object} scanParams Extra params for the query | ||
* @param {Number} limit The of items to request per chunked query. NOT a limit | ||
* of items that should be returned. | ||
* @param {Object?} startKey The key to start query from | ||
* @param {Function} progress Function to execute on each new items returned | ||
* from query. Returns true to stop the query. | ||
* @param {string} readOperation The read operation | ||
* @return {Promise} Promise with items or rejected promise with error. | ||
*/ | ||
function doSearch(docClient, tableName, scanParams, limit, startKey, progress, | ||
readOperation = 'scan') { | ||
limit = limit !== undefined ? limit : null | ||
startKey = startKey !== undefined ? startKey : null | ||
let params = { | ||
TableName: tableName, | ||
} | ||
if (scanParams !== undefined && scanParams) { | ||
params = Object.assign(params, scanParams) | ||
} | ||
if (limit !== null) { | ||
params.Limit = limit | ||
} | ||
if (startKey !== null) { | ||
params.ExclusiveStartKey = startKey | ||
} | ||
const readMethod = { | ||
scan: promisify(docClient.scan.bind(docClient)), | ||
query: promisify(docClient.query.bind(docClient)), | ||
}[readOperation] | ||
let items = [] | ||
const getNextBite = (params, nextKey = null) => { | ||
if (nextKey) { | ||
params.ExclusiveStartKey = nextKey | ||
} | ||
return readMethod(params) | ||
.then(data => { | ||
if (data && data.Items && data.Items.length > 0) { | ||
items = items.concat(data.Items) | ||
} | ||
let lastStartKey = null | ||
if (data) { | ||
lastStartKey = data.LastEvaluatedKey | ||
} | ||
if (progress) { | ||
const stop = progress(data.Items, lastStartKey) | ||
if (stop) { | ||
return items | ||
} | ||
} | ||
if (!lastStartKey) { | ||
return items | ||
} | ||
return getNextBite(params, lastStartKey) | ||
}) | ||
} | ||
return getNextBite(params) | ||
} | ||
function typecastKey(keyName, keyValue, table) { | ||
@@ -37,0 +118,0 @@ const definition = table.AttributeDefinitions.find(attribute => { |
{ | ||
"name": "dynamodb-admin", | ||
"version": "3.0.3", | ||
"version": "3.1.0", | ||
"description": "GUI for DynamoDB. Useful for local development.", | ||
@@ -8,2 +8,3 @@ "main": "lib/backend.js", | ||
"scripts": { | ||
"dev": "nodemon bin/dynamodb-admin.js", | ||
"start": "node bin/dynamodb-admin.js", | ||
@@ -43,4 +44,5 @@ "lint": "eslint --ext .js .", | ||
"eslint-plugin-jest": "^21.24.1", | ||
"jest-cli": "^23.6.0" | ||
"jest-cli": "^23.6.0", | ||
"nodemon": "^1.18.6" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
796224
33
3936
4