eventsourced-object

A minimal eventsourcing helper for objects and classes

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
eventsourced-object
2.0.07 years ago7 years agoMinified + gzip package size for eventsourced-object in KB

Readme

eventsourced-object
A minimal eventsourcing helper for objects and classes.
In case you don't know eventsourcing, here's some reading material
var Aggregate = require('eventsourced-object')

Api

Aggregate.setup(obj, reducer, events)

var user = {version: 0}
var initialEvents = [{name: 'CreateUser', fullName: 'Marc Bachmann'}]
Aggregate.setup(user, reducer, initialEvents)

function reducer (state, evt) {
    state.version += 1
    if (evt.name == 'CreateUser') state.name = evt.fullName
}

Aggregate.event(obj, reducer, event)

var user = Aggregate.setup({version: 0})
var event = {name: 'CreateUser', fullName: 'Marc Bachmann'}
Aggregate.event(user, reducer, event)
// executes the reducer with the event and queues the event so you can save it
function reducer (state, evt) {
    state.version += 1
    if (evt.name == 'CreateUser') state.name = evt.fullName
}

Aggregate.drain(obj)

var obj = {}
Aggregate.setup(obj)
Aggregate.event(obj, reducer, {foo: 'bar'})
Aggregate.event(obj, reducer, {foo: 'test'})
Aggregate.drain(obj) // returns [{foo: 'bar'}, {foo: 'test'}]

Aggregate.isDirty(obj)

var obj = {}
Aggregate.setup(obj)
Aggregate.event(obj, reducer, {foo: 'bar'})
Aggregate.isDirty(obj) // returns true

Example using a class

var user = User.create({email: 'foo@example.com', fullName: 'Foo Example'})
user.rename('Example')
// user == {
//    id: 'iuxswpqw',
//    email: 'foo@example.com',
//    fullName: 'Example',
//    createdAt: Mon Oct 31 2016 09:26:02 GMT+0100 (CET),
//    updatedAt: Mon Oct 31 2016 09:26:03 GMT+0100 (CET)
//}


function User (events) {
  this.version = 0
  Aggregate.setup(this, reducer, events)
}

User.create = function (params) {
  var user = new User()
  return Aggregate.event(user, reducer, {
    aggregateId: params.id || Date.now().toString(36),
    name: 'UserCreated',
    time: new Date(),
    data: {
      email: params.email,
      fullName: params.fullName
    }
  })
}

User.prototype.rename = function (fullName) {
  return Aggregate.event(this, reducer, {
    aggregateId: this.id,
    name: 'UserRenamed',
    time: new Date(),
    data: {
      fullName: fullName
    }
  })
}

User.prototype.save = function () {
  var events = Aggregate.drain(this)
  console.log(events) // Save events to some storage/repository
}

User.prototype.isDirty = function () {
  return Aggregate.isDirty(this)
}

function reducer (state, evt) {
  state.version += 1
  state.updatedAt = evt.time
  if (evt.name === 'UserCreated') {
    state.id = evt.aggregateId
    state.createdAt = evt.time
    state.fullName = evt.data.fullName
    state.email = evt.data.email
  } else if (evt.name === 'UserRenamed') {
    state.fullName = evt.data.fullName
  }
}
Benchmarks
Here are some benchmarks with 10'000'000 iterations per function
NANOBENCH version 1

# raw object creation (for comparison)
  end ~97 ms (0 s + 97465524 ns)
# .setup(obj)
  end ~228 ms (0 s + 227954858 ns)
# .event(obj, reducer, event)
  end ~473 ms (0 s + 473181583 ns)
# .isDirty(obj)
  end ~86 ms (0 s + 86072337 ns)

# total ~885 ms (0 s + 884674302 ns)

# ok

[Finished in 1.0s]
Event Sourcing

Videos

  • https://www.youtube.com/watch?v=JHGkaShoyNs
  • http://www.infoq.com/presentations/greg-young-unshackle-qcon08
  • https://www.youtube.com/watch?v=whCk1Q87ZI
  • https://www.youtube.com/watch?v=I4A5ntHeoxU

Reading material

  • http://cqrs.nu/
  • https://ookami86.github.io/event-sourcing-in-practice/
  • https://nicolaswidart.com/blog/get-up-and-running-with-event-sourcing
  • http://danielwhittaker.me/2014/11/15/aggregate-root-cqrs-event-sourcing/
  • http://docs.geteventstore.com/introduction/event-sourcing-basics/
  • https://abdullin.com/tags/cqrs/
  • https://abdullin.com/post/event-sourcing-projections/
  • http://slides.com/stefankutko/nodejs-microservices-event-sourcing-cqrs
  • http://blog.zilverline.com/2012/07/04/simple-event-sourcing-introduction-part-1/
  • http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/
  • http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf
  • https://groups.google.com/forum/#!forum/dddcqrs