JSPM

eventsourced-object

2.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 1188
  • Score
    100M100P100Q109844F
  • License ISC

A minimal eventsourcing helper for objects and classes

Package Exports

  • eventsourced-object

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (eventsourced-object) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

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

Reading material