tapeworm 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  var _ = require('lodash');
2
2
  var Promise = require('bluebird');
3
+ var uuid = require('uuid').v4;
3
4
 
4
5
  var EventStream = require('./event_stream');
5
6
 
@@ -9,40 +10,47 @@ var EventStorePartition = function (partitionId, persistencePartition, dispatchS
9
10
  this._dispatchService = dispatchService;
10
11
 
11
12
  var self = this;
12
- _.forEach(['storeSnapshot', 'loadSnapshot', 'queryStream', 'queryStreamWithSnapshot', 'removeSnapshot'], function (what) {
13
- if (self._persistencePartition[what]) {
14
- self[what] = function () {
15
- return self._persistencePartition[what].apply(self._persistencePartition, arguments);
16
- };
17
- } else {
18
- if (what === 'queryStreamWithSnapshot') {
19
- // fallback function
13
+ _.forEach(
14
+ ['storeSnapshot', 'loadSnapshot', 'queryStream', 'queryStreamWithSnapshot', 'removeSnapshot', 'getLatestCommit', 'querySnapshotsByMaxDateTime'],
15
+ function (what) {
16
+ if (self._persistencePartition[what]) {
20
17
  self[what] = function () {
21
- return self._queryStreamWithSnapshotFallback.apply(self._persistencePartition, arguments);
18
+ return self._persistencePartition[what].apply(self._persistencePartition, arguments);
22
19
  };
20
+ } else {
21
+ if (what === 'queryStreamWithSnapshot') {
22
+ // fallback function
23
+ self[what] = function () {
24
+ return self._queryStreamWithSnapshotFallback.apply(self._persistencePartition, arguments);
25
+ };
26
+ }
23
27
  }
24
28
  }
25
- })
29
+ );
26
30
  };
27
31
 
28
- EventStorePartition.prototype.openStream = function(streamId, callback) {
29
- var stream = new EventStream(this, streamId);
32
+ EventStorePartition.prototype.openStream = function (streamId, writeOnly, callback) {
33
+ if (typeof writeOnly === 'function') {
34
+ callback = writeOnly;
35
+ writeOnly = false;
36
+ }
37
+ var stream = new EventStream(this, streamId, writeOnly);
30
38
  return stream._prepareStream(callback);
31
39
  };
32
40
 
33
- EventStorePartition.prototype.append = function(commits, callback) {
41
+ EventStorePartition.prototype.append = function (commits, callback) {
34
42
  //pre hooks
35
43
  var self = this;
36
44
 
37
- if(!_.isArray(commits)) {
45
+ if (!_.isArray(commits)) {
38
46
  commits = [commits];
39
47
  }
40
- return Promise.each(commits, function(commit) {
41
- return self._persistencePartition.append(commit, callback).then(function(r) {
42
- var done = function() {
48
+ return Promise.each(commits, function (commit) {
49
+ return self._persistencePartition.append(commit, callback).then(function (r) {
50
+ var done = function () {
43
51
  self._persistencePartition.markAsDispatched(commit);
44
- }
45
- if(self._dispatchService) {
52
+ };
53
+ if (self._dispatchService) {
46
54
  self._dispatchService(commit, done);
47
55
  }
48
56
  return r;
@@ -50,46 +58,82 @@ EventStorePartition.prototype.append = function(commits, callback) {
50
58
  });
51
59
  //post hooks
52
60
  };
61
+ /**
62
+ * Delete function in tapeworm,
63
+ * Delete should trigger a $stream.deleted.event, including aggregateType of first event and publish it.
64
+ * 2. Implement in projector service to listen to this event and then do a delete of all related projections.,
65
+ * 3. Delete function should store the following new commit (deleted event) under the stream:
66
+ * streamId,
67
+ * aggregateType,
68
+ * date of deletion,
69
+ * date of creation,
70
+ * principal
71
+ * 4. Then remove snapshot for this stream and all commits for this stream.
72
+ * @param {*} streamId
73
+ * @param {*} deleteEvent optional delete event
74
+ */
75
+ EventStorePartition.prototype.delete = function (streamId, deleteEvent) {
76
+ var self = this;
77
+ var event = Object.assign({}, deleteEvent, {
78
+ type: '$stream.deleted.event',
79
+ payload: Object.assign({}, { dateOfDeletion: new Date() }, (deleteEvent && deleteEvent.payload) || {})
80
+ });
81
+ return this._truncateStreamFrom(streamId, -1)
82
+ .then(function (result) {
83
+ return self.openStream(streamId, false);
84
+ })
85
+ .then(function (stream) {
86
+ stream.append(event);
87
+ return stream.commit(uuid());
88
+ })
89
+ .then(function () {
90
+ // support legacy/unsupported approach
91
+ if (self._persistencePartition.removeSnapshot) {
92
+ return self._persistencePartition.removeSnapshot(streamId);
93
+ } else if (self._persistencePartition.removeSnapshots) {
94
+ return self._persistencePartition.removeSnapshots([streamId]);
95
+ }
96
+ });
97
+ };
53
98
 
54
99
  /*** UNDOCUMENTED API ***/
55
100
 
56
- EventStorePartition.prototype._queryStream = function(streamId, callback) {
101
+ EventStorePartition.prototype._queryStream = function (streamId, callback) {
57
102
  return this._persistencePartition.queryStream(streamId, callback);
58
103
  };
59
104
 
60
- EventStorePartition.prototype._queryAll = function(callback) {
105
+ EventStorePartition.prototype._queryAll = function (callback) {
61
106
  return this._persistencePartition.queryAll(callback);
62
107
  };
63
108
 
64
- EventStorePartition.prototype._queryStreamWithSnapshotFallback = function(streamId, callback) {
109
+ EventStorePartition.prototype._queryStreamWithSnapshotFallback = function (streamId, callback) {
65
110
  var self = this;
66
111
  return new Promise(function (resolve, reject) {
67
112
  self.loadSnapshot(streamId, function (err, snapshot) {
68
113
  if (err) {
69
- reject(err)
114
+ reject(err);
70
115
  } else {
71
- var snapshotVersion = snapshot && snapshot.version || -1;
116
+ var snapshotVersion = (snapshot && snapshot.version) || -1;
72
117
  self.queryStream(streamId, snapshotVersion, function (err, res) {
73
- resolve({ snapshot: snapshot, commits: res })
74
- })
118
+ resolve({ snapshot: snapshot, commits: res });
119
+ });
75
120
  }
76
- })
121
+ });
77
122
  }).nodeify(callback);
78
123
  };
79
124
 
80
125
  /*** NEEDED FOR SYNCING ***/
81
126
 
82
- EventStorePartition.prototype._truncateStreamFrom = function(streamId, commitSequence, callback) {
127
+ EventStorePartition.prototype._truncateStreamFrom = function (streamId, commitSequence, callback) {
83
128
  return this._persistencePartition.truncateStreamFrom(streamId, commitSequence, callback);
84
- }
129
+ };
85
130
 
86
- EventStorePartition.prototype._applyCommitHeader = function(commit, header, callback) {
131
+ EventStorePartition.prototype._applyCommitHeader = function (commit, header, callback) {
87
132
  return this._persistencePartition.applyCommitHeader(commit, header, callback);
88
- }
133
+ };
89
134
 
90
135
  //EventStorePartition.prototype.loadEvents = function(streamId, callback)
91
136
 
92
-
93
137
  /*EventStorePartition.prototype.append = function(streamId, expectedVersion, events) {
94
138
  var commit = new Commit(uuid(), this._partitionId, streamId, expectedVersion, events);
95
139
  return this._persistencePartition.append(commit).then(function()
@@ -101,4 +145,4 @@ EventStorePartition.prototype._applyCommitHeader = function(commit, header, call
101
145
  };
102
146
  */
103
147
 
104
- module.exports = EventStorePartition;
148
+ module.exports = EventStorePartition;
@@ -2,104 +2,146 @@ var Promise = require('bluebird');
2
2
  var Commit = require('./persistence/commit');
3
3
  var _ = require('lodash');
4
4
 
5
- var EventStream = function(eventPartition, streamId) {
6
- if(streamId === undefined) {
7
- throw new Error('StreamId must be defined!');
8
- }
9
- this._partition = eventPartition;
10
- this._streamId = streamId;
11
-
12
- this._uncommittedEvents = [];
13
- this._version = 0;
14
- // this._prepareStream();
15
- }
16
-
17
- EventStream.prototype._prepareStream = function(callback) {
18
- this._committedEvents = [];
19
- this._commitSequence = -1;
20
- var self = this;
21
-
22
- return this._partition._queryStream(this._streamId, callback).then(function(commits) {
23
- self._version = 0;
24
-
25
- if(!commits || commits.length === 0) {
5
+ // writeOnly - will never read entire stream from
6
+ var EventStream = function (eventPartition, streamId, writeOnly) {
7
+ if (streamId === undefined) {
8
+ throw new Error('StreamId must be defined!');
9
+ }
10
+ this._partition = eventPartition;
11
+ this._streamId = streamId;
12
+ this._writeOnly = writeOnly;
13
+ this._uncommittedEvents = [];
14
+ this._committedEvents = [];
15
+ this._version = 0;
16
+ this._isDeleted = false;
17
+ };
26
18
 
27
- commits = [];
28
- self._version = -1;
29
- }
30
- var version = 0
31
- for(var i=0; i<commits.length; i++) {
32
- //console.log('found commit' + commit);
33
- self._commitSequence++;
34
- for(var j=0;j<commits[i].events.length;j++) {
35
- self._version++;
36
- commits[i].events[j].version = version++;
37
- self._committedEvents.push(commits[i].events[j]);
38
- }
39
- }
40
- }).then(function(){
41
- return self;
42
- });
19
+ EventStream.prototype._prepareStream = function (callback) {
20
+ this._committedEvents = [];
21
+ this._commitSequence = -1;
22
+ var self = this;
23
+ if (self._writeOnly === true && self._partition.getLatestCommit) {
24
+ // if stream should only be opened for appending commits, only really care about getting the correct commitSequence (from last commit)
25
+ return self._partition
26
+ .getLatestCommit(self._streamId)
27
+ .then(function (commit) {
28
+ if (commit) {
29
+ self._commitSequence = commit.commitSequence;
30
+ var lastEvent = commit.events[commit.events.length - 1];
31
+ if (lastEvent && lastEvent.type === '$stream.deleted.event') {
32
+ self._isDeleted = true;
33
+ }
34
+ self._version = lastEvent.version + 1;
35
+ }
36
+ // if no commit is found, assume its a new stream, and keep default versions
37
+ })
38
+ .then(function () {
39
+ return self;
40
+ });
41
+ } else {
42
+ return self._partition
43
+ ._queryStream(self._streamId, callback)
44
+ .then(function (commits) {
45
+ self._version = 0;
46
+
47
+ if (!commits || commits.length === 0) {
48
+ commits = [];
49
+ self._version = -1;
50
+ } else {
51
+ if (commits[0] && commits[0].events && commits[0].events[0] && commits[0].events[0].type === '$stream.deleted.event') {
52
+ throw new Error('Stream is deleted');
53
+ }
54
+ }
55
+ var version = 0;
56
+ for (var i = 0; i < commits.length; i++) {
57
+ self._commitSequence++;
58
+ for (var j = 0; j < commits[i].events.length; j++) {
59
+ self._version++;
60
+ commits[i].events[j].version = version++;
61
+ self._committedEvents.push(commits[i].events[j]);
62
+ }
63
+ }
64
+ })
65
+ .then(function () {
66
+ return self;
67
+ });
68
+ }
43
69
  };
44
70
 
45
- EventStream.prototype.getVersion = function() {
46
- return this._version;
71
+ EventStream.prototype.getVersion = function () {
72
+ return this._version;
47
73
  };
48
74
 
49
- EventStream.prototype.append = function(event) {
50
- this._uncommittedEvents.push(event);
75
+ EventStream.prototype.append = function (event) {
76
+ this._uncommittedEvents.push(event);
51
77
  };
52
78
 
53
- EventStream.prototype.hasChanges = function() {
54
- return this._uncommittedEvents.length > 0;
79
+ EventStream.prototype.hasChanges = function () {
80
+ return this._uncommittedEvents.length > 0;
55
81
  };
56
82
 
57
- EventStream.prototype.commit = function(commitId, callback) {
58
- var self = this;
59
- if(!this.hasChanges()) {
60
- //nothing to commit
61
- return Promise.resolve().nodeify(callback);
62
- } else {
63
- var commit = this._buildCommit(commitId, this._uncommittedEvents);
64
-
65
- return this._partition.append(commit, callback).then(function(commit) {
66
- self._clearChanges();
67
- //rebuild local state
68
- return self._prepareStream(callback);
69
- });
70
- }
71
- }
83
+ EventStream.prototype.commit = function (commitId, callback) {
84
+ var self = this;
85
+
86
+ if(this._isDeleted) {
87
+ throw new Error('Stream is deleted, unable to commit: ' + this._uncommittedEvents.map(function(event) {return event.type}) );
88
+ }
89
+
90
+ if (!this.hasChanges()) {
91
+ //nothing to commit
92
+ return Promise.resolve().nodeify(callback);
93
+ } else {
94
+ var commit = this._buildCommit(commitId, this._uncommittedEvents);
95
+ return this._partition.append(commit, callback).then(function (commit) {
96
+ //rebuild local state
97
+ var events = self._uncommittedEvents;
98
+ self._version = events[events.length - 1].version + 1;
99
+ if (self._writeOnly === true) {
100
+ self._commitSequence++;
101
+ self._clearChanges();
102
+ } else {
103
+ for (var i = 0; i < events.length; i++) {
104
+ self._committedEvents.push(events[i]);
105
+ }
106
+ self._clearChanges();
107
+ self._commitSequence++;
108
+ return self;
109
+ }
110
+ });
111
+ }
112
+ };
72
113
 
73
- EventStream.prototype._clearChanges = function() {
74
- this._uncommittedEvents = [];
114
+ EventStream.prototype._clearChanges = function () {
115
+ this._uncommittedEvents = [];
75
116
  };
76
117
 
77
- EventStream.prototype.revertChanges = function() {
78
- //trunc the uncomitted events log
79
- var arr = this._uncommittedEvents;
80
- this._uncommittedEvents = [];
81
- delete arr;
118
+ EventStream.prototype.revertChanges = function () {
119
+ //trunc the uncomitted events log
120
+ var arr = this._uncommittedEvents;
121
+ this._uncommittedEvents = [];
122
+ delete arr;
82
123
  };
83
124
 
125
+ EventStream.prototype._buildCommit = function (commitId, events) {
126
+ var commitSequence = this._commitSequence;
127
+ var commit = new Commit(commitId, this._partition._partitionId, this._streamId, ++commitSequence, events);
128
+ var version = this._version == -1 ? 0 : this._version;
84
129
 
85
- EventStream.prototype._buildCommit = function(commitId, events) {
86
- var commitSequence = this._commitSequence;
87
- var commit = new Commit(commitId, this._partition._partitionId, this._streamId, ++commitSequence, events);
88
- var version = this._version == -1 ? 0 : this._version;
89
-
90
- _.forEach(events, function(evt) {
91
- evt.version = version++;
92
- })
93
- return commit;
130
+ _.forEach(events, function (evt) {
131
+ evt.version = version++;
132
+ });
133
+ return commit;
94
134
  };
95
135
 
96
- EventStream.prototype.getCommittedEvents = function() {
97
- return this._committedEvents.slice();
136
+ EventStream.prototype.getCommittedEvents = function () {
137
+ if (this._writeOnly) {
138
+ throw new Error('Cannot access committed events when using writeOnly mode...');
139
+ }
140
+ return this._committedEvents.slice();
98
141
  };
99
142
 
100
- EventStream.prototype.getUncommittedEvents = function() {
101
- return this._uncommittedEvents.slice();
143
+ EventStream.prototype.getUncommittedEvents = function () {
144
+ return this._uncommittedEvents.slice();
102
145
  };
103
146
 
104
-
105
- module.exports = EventStream;
147
+ module.exports = EventStream;
@@ -9,8 +9,7 @@ var InMemoryPartition = function () {
9
9
  this._commitIds = [];
10
10
  this._commitConcurrencyCheck = [];
11
11
  this._snapshots = {};
12
- }
13
-
12
+ };
14
13
 
15
14
  function getConcurrencyKey(commit) {
16
15
  return commit.streamId + '-' + commit.commitSequence;
@@ -21,7 +20,7 @@ InMemoryPartition.prototype._promisify = function (value, callback) {
21
20
 
22
21
  InMemoryPartition.prototype.truncateStreamFrom = function (streamId, commitSequence, callback) {
23
22
  var self = this;
24
- var commits = this._streamIndex[streamId];
23
+ var commits = Array.from(this._streamIndex[streamId]);
25
24
  for (var i = 0; i < commits.length; i++) {
26
25
  var commit = commits[i];
27
26
 
@@ -30,12 +29,17 @@ InMemoryPartition.prototype.truncateStreamFrom = function (streamId, commitSeque
30
29
  self._commitIds = _.without(self._commitIds, commit.id);
31
30
  self._commitConcurrencyCheck = _.without(self._commitConcurrencyCheck, getConcurrencyKey(commit));
32
31
  self._commits = _.without(self._commits, commit);
32
+ // i--;
33
33
  }
34
34
  }
35
- commits = commits.slice(0, commitSequence);
35
+ commits = commits.slice(0, Math.max(commitSequence, 0));
36
36
  this._streamIndex[streamId] = commits;
37
37
  return this._promisify(this);
38
- }
38
+ };
39
+
40
+ // InMemoryPartition.prototype.delete = function (streamId, headers, callback) {
41
+
42
+ // }
39
43
 
40
44
  InMemoryPartition.prototype.applyCommitHeader = function (commitId, header, callback) {
41
45
  var self = this;
@@ -43,17 +47,16 @@ InMemoryPartition.prototype.applyCommitHeader = function (commitId, header, call
43
47
  if (commit) {
44
48
  _.assign(commit, header);
45
49
  } else {
46
- throw new Error("Trying to apply header to missing commit: " + commitId);
50
+ throw new Error('Trying to apply header to missing commit: ' + commitId);
47
51
  }
48
52
  return this._promisify(commit, callback);
49
- }
50
-
53
+ };
51
54
 
52
55
  InMemoryPartition.prototype.append = function (commit, callback) {
53
56
  commit.isDispatched = false;
54
57
  //check for duplicates
55
58
  if (_.contains(this._commitIds, commit.id)) {
56
- throw new DuplicateCommitError("Duplicate commit of " + commit.id);
59
+ throw new DuplicateCommitError('Duplicate commit of ' + commit.id);
57
60
  }
58
61
  var concurrencyKey = getConcurrencyKey(commit);
59
62
  if (_.contains(this._commitConcurrencyCheck, concurrencyKey)) {
@@ -72,7 +75,7 @@ InMemoryPartition.prototype.append = function (commit, callback) {
72
75
  };
73
76
 
74
77
  InMemoryPartition.prototype.storeSnapshot = function (streamId, snapshot, version, callback) {
75
- return this._promisify(this._snapshots[streamId] = { id: streamId, version: version, snapshot: snapshot }, callback);
78
+ return this._promisify((this._snapshots[streamId] = { id: streamId, version: version, snapshot: snapshot }), callback);
76
79
  };
77
80
 
78
81
  // Loads the latest snapshot
@@ -100,6 +103,14 @@ InMemoryPartition.prototype.queryAll = function (callback) {
100
103
  return this._promisify(this._commits.slice(), callback);
101
104
  };
102
105
 
106
+ InMemoryPartition.prototype.getLatestCommit = function (streamId, callback) {
107
+ var result = this._streamIndex[streamId];
108
+ if (result) {
109
+ result = result.slice().pop();
110
+ }
111
+ return this._promisify(result, callback);
112
+ };
113
+
103
114
  InMemoryPartition.prototype.queryStream = function (streamId, fromEventSequence, callback) {
104
115
  if (_.isFunction(fromEventSequence)) {
105
116
  callback = fromEventSequence;
@@ -132,4 +143,4 @@ InMemoryPartition.prototype.queryStream = function (streamId, fromEventSequence,
132
143
  return this._promisify(result, callback);
133
144
  };
134
145
 
135
- module.exports = InMemoryPartition;
146
+ module.exports = InMemoryPartition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tapeworm",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -24,6 +24,7 @@
24
24
  "event",
25
25
  "store"
26
26
  ],
27
+ "prettier": "prettier-config-surikaterna",
27
28
  "author": "",
28
29
  "license": "MIT",
29
30
  "devDependencies": {
@@ -33,11 +34,13 @@
33
34
  "eslint-plugin-react": "^3.3.1",
34
35
  "istanbul": "^0.3.2",
35
36
  "mocha": "^2.0.1",
36
- "should": "^4.1.0"
37
+ "should": "^4.1.0",
38
+ "prettier": "^2.1.2",
39
+ "prettier-config-surikaterna": "^1.0.1"
37
40
  },
38
41
  "dependencies": {
39
42
  "bluebird": "^2.5.2",
40
- "lodash": "^2.4.1",
41
- "node-uuid": "^1.4.2"
43
+ "lodash": "^2.4.2",
44
+ "uuid": "^8.3.2"
42
45
  }
43
46
  }
@@ -1,103 +1,115 @@
1
1
  var should = require('should');
2
2
  var Promise = require('bluebird');
3
- var uuid = require('node-uuid').v4;
3
+ var uuid = require('uuid').v4;
4
4
 
5
5
  var EventStore = require('..');
6
6
  var Commit = EventStore.Commit;
7
7
 
8
- describe('Partition', function() {
9
- describe('#append', function(done) {
10
- it('should return commit if added', function(done) {
11
- var es = new EventStore();
12
- es.openPartition('location').then(function(partition) {
13
- partition.append(new Commit('1', 'location', '1', 0, [])).then(function(c) {
14
- c[0].events.length.should.equal(0);
15
- done();
16
- });
17
- }).catch(function(err) {
18
- done(err);
19
- });
20
- });
21
- it('should return after all commits are persisted', function(done) {
22
- var es = new EventStore();
23
- es.openPartition('location').then(function(partition) {
24
- return partition.append([new Commit('1', 'location', '1', 0, []), new Commit('2', 'location', '1', 1, [])]).then(function(c) {
25
- c.length.should.equal(2);
26
- done();
27
- });
28
- }).catch(function(err) {
29
- done(err);
30
- });
31
- });
32
- });
33
- describe('#_truncateStreamFrom', function() {
34
- it('should remove all commits ', function(done) {
35
- var es = new EventStore();
36
- es.openPartition('location').then(function(partition) {
37
- return partition.append([new Commit('1', 'location', '1', 0, []), new Commit('2', 'location', '1', 1, [])]).then(function(c) {
38
- return partition._truncateStreamFrom('1', 0).then(function() {
39
- return partition.openStream('1').then(function(stream) {
40
- stream.getVersion().should.equal(-1);
41
- done();
42
- });
43
- });
44
- });
45
- }).catch(function(err) {
46
- done(err);
47
- });
48
- });
49
- it('should remove all commits after commitSequence', function(done) {
50
- var es = new EventStore();
51
- es.openPartition('location').then(function(partition) {
52
- return partition.append([new Commit('1', 'location', '1', 0, [{}]), new Commit('2', 'location', '1', 1, [{}])]).then(function(c) {
53
- return partition._truncateStreamFrom('1', 1).then(function() {
54
- return partition.openStream('1').then(function(stream) {
55
- stream.getVersion().should.equal(1);
56
- done();
57
- });
58
- });
59
- });
60
- }).catch(function(err) {
61
- done(err);
62
- });
63
- });
64
- });
65
- describe('#_applyCommitHeader', function() {
66
- it('should add to commit ', function(done) {
67
- var es = new EventStore();
68
- es.openPartition('location').then(function(partition) {
69
- var commit = new Commit('1', 'location', '1', 0, []);
70
- return partition.append([commit, new Commit('2', 'location', '1', 1, [])]).then(function(c) {
71
- return partition._applyCommitHeader(commit.id, {authorative:true}).then(function(commit) {
72
- commit.authorative.should.be.ok;
73
- done();
74
- });
75
- });
76
- }).catch(function(err) {
77
- done(err);
78
- });
79
- });
80
- it('should throw if commit id is unknown', function(done) {
81
- var es = new EventStore();
82
- es.openPartition('location').then(function(partition) {
83
- var commit = new Commit('1', 'location', '1', 0, []);
84
- return partition.append([commit, new Commit('2', 'location', '1', 1, [])]).then(function(c) {
85
- return partition._applyCommitHeader("ID MISSING", {authorative:true}).then(function(commit) {
86
- done(new Error("Unreachable code"));
87
-
88
- });
89
- });
90
- }).catch(function(err) {
91
- done();
92
- });
93
- });
94
- });
8
+ describe('Partition', function () {
9
+ describe('#append', function (done) {
10
+ it('should return commit if added', function (done) {
11
+ var es = new EventStore();
12
+ es.openPartition('location')
13
+ .then(function (partition) {
14
+ partition.append(new Commit('1', 'location', '1', 0, [])).then(function (c) {
15
+ c[0].events.length.should.equal(0);
16
+ done();
17
+ });
18
+ })
19
+ .catch(function (err) {
20
+ done(err);
21
+ });
22
+ });
23
+ it('should return after all commits are persisted', function (done) {
24
+ var es = new EventStore();
25
+ es.openPartition('location')
26
+ .then(function (partition) {
27
+ return partition.append([new Commit('1', 'location', '1', 0, []), new Commit('2', 'location', '1', 1, [])]).then(function (c) {
28
+ c.length.should.equal(2);
29
+ done();
30
+ });
31
+ })
32
+ .catch(function (err) {
33
+ done(err);
34
+ });
35
+ });
36
+ });
37
+ describe('#_truncateStreamFrom', function () {
38
+ it('should remove all commits ', function (done) {
39
+ var es = new EventStore();
40
+ es.openPartition('location')
41
+ .then(function (partition) {
42
+ return partition.append([new Commit('1', 'location', '1', 0, []), new Commit('2', 'location', '1', 1, [])]).then(function (c) {
43
+ return partition._truncateStreamFrom('1', 0).then(function () {
44
+ return partition.openStream('1').then(function (stream) {
45
+ stream.getVersion().should.equal(-1);
46
+ done();
47
+ });
48
+ });
49
+ });
50
+ })
51
+ .catch(function (err) {
52
+ done(err);
53
+ });
54
+ });
55
+ it('should remove all commits after commitSequence', function (done) {
56
+ var es = new EventStore();
57
+ es.openPartition('location')
58
+ .then(function (partition) {
59
+ return partition.append([new Commit('1', 'location', '1', 0, [{}]), new Commit('2', 'location', '1', 1, [{}])]).then(function (c) {
60
+ return partition._truncateStreamFrom('1', 1).then(function () {
61
+ return partition.openStream('1').then(function (stream) {
62
+ stream.getVersion().should.equal(1);
63
+ done();
64
+ });
65
+ });
66
+ });
67
+ })
68
+ .catch(function (err) {
69
+ done(err);
70
+ });
71
+ });
72
+ });
73
+ describe('#_applyCommitHeader', function () {
74
+ it('should add to commit ', function (done) {
75
+ var es = new EventStore();
76
+ es.openPartition('location')
77
+ .then(function (partition) {
78
+ var commit = new Commit('1', 'location', '1', 0, []);
79
+ return partition.append([commit, new Commit('2', 'location', '1', 1, [])]).then(function (c) {
80
+ return partition._applyCommitHeader(commit.id, { authorative: true }).then(function (commit) {
81
+ commit.authorative.should.be.ok;
82
+ done();
83
+ });
84
+ });
85
+ })
86
+ .catch(function (err) {
87
+ done(err);
88
+ });
89
+ });
90
+ it('should throw if commit id is unknown', function (done) {
91
+ var es = new EventStore();
92
+ es.openPartition('location')
93
+ .then(function (partition) {
94
+ var commit = new Commit('1', 'location', '1', 0, []);
95
+ return partition.append([commit, new Commit('2', 'location', '1', 1, [])]).then(function (c) {
96
+ return partition._applyCommitHeader('ID MISSING', { authorative: true }).then(function (commit) {
97
+ done(new Error('Unreachable code'));
98
+ });
99
+ });
100
+ })
101
+ .catch(function (err) {
102
+ done();
103
+ });
104
+ });
105
+ });
95
106
  describe('#queryStreamWithSnapshot', function () {
96
107
  it('queryStreamWithSnapshot should return snapshot and missing commits', function (done) {
97
108
  var es = new EventStore();
98
109
  var streamId = '1';
99
110
  var stream;
100
- es.openPartition('location').call('openStream', streamId)
111
+ es.openPartition('location')
112
+ .call('openStream', streamId)
101
113
  .then(function (stream1) {
102
114
  stream = stream1;
103
115
  stream.append({ event: '123' });
@@ -118,16 +130,18 @@ describe('Partition', function() {
118
130
  res.commits[0].events.length.should.eql(2);
119
131
  res.commits[0].events[0].version.should.eql(2);
120
132
  done();
121
- })
122
- })
123
- }).catch(function (err) {
124
- done(err);
125
- });
133
+ });
134
+ });
135
+ })
136
+ .catch(function (err) {
137
+ done(err);
138
+ });
126
139
  });
127
140
  it('queryStreamWithSnapshot should return snapshot and no commit if up to date', function (done) {
128
141
  var es = new EventStore();
129
142
  var streamId = '1';
130
- es.openPartition('location').call('openStream', streamId)
143
+ es.openPartition('location')
144
+ .call('openStream', streamId)
131
145
  .then(function (stream) {
132
146
  stream.append({ event: '123' });
133
147
  stream.append({ event: '999' });
@@ -140,12 +154,79 @@ describe('Partition', function() {
140
154
  res.snapshot.version.should.eql(2);
141
155
  res.commits.length.should.eql(0);
142
156
  done();
143
- })
144
- })
145
- }).catch(function (err) {
146
- done(err);
147
- });
157
+ });
158
+ });
159
+ })
160
+ .catch(function (err) {
161
+ done(err);
162
+ });
148
163
  });
149
164
  });
165
+ describe('#delete', function () {
166
+ it('should delete stream and all commits', function (done) {
167
+ var didIGetaDeleteEvent = false;
168
+ var es = new EventStore(null, (commit) => {
169
+ if (commit.events[0].type === '$stream.deleted.event') {
170
+ didIGetaDeleteEvent = true;
171
+ }
172
+ });
173
+ es.openPartition('location')
174
+ .then(function (partition) {
175
+ return partition
176
+ .append([new Commit('1', 'location', '1', 0, [{ type: 'dummy.event' }]), new Commit('2', 'location', '1', 1, [{ type: 'dummy2.event' }])])
177
+ .then(function (c) {
178
+ return partition.delete('1', { some: 'header-value', payload: { test: true }, type: 'fail' }).then(function () {
179
+ return partition
180
+ .openStream('1')
181
+ .then(function (stream) {
182
+ console.log(JSON.stringify(stream, null, 2));
183
+ done(new Error('able to open deleted stream'));
184
+ })
185
+ .catch(function (error) {
186
+ error.message.should.equal('Stream is deleted');
187
+ didIGetaDeleteEvent.should.be.true;
188
+ done();
189
+ });
190
+ });
191
+ });
192
+ })
193
+ .catch(function (err) {
194
+ done(err);
195
+ });
196
+ });
150
197
 
198
+ it('should delete and placeholder commit should have an id', function (done) {
199
+ var didIGetaDeleteEvent = false;
200
+ var es = new EventStore(null, (commit) => {
201
+ console.log(commit.id);
202
+ if (commit.events[0].type === '$stream.deleted.event' && commit.id) {
203
+ didIGetaDeleteEvent = true;
204
+ }
205
+ should(commit.id).not.be.null;
206
+ });
207
+ es.openPartition('location')
208
+ .then(function (partition) {
209
+ return partition
210
+ .append([new Commit('1', 'location', '1', 0, [{ type: 'dummy.event' }]), new Commit('2', 'location', '1', 1, [{ type: 'dummy2.event' }])])
211
+ .then(function (c) {
212
+ return partition.delete('1', { some: 'header-value', payload: { test: true }, type: 'fail' }).then(function () {
213
+ return partition
214
+ .openStream('1')
215
+ .then(function (stream) {
216
+ console.log(JSON.stringify(stream, null, 2));
217
+ done(new Error('able to open deleted stream'));
218
+ })
219
+ .catch(function (error) {
220
+ error.message.should.equal('Stream is deleted');
221
+ didIGetaDeleteEvent.should.be.true;
222
+ done();
223
+ });
224
+ });
225
+ });
226
+ })
227
+ .catch(function (err) {
228
+ done(err);
229
+ });
230
+ });
231
+ });
151
232
  });
@@ -1,6 +1,6 @@
1
1
  var should = require('should');
2
2
  var Promise = require('bluebird');
3
- var uuid = require('node-uuid').v4;
3
+ var uuid = require('uuid').v4;
4
4
 
5
5
  var EventStore = require('..');
6
6
  var EventStream = require('../lib/event_stream');
@@ -111,6 +111,31 @@ describe('event_stream', function () {
111
111
  done(err);
112
112
  });
113
113
  });
114
+ it('event stream writeOnly', function (done) {
115
+ var es = new EventStore();
116
+ var stream;
117
+ es.openPartition('location').then(function (partition) {
118
+ partition.openStream('1', true)
119
+ .then(function (stream1) {
120
+ stream = stream1;
121
+ stream.append({ event: '123' });
122
+ return stream.commit(uuid());
123
+ })
124
+ .then(function () {
125
+ stream._commitSequence.should.equal(0);
126
+ stream.append({ event: '666' });
127
+ stream.append({ event: '777' });
128
+ return stream.commit(uuid());
129
+ })
130
+ .then(function () {
131
+ stream._commitSequence.should.equal(1);
132
+ done();
133
+ })
134
+ .catch(function (err) {
135
+ done(err);
136
+ });
137
+ });
138
+ });
114
139
  it('committed events should have increasing version', function (done) {
115
140
  var es = new EventStore();
116
141
  var stream;
@@ -127,11 +152,37 @@ describe('event_stream', function () {
127
152
  })
128
153
  .then(function () {
129
154
  stream.getCommittedEvents()[3].version.should.equal(3);
155
+ stream._version.should.equal(4);
130
156
  done();
131
157
  }).catch(function (err) {
132
158
  done(err);
133
159
  });
134
160
  });
161
+ it('committed events should have increasing version (writeOnly)', function (done) {
162
+ var es = new EventStore();
163
+ var stream;
164
+ es.openPartition('location').then(function (partition) {
165
+ partition.openStream('1', true)
166
+ .then(function (stream1) {
167
+ stream = stream1;
168
+ stream.append({ event: '123' });
169
+ stream.append({ event: '999' });
170
+ return stream.commit(uuid());
171
+ })
172
+ .then(function () {
173
+ stream.append({ event: '666' });
174
+ stream.append({ event: '777' });
175
+ return stream.commit(uuid());
176
+ })
177
+ .then(function () {
178
+ stream._version.should.equal(4);
179
+ done();
180
+ })
181
+ .catch(function (err) {
182
+ done(err);
183
+ });
184
+ });
185
+ });
135
186
  it('published events should have increasing version', function (done) {
136
187
  var commitCount = 0;
137
188
 
@@ -160,4 +211,4 @@ describe('event_stream', function () {
160
211
  });
161
212
  });
162
213
  });
163
- });
214
+ });
@@ -1,5 +1,5 @@
1
1
  var should = require('should');
2
- var uuid = require("node-uuid").v4;
2
+ var uuid = require("uuid").v4;
3
3
  var Promise = require("bluebird");
4
4
 
5
5
  var Store = require('../../lib/persistence/inmemory/inmemory_persistence');