tapeworm 0.4.0 → 0.5.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.
package/README.md CHANGED
@@ -1,4 +1,332 @@
1
- [![Build Status](https://travis-ci.org/spralle/rec.svg?branch=master)](https://travis-ci.org/spralle/rec)
2
- # Tapeworm - Tape Write Once Read Many
1
+ Tapeworm
2
+ ========
3
3
 
4
- Event sourcing for Node and Browserify
4
+ [Tape Write Once, Read Many](https://github.com/surikaterna/tapeworm) is a library for event sourcing for in Node.
5
+
6
+ * [Purpose](#purpose)
7
+ * [Installation](#installation)
8
+ * [Usage](#usage)
9
+ * [In Memory](#in-memory)
10
+ * [Custom Partition](#custom-partition)
11
+ * [Components](#components)
12
+ * [EventStore](#eventstore)
13
+ * [Methods](#methods)
14
+ * [openPartition](#openpartition)
15
+ * [EventStorePartition](#eventstorepartition)
16
+ * [Methods](#methods-1)
17
+ * [openStream](#openstream)
18
+ * [append](#append)
19
+ * [delete](#delete)
20
+ * [Persistence Partition Wrapper Methods](#persistence-partition-wrapper-methods)
21
+ * [queryStreamWithSnapshot](#querystreamwithsnapshot)
22
+ * [storeSnapshot](#storesnapshot)
23
+ * [loadSnapshot](#loadsnapshot)
24
+ * [queryStream](#querystream)
25
+ * [removeSnapshot](#removesnapshot)
26
+ * [getLatestCommit](#getlatestcommit)
27
+ * [querySnapshotsByMaxDateTime](#querysnapshotsbymaxdatetime)
28
+ * [EventStream](#eventstream)
29
+ * [Methods](#methods-2)
30
+ * [getVersion](#getversion)
31
+ * [append](#append-1)
32
+ * [hasChanges](#haschanges)
33
+ * [commit](#commit)
34
+ * [revertChanges](#revertchanges)
35
+ * [getCommittedEvents](#getcommittedevents)
36
+ * [getUncommittedEvents](#getuncommittedevents)
37
+ * [Commit](#commit-1)
38
+ * [Event](#event)
39
+
40
+ # Purpose
41
+
42
+ Tapeworm is an event store, configurable with an external persistence partition. By default it provides its own in
43
+ memory persistence partition, but it can be exchanged by e.g.
44
+ a [MongoDB persistence partition](https://github.com/surikaterna/tapeworm_persistence_store_mongodb) or
45
+ an [IndexedDB persistence partition](https://github.com/surikaterna/tapeworm_persistence_store_indexdb).
46
+
47
+ # Installation
48
+
49
+ ```shell
50
+ npm install tapeworm
51
+ ```
52
+
53
+ # Usage
54
+
55
+ ## In Memory
56
+
57
+ ```js
58
+ import EventStore from 'tapeworm';
59
+
60
+ // A singleton Tapeworm EventStore should be instantiated somewhere
61
+ const eventStore = new EventStore();
62
+
63
+ // Opening the same partition multiple times returns the same Partition instance
64
+ const partition = await eventStore.openPartition('location');
65
+
66
+ const firstCommit = new Commit('1', 'location', '1', 0, []);
67
+ const secondCommit = new Commit('2', 'location', '1', 1, []);
68
+ const thirdCommit = new Commit('3', 'location', '1', 2, []);
69
+
70
+ // When all commits have ben persisted, the commits are returned
71
+ const commits = await partition.append([firstCommit, secondCommit]);
72
+ // [firstCommit, secondCommit]
73
+
74
+ // Single commits are returned as an array of one item
75
+ const addedCommits = await partition.append(thirdCommit);
76
+ // [thirdCommit]
77
+ ```
78
+
79
+ ## Custom Partition
80
+
81
+ This example uses
82
+ the [MongoDB persistence partition](https://github.com/surikaterna/tapeworm_persistence_store_mongodb), but a custom
83
+ persistence partition can be implemented and used as needed.
84
+
85
+ ```js
86
+ const dispatchService = (commit) => {
87
+ // Commit dispatched from the custom store, handle it as necessary
88
+ }
89
+
90
+ const eventStore = new EventStore(tapewormMdbStore, dispatchService);
91
+ const partition = await eventStore.openPartition('location');
92
+
93
+ const commits = [
94
+ new Commit('1', 'location', '1', 0, []),
95
+ new Commit('2', 'location', '1', 1, [])
96
+ ];
97
+
98
+ // Will call dispatchService twice, once for each commit when handled by the custom partition
99
+ await partition.append(commits);
100
+ ```
101
+
102
+ # Components
103
+
104
+ ## EventStore
105
+
106
+ The TapeWORM EventStore is exported as default. It takes an optional custom partition and an optional dispatch service
107
+ and holds a collection of [event store partitions](#eventstorepartition) opened.
108
+
109
+ ```js
110
+ import EventStore from 'tapeworm';
111
+
112
+ // A singleton TapeWORM EventStore should be instantiated somewhere
113
+ const eventStore = new EventStore();
114
+ ```
115
+
116
+ ### Methods
117
+
118
+ #### openPartition
119
+
120
+ Resolves an [EventStorePartition](#eventstorepartition) when the persistence store has successfully opened its
121
+ persistence partition.
122
+
123
+ ```js
124
+ const partition = await eventStore.openPartition();
125
+ ```
126
+
127
+ ### EventStorePartition
128
+
129
+ A wrapper around the persistence partition.
130
+
131
+ ### Methods
132
+
133
+ #### openStream
134
+
135
+ Resolves an [EventStream](#eventstream) when it has properly loaded all commits.
136
+
137
+ ```js
138
+ const eventStream = await partition.openStream(streamId, writeOnly, callback);
139
+ ```
140
+
141
+ #### append
142
+
143
+ Takes a commit or a list of commits and appends them on the persistence partition. Will call the dispatch service, if
144
+ provided, once per appended commit.
145
+
146
+ ```js
147
+ const appendedCommits = await partition.append(commits, callback);
148
+ ```
149
+
150
+ #### delete
151
+
152
+ Commit a stream deleted event to indicate that all related data for the stream shall be removed.
153
+
154
+ ```js
155
+ await partition.delete(streamId, deleteEvent);
156
+ ```
157
+
158
+ ### Persistence Partition Wrapper Methods
159
+
160
+ The EventStorePartition will provide methods for calling the following methods directly on the persistence partition,
161
+ providing the provided arguments.
162
+
163
+ #### queryStreamWithSnapshot
164
+
165
+ Has a fallback implementation assuming that the persistence partition used has the [loadSnapshot](#loadsnapshot)
166
+ and [queryStream](#querystream) methods implemented.
167
+
168
+ #### storeSnapshot
169
+
170
+ Store a snapshot for a stream and resolve data for the stored snapshot.
171
+
172
+ ```js
173
+ const snapshotData = await partition.storeSnapshot(streamId, snapshot, version, callback);
174
+ // Result: { id, version, snapshot }
175
+ ```
176
+
177
+ #### loadSnapshot
178
+
179
+ Retrieve the stored snapshot of a stream.
180
+
181
+ ```js
182
+ const snapshotData = await partition.loadSnapshot(streamId, callback);
183
+ // Result: { id, version, snapshot }
184
+ ```
185
+
186
+ #### queryStream
187
+
188
+ Retrieve the commits for a stream.
189
+
190
+ ```js
191
+ const snapshotData = await partition.queryStream(streamId, fromEventSequence, callback);
192
+ // Result: [{ id, streamId, commitSequence, events }, { id, streamId, commitSequence, events }]
193
+ ```
194
+
195
+ #### removeSnapshot
196
+
197
+ Remove the stored snapshot of a stream.
198
+
199
+ ```js
200
+ await partition.removeSnapshot(streamId, callback);
201
+ // Result: { id, version, snapshot }
202
+ ```
203
+
204
+ #### getLatestCommit
205
+
206
+ Retrieve the last stored commit for a stream.
207
+
208
+ ```js
209
+ const commit = await partition.getLatestCommit(streamId, callback);
210
+ // Result: { id, streamId, commitSequence, events }
211
+ ```
212
+
213
+ #### querySnapshotsByMaxDateTime
214
+
215
+ Retrieve the stored snapshots older than the provided date string.
216
+
217
+ ```js
218
+ const snapshots = await partition.querySnapshotsByMaxDateTime(dateTime, callback);
219
+ // Result: [{ id }, { id }]
220
+ ```
221
+
222
+ ## EventStream
223
+
224
+ ### Methods
225
+
226
+ #### getVersion
227
+
228
+ Retrieves the current version of the stream.
229
+
230
+ ```js
231
+ const version = eventStream.getVersion();
232
+ ```
233
+
234
+ #### append
235
+
236
+ Add an [Event](#event) to the streams list of uncommitted (planned) events.
237
+
238
+ ```js
239
+ eventStream.append(event);
240
+ ```
241
+
242
+ #### hasChanges
243
+
244
+ Returns whether there are uncommitted events on the stream.
245
+
246
+ ```js
247
+ const hasChanges = eventStream.hasChanges();
248
+ ```
249
+
250
+ #### commit
251
+
252
+ Build a [commit](#commit) from the uncommitted [events](#event) and append it to
253
+ the [event store partition](#eventstorepartition).
254
+
255
+ ```js
256
+ await eventStream.commit(commitId, callback);
257
+ ```
258
+
259
+ #### revertChanges
260
+
261
+ Remove the uncommitted events from the stream to prevent the changes from being committed.
262
+
263
+ ```js
264
+ eventStream.revertChanges();
265
+ ```
266
+
267
+ #### getCommittedEvents
268
+
269
+ Returns a copy of the committed events for the stream.
270
+
271
+ Throws an error if the stream is created as _write only_.
272
+
273
+ ```js
274
+ const events = eventStream.getCommittedEvents();
275
+ ```
276
+
277
+ #### getUncommittedEvents
278
+
279
+ Returns a copy of the uncommitted events appended to the stream.
280
+
281
+ ```js
282
+ const events = eventStream.getUncommittedEvents();
283
+ ```
284
+
285
+ ## Commit
286
+
287
+ Creates a new Commit instance.
288
+
289
+ ```js
290
+ const commit = new Commit(id, partitionId, streamId, commitSequence, events);
291
+
292
+ // commit.id: id
293
+ // commit.partitionId: partitionId
294
+ // commit.streamId: streamId
295
+ // commit.commitSequence: commitSequence
296
+ // commit.events: events
297
+ ```
298
+
299
+ ## Event
300
+
301
+ Creates a new Event instance.
302
+
303
+ ```js
304
+ const event = new Event(id, type, data, metadata);
305
+
306
+ // event.id: id
307
+ // event.type: type
308
+ // event.data: data
309
+ // event.metadata: metadata (defaults to {})
310
+ // event.timestamps: Date (date of creation)
311
+ // event.revision: null (to be updated by the event store when appended)
312
+ ```
313
+
314
+ ## Dispatch Service
315
+
316
+ The Tapeworm event store takes a dispatch service as an optional second argument. If provided, it will be called with
317
+ the commit as payload once it has been processed by the persistence partition.
318
+
319
+ ```js
320
+ function dispatchService(commit, markAsDispatched) {
321
+ // Distribute information about the processed commit
322
+ // ...
323
+
324
+ markAsDispatched();
325
+ }
326
+
327
+ const eventStore = new EventStore(null, dispatchService);
328
+ const partition = await eventStore.openPartition('location');
329
+
330
+ // Will call dispatchService when the commit is processed
331
+ partition.append(new Commit('4', 'location', '1', 3, []));
332
+ ```
@@ -82,9 +82,14 @@ EventStream.prototype.hasChanges = function () {
82
82
 
83
83
  EventStream.prototype.commit = function (commitId, callback) {
84
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}) );
85
+
86
+ if (this._isDeleted) {
87
+ throw new Error(
88
+ 'Stream is deleted, unable to commit: ' +
89
+ this._uncommittedEvents.map(function (event) {
90
+ return event.type;
91
+ })
92
+ );
88
93
  }
89
94
 
90
95
  if (!this.hasChanges()) {
@@ -117,9 +122,7 @@ EventStream.prototype._clearChanges = function () {
117
122
 
118
123
  EventStream.prototype.revertChanges = function () {
119
124
  //trunc the uncomitted events log
120
- var arr = this._uncommittedEvents;
121
125
  this._uncommittedEvents = [];
122
- delete arr;
123
126
  };
124
127
 
125
128
  EventStream.prototype._buildCommit = function (commitId, events) {
@@ -55,11 +55,11 @@ InMemoryPartition.prototype.applyCommitHeader = function (commitId, header, call
55
55
  InMemoryPartition.prototype.append = function (commit, callback) {
56
56
  commit.isDispatched = false;
57
57
  //check for duplicates
58
- if (_.contains(this._commitIds, commit.id)) {
58
+ if (_.includes(this._commitIds, commit.id)) {
59
59
  throw new DuplicateCommitError('Duplicate commit of ' + commit.id);
60
60
  }
61
61
  var concurrencyKey = getConcurrencyKey(commit);
62
- if (_.contains(this._commitConcurrencyCheck, concurrencyKey)) {
62
+ if (_.includes(this._commitConcurrencyCheck, concurrencyKey)) {
63
63
  throw new ConcurrencyError('Concurrency error on stream ' + commit.streamId);
64
64
  }
65
65
  //check concurrency
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tapeworm",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -34,13 +34,13 @@
34
34
  "eslint-plugin-react": "^3.3.1",
35
35
  "istanbul": "^0.3.2",
36
36
  "mocha": "^2.0.1",
37
- "should": "^4.1.0",
38
37
  "prettier": "^2.1.2",
39
- "prettier-config-surikaterna": "^1.0.1"
38
+ "prettier-config-surikaterna": "^1.0.1",
39
+ "should": "^4.1.0"
40
40
  },
41
41
  "dependencies": {
42
42
  "bluebird": "^2.5.2",
43
- "lodash": "^2.4.2",
43
+ "lodash": "^4.17.21",
44
44
  "uuid": "^8.3.2"
45
45
  }
46
46
  }