@voodoo.io/aws-utils
Advanced tools
Comparing version 1.1.0 to 2.0.0
{ | ||
"name": "@voodoo.io/aws-utils", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "AWS utils methods - using homemade retry system", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -30,2 +30,14 @@ # aws-utils | ||
**BREAKING CHANGES since version 2.0** | ||
Now dynamo tools returns an object and not directly an array of items. | ||
```json | ||
{ | ||
Items:[ { ....} , { ... } ], | ||
LastEvaluatedKey: {....} | ||
} | ||
``` | ||
# Installation | ||
@@ -70,3 +82,3 @@ | ||
#### queryHashKey(dynamoTable, hashKeyName, hashKeyValue, [exclusiveStartKey]) | ||
#### queryHashKey(dynamoTable, hashKeyName, hashKeyValue, [exclusiveStartKey], [limit]) | ||
@@ -77,2 +89,3 @@ * `dynamoTable` : table's name | ||
* `exclusiveStartKey` : (optional) start search at a specific key | ||
* `limit` : (optional) don't return more items than the limit | ||
@@ -84,3 +97,3 @@ #### putItem(dynamoTable, item) | ||
#### scan(dynamoTable, [hashKeyName], [hashKeyValue], [exclusiveStartKey]) | ||
#### scan(dynamoTable, [hashKeyName], [hashKeyValue], [exclusiveStartKey], [limit]) | ||
@@ -91,2 +104,3 @@ * `dynamoTable` : table's name | ||
* `exclusiveStartKey` : (optional) start search at a specific key | ||
* `limit` : (optional) don't return more items than the limit | ||
@@ -93,0 +107,0 @@ If no hashkey is provided it returns the full table. |
@@ -35,4 +35,4 @@ /** | ||
*/ | ||
queryHashKey(dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey = null, results = [], cli = null) { | ||
return this._promiseFunction('query', 'queryHashKey', dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey, results, cli); | ||
queryHashKey(dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey = null, limit = null, results = {Items: []}, cli = null) { | ||
return this._promiseFunction('query', 'queryHashKey', dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey, limit, results, cli); | ||
} | ||
@@ -99,4 +99,4 @@ | ||
*/ | ||
scan(dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey = null, results = [], cli = null) { | ||
return this._promiseFunction('scan', 'scan', dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey, results, cli); | ||
scan(dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey = null, limit = null, results = {Items: []}, cli = null) { | ||
return this._promiseFunction('scan', 'scan', dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey, limit, results, cli); | ||
} | ||
@@ -214,6 +214,7 @@ | ||
* @param {Object} exclusiveStartKey - use for pagination | ||
* @param {Array} results - query's results | ||
* @param {Object} results - query's results | ||
* @param {*} cli - fallback cli in case the default one fail, useful when we use DAX and we want to fallback to dynamo | ||
* @param {Number} limit - in case of specific limit | ||
*/ | ||
_promiseFunction (AWSMethod, method, dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey, results, cli) { | ||
_promiseFunction (AWSMethod, method, dynamoTable, hashKeyName, hashKeyValue, exclusiveStartKey, limit, results, cli) { | ||
const AWSCli = cli || this.cli; | ||
@@ -236,3 +237,3 @@ const AWSCliFallback = this.cliFallback; | ||
return new Promise((resolve, reject) => { | ||
if (method === 'queryHashKey' && (typeof dynamoTable !== "string" || typeof hashKeyName !== "string" || typeof hashKeyValue !== "string" || typeof exclusiveStartKey !== "object" || !Array.isArray(results))) { | ||
if (method === 'queryHashKey' && (typeof dynamoTable !== "string" || typeof hashKeyName !== "string" || typeof hashKeyValue !== "string" || typeof exclusiveStartKey !== "object" || typeof results !== 'object')) { | ||
let myErr = new Error(`BAD_PARAM`); | ||
@@ -247,2 +248,6 @@ myErr.more_infos_queryHashKey = errObj; | ||
if(limit) { | ||
params.Limit = limit | ||
} | ||
// if we request a specific key | ||
@@ -274,3 +279,3 @@ // we build condition and expression | ||
// if error is retryable we will execute it again | ||
await this._execute(method, AWSMethod, dynamoTable, hashKeyName, hashKeyValue, results, params, AWSCli); | ||
await this._execute(method, AWSMethod, dynamoTable, hashKeyName, hashKeyValue, results, params, AWSCli, limit); | ||
return resolve(results); | ||
@@ -285,3 +290,3 @@ } catch (err) { | ||
try { | ||
await this._execute(method, AWSMethod, dynamoTable, hashKeyName, hashKeyValue, results, params, AWSCliFallback); | ||
await this._execute(method, AWSMethod, dynamoTable, hashKeyName, hashKeyValue, results, params, AWSCliFallback, limit); | ||
return resolve(results); | ||
@@ -301,3 +306,3 @@ } catch (errDynamo) { | ||
// collect data into "results" before return it | ||
await this._collecData(method, AWSMethod, data, dynamoTable, hashKeyName, hashKeyValue, results, AWSCli); | ||
await this._collecData(method, AWSMethod, data, dynamoTable, hashKeyName, hashKeyValue, results, AWSCli, limit); | ||
return resolve(results); | ||
@@ -320,7 +325,7 @@ }) | ||
*/ | ||
async _execute(func, cliFunc, dynamoTable, hashKeyName, hashKeyValue, results, params, cli) { | ||
async _execute(func, cliFunc, dynamoTable, hashKeyName, hashKeyValue, results, params, cli, limit) { | ||
// retry the method with its original params | ||
const data = await utils.retry(cli[cliFunc], [params], true, this.retryMax); | ||
// collect data into results array | ||
await this._collecData(func, cliFunc, data, dynamoTable, hashKeyName, hashKeyValue, results, cli) | ||
await this._collecData(func, cliFunc, data, dynamoTable, hashKeyName, hashKeyValue, results, cli, limit) | ||
return results; | ||
@@ -341,11 +346,14 @@ } | ||
*/ | ||
async _collecData (func, cliFunc, data, dynamoTable, hashKeyName, hashKeyValue, results, AWSCli) { | ||
async _collecData (func, cliFunc, data, dynamoTable, hashKeyName, hashKeyValue, results, AWSCli, limit) { | ||
// collect data from "Items" property | ||
if (data && data.Items && data.Items.length > 0) { | ||
for (const obj of data.Items) { | ||
results.push(obj); | ||
results.Items.push(obj); | ||
} | ||
results.LastEvaluatedKey = data.LastEvaluatedKey; | ||
} | ||
// if we need pagination, then recall the original method of dynamoTools | ||
if (data.LastEvaluatedKey) return await this._promiseFunction(cliFunc, func, dynamoTable, hashKeyName, hashKeyValue, data.LastEvaluatedKey, results, AWSCli); | ||
if (data.LastEvaluatedKey && (limit == null || limit > results.Items.length)) return await this._promiseFunction(cliFunc, func, dynamoTable, hashKeyName, hashKeyValue, data.LastEvaluatedKey, limit, results, AWSCli); | ||
return results; | ||
@@ -352,0 +360,0 @@ } |
@@ -5,2 +5,4 @@ const AWS = require('aws-sdk-mock'); | ||
function AmazonDaxClient(){ this.query = (params, cb) => {const err = new Error('Error from Dax'); err.retryable = true; cb(err, null);}} | ||
AWS.mock('DynamoDB.DocumentClient', 'query', function (params, callback) { | ||
@@ -133,5 +135,12 @@ let res = []; | ||
id: 2 | ||
}]; | ||
}]; | ||
let lastEvaluatedKey = null | ||
callback(null, { 'Items': res }); | ||
// remove one item to respect the limit of 1 item | ||
if(params.Limit) { | ||
res.pop() | ||
lastEvaluatedKey = {} | ||
} | ||
callback(null, { 'Items': res, 'LastEvaluatedKey': lastEvaluatedKey }); | ||
}); | ||
@@ -174,4 +183,4 @@ | ||
expect(res.length).toEqual(2); | ||
expect(res[0].id).toEqual(1); | ||
expect(res.Items.length).toEqual(2); | ||
expect(res.Items[0].id).toEqual(1); | ||
}) | ||
@@ -182,5 +191,5 @@ | ||
expect(res.length).toEqual(2); | ||
expect(res[0].id).toEqual(1); | ||
expect(res[1].id).toEqual(2); | ||
expect(res.Items.length).toEqual(2); | ||
expect(res.Items[0].id).toEqual(1); | ||
expect(res.Items[1].id).toEqual(2); | ||
}) | ||
@@ -210,3 +219,2 @@ | ||
function AmazonDaxClient(){ this.query = (params, cb) => {const err = new Error('Error from Dax'); err.retryable = true; cb(err, null);}}; | ||
const daxClient = new AmazonDaxClient(); | ||
@@ -233,3 +241,2 @@ const logger = require('pino')(); | ||
function AmazonDaxClient(){ this.query = (params, cb) => {const err = new Error('Error from Dax'); err.retryable = true; cb(err, null);}}; | ||
const daxClient = new AmazonDaxClient(); | ||
@@ -239,3 +246,3 @@ dynamoTools = new awsUtils(daxClient); | ||
const res = await dynamoTools.queryHashKey('errorWithDaxButOkWithDynamo', 'key', 'value'); | ||
expect(res.length).toEqual(1); | ||
expect(res.Items.length).toEqual(1); | ||
}, 10000) | ||
@@ -245,4 +252,4 @@ | ||
const res = await dynamoTools.queryHashKey('errorWithOneRetry', 'key', 'value'); | ||
expect(res.length).toEqual(1); | ||
expect(res[0].id).toEqual(2) | ||
expect(res.Items.length).toEqual(1); | ||
expect(res.Items[0].id).toEqual(2) | ||
}) | ||
@@ -275,3 +282,3 @@ | ||
const res = await dynamoTools.queryHashKey('noItems', 'key', 'value'); | ||
expect(res.length).toEqual(0); | ||
expect(res.Items.length).toEqual(0); | ||
}) | ||
@@ -295,5 +302,12 @@ }) | ||
expect(res.length).toEqual(2); | ||
expect(res[0].id).toEqual(1) | ||
expect(res.Items.length).toEqual(2); | ||
expect(res.Items[0].id).toEqual(1) | ||
}) | ||
it('Normal case with limit', async () => { | ||
const res = await dynamoTools.scan('myTable', null, null, null, 1); | ||
expect(res.Items.length).toEqual(1); | ||
expect(res.Items[0].id).toEqual(1) | ||
}) | ||
}) | ||
@@ -300,0 +314,0 @@ |
52246
1222
171