diff --git a/index.js b/index.js index 2e48fdf..4589465 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,4 @@ "use strict"; -const _ = require("lodash"); const AWS = require("aws-sdk"); const dynamodbLocal = require("aws-dynamodb-local"); const seeder = require("./src/seeder"); @@ -11,11 +10,10 @@ class ServerlessDynamodbLocal { this.service = serverless.service; this.serverlessLog = serverless.cli.log.bind(serverless.cli); this.config = this.service.custom && this.service.custom['serverless-dynamodb'] || this.service.custom.dynamodb || {}; - this.options = _.merge({ - localPath: serverless.config && path.join(serverless.config.servicePath, '.dynamodb') - }, - options - ); + this.options = { + localPath: serverless.config && path.join(serverless.config.servicePath, '.dynamodb'), + ...options, + }; this.provider = "aws"; this.commands = { dynamodb: { @@ -156,13 +154,11 @@ class ServerlessDynamodbLocal { } get port() { - const port = _.get(this.config, "start.port", 8000); - return port; + return this.config?.start?.port ?? 8000; } get host() { - const host = _.get(this.config, "start.host", "localhost"); - return host; + return this.config?.start?.host ?? "localhost"; } /** @@ -254,13 +250,12 @@ class ServerlessDynamodbLocal { startHandler() { if (this.shouldExecute()) { - const options = _.merge({ - sharedDb: this.options.sharedDb || true, - installPath: this.options.localPath - }, - this.config.start, - this.options - ); + const options = { + sharedDb: this.options.sharedDb ?? true, + installPath: this.options.localPath, + ...this.config.start, + ...this.options + } // otherwise endHandler will be mis-informed this.options = options; @@ -288,19 +283,19 @@ class ServerlessDynamodbLocal { } getDefaultStack() { - return _.get(this.service, "resources"); + return this.service.resources; } getAdditionalStacks() { - return _.values(_.get(this.service, "custom.additionalStacks", {})); + return Object.values(this.service.custom?.additionalStacks ?? {}); } hasAdditionalStacksPlugin() { - return _.get(this.service, "plugins", []).includes("serverless-plugin-additional-stacks"); + return (this.service.plugins ?? []).includes("serverless-plugin-additional-stacks"); } getTableDefinitionsFromStack(stack) { - const resources = _.get(stack, "Resources", []); + const resources = stack.Resources ?? []; return Object.keys(resources).map((key) => { if (resources[key].Type === "AWS::DynamoDB::Table") { return resources[key].Properties; @@ -320,7 +315,7 @@ class ServerlessDynamodbLocal { } if (this.hasAdditionalStacksPlugin()) { - stacks = stacks.concat(this.getAdditionalStacks()); + stacks.push(...this.getAdditionalStacks()); } return stacks.map((stack) => this.getTableDefinitionsFromStack(stack)).reduce((tables, tablesInStack) => tables.concat(tablesInStack), []); @@ -330,7 +325,7 @@ class ServerlessDynamodbLocal { * Gets the seeding sources */ get seedSources() { - const seedConfig = _.get(this.config, "seed", {}); + const seedConfig = this.config.seed ?? {}; const seed = this.options.seed || this.config.start.seed || seedConfig; let categories; if (typeof seed === "string") { diff --git a/package-lock.json b/package-lock.json index ad630e8..b4d9feb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,7 @@ "license": "MIT", "dependencies": { "aws-dynamodb-local": "^0.0.11", - "aws-sdk": "^2.7.0", - "bluebird": "^3.4.6", - "lodash": "^4.17.0" + "aws-sdk": "^2.7.0" }, "devDependencies": { "chai": "^4.1.1", @@ -106,11 +104,6 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, - "node_modules/bluebird": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", - "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==" - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -677,7 +670,8 @@ "node_modules/lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true }, "node_modules/log-symbols": { "version": "2.2.0", diff --git a/package.json b/package.json index d9d5270..2a98cbd 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,7 @@ }, "dependencies": { "aws-dynamodb-local": "^0.0.11", - "aws-sdk": "^2.7.0", - "bluebird": "^3.4.6", - "lodash": "^4.17.0" + "aws-sdk": "^2.7.0" }, "devDependencies": { "chai": "^4.1.1", diff --git a/src/seeder.js b/src/seeder.js index 1fce0f4..2c68646 100644 --- a/src/seeder.js +++ b/src/seeder.js @@ -1,16 +1,11 @@ "use strict"; -const BbPromise = require("bluebird"); -const _ = require("lodash"); -const path = require("path"); -const fs = require("fs"); +const path = require("node:path"); +const fs = require("node:fs"); // DynamoDB has a 25 item limit in batch requests // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html const MAX_MIGRATION_CHUNK = 25; -// TODO: let this be configurable -const MIGRATION_SEED_CONCURRENCY = 5; - /** * Writes a batch chunk of migration seeds to DynamoDB. DynamoDB has a limit on the number of * items that may be written in a batch operation. @@ -67,59 +62,36 @@ function writeSeeds(dynamodbWriteFunction, tableName, seeds) { } if (seeds.length > 0) { - const seedChunks = _.chunk(seeds, MAX_MIGRATION_CHUNK); - return BbPromise.map( - seedChunks, - (chunk) => writeSeedBatch(dynamodbWriteFunction, tableName, chunk), - { concurrency: MIGRATION_SEED_CONCURRENCY } - ) + const seedChunks = chunk(seeds, MAX_MIGRATION_CHUNK); + return Promise.all(seedChunks.map((chunk) => writeSeedBatch(dynamodbWriteFunction, tableName, chunk))) .then(() => console.log("Seed running complete for table: " + tableName)); } } -/** - * A promise-based function that determines if a file exists - * @param {string} fileName The path to the file - */ -function fileExists(fileName) { - return new Promise((resolve) => { - fs.exists(fileName, (exists) => resolve(exists)); - }); -} - -/** - * Transform all selerialized Buffer value in a Buffer value inside a json object - * - * @param {json} json with serialized Buffer value. - * @return {json} json with Buffer object. - */ -function unmarshalBuffer(json) { - _.forEach(json, function(value, key) { - // Null check to prevent creation of Buffer when value is null - if (value !== null && value.type==="Buffer") { - json[key]= new Buffer(value.data); - } - }); - return json; -} +const chunk = (input, size) => { + return input.reduce((arr, item, idx) => { + return idx % size === 0 + ? [...arr, [item]] + : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]]; + }, []); +}; /** * Scrapes seed files out of a given location. This file may contain * either a simple json object, or an array of simple json objects. An array * of json objects is returned. * - * @param {any} location the filename to read seeds from. + * @param {string} location the filename to read seeds from. + * @returns {object[]} json */ function getSeedsAtLocation(location) { // load the file as JSON const result = require(location); // Ensure the output is an array - if (Array.isArray(result)) { - return _.forEach(result, unmarshalBuffer); - } else { - return [ unmarshalBuffer(result) ]; - } + const array = Array.isArray(result) ? result : [result]; + + return array; } /** @@ -131,15 +103,12 @@ function locateSeeds(sources, cwd) { cwd = cwd || process.cwd(); const locations = sources.map((source) => path.join(cwd, source)); - return BbPromise.map(locations, (location) => { - return fileExists(location).then((exists) => { - if(!exists) { - throw new Error("source file " + location + " does not exist"); - } - return getSeedsAtLocation(location); - }); - // Smash the arrays together - }).then((seedArrays) => [].concat.apply([], seedArrays)); + return locations.map((location) => { + if(!fs.existsSync(location)) { + throw new Error("source file " + location + " does not exist"); + } + return getSeedsAtLocation(location); + }).flat(1); } module.exports = { writeSeeds, locateSeeds };