From 8a8b5045410d1fa605d7faf08a7c94aa02e33d6b Mon Sep 17 00:00:00 2001 From: Angga Muhammad Date: Sun, 28 Oct 2018 23:15:19 +0700 Subject: [PATCH 1/4] Add google cloud datastore implementation for Lock --- index.yaml | 8 ++ lib/lock/databases/datastore.js | 130 ++++++++++++++++++++++++++++++++ package.json | 3 +- test/unit/aggregateLockTest.js | 2 +- 4 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 index.yaml create mode 100644 lib/lock/databases/datastore.js diff --git a/index.yaml b/index.yaml new file mode 100644 index 0000000..1e32431 --- /dev/null +++ b/index.yaml @@ -0,0 +1,8 @@ +# This is needed for testing google cloud datastore, since a lot of queries are using composite index +# please set up your gcloud-cli, and run "gcloud datastore create-indexes index.yaml" + +indexes: +- kind: aggregatelock + ancestor: yes + properties: + - name: timeStamp \ No newline at end of file diff --git a/lib/lock/databases/datastore.js b/lib/lock/databases/datastore.js new file mode 100644 index 0000000..144deac --- /dev/null +++ b/lib/lock/databases/datastore.js @@ -0,0 +1,130 @@ +var util = require('util'), + Lock = require('../base'), + _ = require('lodash'), + async = require('async'), + DS = require('@google-cloud/datastore'); + +function Datastore(options) { + options = options || {}; + + var dsConf = { + projectId: "" + }; + + this.options = _.defaults(options, dsConf); + + var defaults = { + lockTableName: 'aggregatelock' + }; + + this.options = _.defaults(this.options, defaults); +} + +util.inherits(Datastore, Lock); + +_.extend(Datastore.prototype, { + + AGGREGATE_KIND: "Aggregate", + + connect: function (callback) { + var self = this; + self.client = new DS(self.options); + self.isConnected = true; + + self.emit('connect'); + if (callback) callback(null, self); + }, + + disconnect: function (callback) { + // do nothing on cloud datastore client + this.emit('disconnect'); + if (callback) callback(null); + }, + + reserve: function(workerId, aggregateId, callback) { + var self = this; + var client = self.client; + + var entity = { + key: client.key([self.AGGREGATE_KIND, aggregateId, self.options.lockTableName, workerId]), + data: { + aggregateId: aggregateId, + workerId: workerId, + timeStamp: new Date() + } + }; + + client.save(entity, function(err, apiResponse) { + if(callback) callback(err); + }); + }, + + getAll: function(aggregateId, callback) { + var self = this; + var client = self.client; + + if (callback) { + var q = client + .createQuery(self.options.lockTableName) + .hasAncestor(client.key([self.AGGREGATE_KIND, aggregateId])) + .order("timeStamp"); + + client.runQuery(q, function(err, entities, info) { + if (err) { + return callback(err); + } + + var res = entities.map(function(r){ return r.workerId}); + callback(null, res); + }); + } + }, + + resolve: function(aggregateId, callback) { + var self = this; + var client = self.client; + + var q = client + .createQuery(self.options.lockTableName) + .select('__key__') + .hasAncestor(client.key([self.AGGREGATE_KIND, aggregateId])); + + client.runQuery(q, function(err, entities) { + if (err) { + if (callback) callback(err); + return; + } + + var keys = entities.map(function(r){ return r[client.KEY] }); + + client.delete(keys, function(err) { + if (callback) callback(err); + }); + }); + }, + + clear: function(callback) { + var self = this; + var client = self.client; + + var q = client + .createQuery(self.options.lockTableName) + .select('__key__'); + + client.runQuery(q, function(err, entities) { + if (err) { + if (callback) callback(err); + return; + } + + var keys = entities.map(function(r){ return r[client.KEY] }); + + client.delete(keys, function(err) { + if (callback) callback(err); + }); + }); + } + +}); + +module.exports = Datastore; \ No newline at end of file diff --git a/package.json b/package.json index f1b13d9..ce632a0 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "uuid": "3.1.0" }, "devDependencies": { + "@google-cloud/datastore": "^2.0.0", "aws-sdk": ">=2.96.0", "azure-storage": ">=0.10.0", "cradle": ">=0.6.7", @@ -60,6 +61,6 @@ } ], "scripts": { - "test": "mocha test/unit && mocha test/integration" + "test": "mocha test/unit/aggregateLockTest.js" } } diff --git a/test/unit/aggregateLockTest.js b/test/unit/aggregateLockTest.js index c474a5e..aee6cb3 100644 --- a/test/unit/aggregateLockTest.js +++ b/test/unit/aggregateLockTest.js @@ -77,7 +77,7 @@ describe('AggregateLock', function() { describe('with options containing a type property with the value of', function() { - var types = ['inmemory', 'mongodb', 'tingodb', 'redis', 'dynamodb'/*, 'couchdb', 'azuretable'*/]; + var types = ['inmemory', 'mongodb', 'tingodb', 'redis', 'dynamodb', 'datastore'/*, 'couchdb', 'azuretable'*/]; types.forEach(function(type) { From 10d806a92490e7cc6bf70f98fbcfa3393756dbab Mon Sep 17 00:00:00 2001 From: Angga Muhammad Date: Sun, 28 Oct 2018 23:18:21 +0700 Subject: [PATCH 2/4] bring back all test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce632a0..5fa5dbd 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,6 @@ } ], "scripts": { - "test": "mocha test/unit/aggregateLockTest.js" + "test": "mocha test/unit && mocha test/integration" } } From dc0577fe8d08d5408b90bfc1d017c47bc0282598 Mon Sep 17 00:00:00 2001 From: Angga Muhammad Date: Wed, 31 Oct 2018 00:10:10 +0700 Subject: [PATCH 3/4] move index.yaml (gcloud datastore) into test folder --- index.yaml => test/unit/index.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename index.yaml => test/unit/index.yaml (88%) diff --git a/index.yaml b/test/unit/index.yaml similarity index 88% rename from index.yaml rename to test/unit/index.yaml index 1e32431..5556142 100644 --- a/index.yaml +++ b/test/unit/index.yaml @@ -1,5 +1,5 @@ # This is needed for testing google cloud datastore, since a lot of queries are using composite index -# please set up your gcloud-cli, and run "gcloud datastore create-indexes index.yaml" +# please set up your gcloud-cli, and run "gcloud datastore create-indexes test/unit/index.yaml" indexes: - kind: aggregatelock From 1811aaa9d2a8f3100de218d4f6d76b218dcacefd Mon Sep 17 00:00:00 2001 From: Angga Muhammad Date: Wed, 31 Oct 2018 07:26:24 +0700 Subject: [PATCH 4/4] update readme to include "google cloud datastore" use Lock.use instead of "require" --- README.md | 2 +- lib/lock/databases/datastore.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eda8f94..3ae14f8 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ It can be very useful as domain component if you work with (d)ddd, cqrs, eventde }, // optional, default is in-memory - // currently supports: mongodb, redis, tingodb, couchdb, azuretable, dynamodb and inmemory + // currently supports: mongodb, redis, tingodb, couchdb, azuretable, dynamodb, cloud datastore and inmemory // hint settings like: [eventstore](https://github.com/adrai/node-eventstore#provide-implementation-for-storage) aggregateLock: { type: 'redis', diff --git a/lib/lock/databases/datastore.js b/lib/lock/databases/datastore.js index 144deac..13d5b4b 100644 --- a/lib/lock/databases/datastore.js +++ b/lib/lock/databases/datastore.js @@ -2,7 +2,7 @@ var util = require('util'), Lock = require('../base'), _ = require('lodash'), async = require('async'), - DS = require('@google-cloud/datastore'); + DS = Lock.use('@google-cloud/datastore'); function Datastore(options) { options = options || {};