{"id":16531403,"url":"https://github.com/marcbachmann/eventsourced-object","last_synced_at":"2025-09-13T23:32:19.910Z","repository":{"id":57153930,"uuid":"72449425","full_name":"marcbachmann/eventsourced-object","owner":"marcbachmann","description":"𝌭 A minimal eventsourcing helper for objects and classes","archived":false,"fork":false,"pushed_at":"2023-12-15T02:33:35.000Z","size":18,"stargazers_count":7,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-14T14:40:20.454Z","etag":null,"topics":["aggregate","event-sourcing","reducer"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcbachmann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-31T15:21:39.000Z","updated_at":"2018-12-12T19:11:25.000Z","dependencies_parsed_at":"2023-12-15T03:45:11.315Z","dependency_job_id":null,"html_url":"https://github.com/marcbachmann/eventsourced-object","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbachmann%2Feventsourced-object","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbachmann%2Feventsourced-object/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbachmann%2Feventsourced-object/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbachmann%2Feventsourced-object/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcbachmann","download_url":"https://codeload.github.com/marcbachmann/eventsourced-object/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232931899,"owners_count":18598665,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aggregate","event-sourcing","reducer"],"created_at":"2024-10-11T18:08:44.459Z","updated_at":"2025-01-07T20:09:02.446Z","avatar_url":"https://github.com/marcbachmann.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# eventsourced-object\n\n[![Greenkeeper badge](https://badges.greenkeeper.io/marcbachmann/eventsourced-object.svg)](https://greenkeeper.io/)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmarcbachmann%2Feventsourced-object.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmarcbachmann%2Feventsourced-object?ref=badge_shield)\n\nA minimal eventsourcing helper for objects and classes.  \nIn case you don't know eventsourcing, [here's some reading material](#event-sourcing)\n\n\n```js\nvar Aggregate = require('eventsourced-object')\n```\n\n## Api\n\n### Aggregate.setup(obj, reducer, events)\n\n```js\nvar user = {version: 0}\nvar initialEvents = [{name: 'CreateUser', fullName: 'Marc Bachmann'}]\nAggregate.setup(user, reducer, initialEvents)\n\nfunction reducer (state, evt) {\n    state.version += 1\n    if (evt.name == 'CreateUser') state.name = evt.fullName\n}\n```\n\n### Aggregate.event(obj, reducer, event)\n\n```js\nvar user = Aggregate.setup({version: 0})\nvar event = {name: 'CreateUser', fullName: 'Marc Bachmann'}\nAggregate.event(user, reducer, event)\n// executes the reducer with the event and queues the event so you can save it\nfunction reducer (state, evt) {\n    state.version += 1\n    if (evt.name == 'CreateUser') state.name = evt.fullName\n}\n```\n\n### Aggregate.drain(obj)\n\n```js\nvar obj = {}\nAggregate.setup(obj)\nAggregate.event(obj, reducer, {foo: 'bar'})\nAggregate.event(obj, reducer, {foo: 'test'})\nAggregate.drain(obj) // returns [{foo: 'bar'}, {foo: 'test'}]\n```\n\n### Aggregate.isDirty(obj)\n\n```js\nvar obj = {}\nAggregate.setup(obj)\nAggregate.event(obj, reducer, {foo: 'bar'})\nAggregate.isDirty(obj) // returns true\n```\n\n## Example using a class\n```js\nvar user = User.create({email: 'foo@example.com', fullName: 'Foo Example'})\nuser.rename('Example')\n// user == {\n//    id: 'iuxswpqw',\n//    email: 'foo@example.com',\n//    fullName: 'Example',\n//    createdAt: Mon Oct 31 2016 09:26:02 GMT+0100 (CET),\n//    updatedAt: Mon Oct 31 2016 09:26:03 GMT+0100 (CET)\n//}\n\n\nfunction User (events) {\n  this.version = 0\n  Aggregate.setup(this, reducer, events)\n}\n\nUser.create = function (params) {\n  var user = new User()\n  return Aggregate.event(user, reducer, {\n    aggregateId: params.id || Date.now().toString(36),\n    name: 'UserCreated',\n    time: new Date(),\n    data: {\n      email: params.email,\n      fullName: params.fullName\n    }\n  })\n}\n\nUser.prototype.rename = function (fullName) {\n  return Aggregate.event(this, reducer, {\n    aggregateId: this.id,\n    name: 'UserRenamed',\n    time: new Date(),\n    data: {\n      fullName: fullName\n    }\n  })\n}\n\nUser.prototype.save = function () {\n  var events = Aggregate.drain(this)\n  console.log(events) // Save events to some storage/repository\n}\n\nUser.prototype.isDirty = function () {\n  return Aggregate.isDirty(this)\n}\n\nfunction reducer (state, evt) {\n  state.version += 1\n  state.updatedAt = evt.time\n  if (evt.name === 'UserCreated') {\n    state.id = evt.aggregateId\n    state.createdAt = evt.time\n    state.fullName = evt.data.fullName\n    state.email = evt.data.email\n  } else if (evt.name === 'UserRenamed') {\n    state.fullName = evt.data.fullName\n  }\n}\n```\n\n# Benchmarks\n\nHere are some benchmarks with 10'000'000 iterations per function\n```\nNANOBENCH version 1\n\n# raw object creation (for comparison)\n  end ~97 ms (0 s + 97465524 ns)\n# .setup(obj)\n  end ~228 ms (0 s + 227954858 ns)\n# .event(obj, reducer, event)\n  end ~473 ms (0 s + 473181583 ns)\n# .isDirty(obj)\n  end ~86 ms (0 s + 86072337 ns)\n\n# total ~885 ms (0 s + 884674302 ns)\n\n# ok\n\n[Finished in 1.0s]\n```\n\n# Event Sourcing\n\n## Videos\n- https://www.youtube.com/watch?v=JHGkaShoyNs\n- http://www.infoq.com/presentations/greg-young-unshackle-qcon08\n- https://www.youtube.com/watch?v=whCk1Q87_ZI\n- https://www.youtube.com/watch?v=I4A5ntHeoxU\n\n## Reading material\n- http://cqrs.nu/\n- https://ookami86.github.io/event-sourcing-in-practice/\n- https://nicolaswidart.com/blog/get-up-and-running-with-event-sourcing\n- http://danielwhittaker.me/2014/11/15/aggregate-root-cqrs-event-sourcing/\n- http://docs.geteventstore.com/introduction/event-sourcing-basics/\n- https://abdullin.com/tags/cqrs/\n- https://abdullin.com/post/event-sourcing-projections/\n- http://slides.com/stefankutko/nodejs-microservices-event-sourcing-cqrs\n- http://blog.zilverline.com/2012/07/04/simple-event-sourcing-introduction-part-1/\n- http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/\n- http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf\n- https://groups.google.com/forum/#!forum/dddcqrs\n\n\n\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmarcbachmann%2Feventsourced-object.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmarcbachmann%2Feventsourced-object?ref=badge_large)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcbachmann%2Feventsourced-object","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcbachmann%2Feventsourced-object","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcbachmann%2Feventsourced-object/lists"}