1.0.0 • Published 7 years ago

js-cqrs-es v1.0.0

Weekly downloads
1
License
MIT
Repository
github
Last release
7 years ago

js-cqrs-es

A JavaScript Command Query Responsibility Segregation (CQRS) and Event Sourcing (ES) library. This is developed in parallel to prove the Hive Pattern theory. It is the library that the Hive Stack Components are built upon.

Library

The library contains a base set of classes that can be used to implement your domain layer of your CQRS/ES application. It contains all the basic building blocks for defining Aggregates, Entities, and Value Objects backed by a rich Schema specification that is meant to translate to/from JSON for easy network transport. It also provides extensible Command and Event Messages to support your Aggregate implementation.

Schema

Let's start with Schema first. Inspired by Mongoose Schemas, it has very similar features but some very distinct differences. A Schema is a specification for your data models to provide a reference for validation when instantiating and/or applying data to your models. Each property must have one of the valid JSON primitive/complex data types defined:

  • Boolean
  • Number
  • String
  • Object (as a nested Schema)
  • Array (as an Array literal)

Property definitions can be as simple as providing the one of the data types above or as complex as a object literal containing the following properties:

  • type = use one of the types listed above
  • (Optional) required = set as a truthy value
  • (Optional) validate = custom validation method that must throw an Error on a failed validation
  • (Optional) default = a default value/function for the property
  • (Optional) value = a hard-coded value/function

While Schema only provides two public methods, it does quite a bit more under the hood to support the definitions above. It is defined as an iterable object with the same signature as a Map so Aggregates/Models can iterate over the schema using for...of instead of for...in w/ hasOwnProperty. While the Aggregates/Models iterate over the Schema, they call the following methods for support:

  • validate(value, rule) - called by Aggregate/Model to validate each property while being assigned. value is the value to validate and rule is a reference to the property's Schema definition.
  • evalProperty() - not as evil as it sounds, this method is used to return the value or execute the function assigned to either default or value definitions above.

Model

Next is Model. The Model class, in conjunction with a Schema reference, is used to define Entities and Value Objects in your CQRS implementation. Just like Schema, it is implemented as an iterable object with the same signature as a Map. It exposes two public methods but it also does quite a bit under the hood.

  • update(data) - used to create the object's data properties initially and also when updating data against the Schema definition. it uses three internal setter methods to iterate over the Schema to validate and set data properties accordingly.
  • toJSON() - can be called directly but is typically called by JSON.stringify(object) to add the class name of the object for network transport and reconstruction.

Aggregate

The Aggregate class extends Model to add aggregate specific methods. Therefore, it has the same base functionality and public methods as the Model class but with a few additions. Namely, it has two apply methods to support different use cases.

  • applyData(data) - applies the event data from an object literal to the object. It first validates that the version of the data being applied is not out of sequence. If version validation passes, then it uses Model's update method to apply the new data on top of the existing state.
  • applySequence(data) - applies a list of events to the object to support a traditional CQRS Aggregate implementation. This method is for instantiating the state of the object from the list of events returned from your event store.
    • NOTE: This is not the default use case for the Aggregate class but can be achieved by chaining the constructor call like so new Aggregate({}, schema).applySequence(data).

Message

The Message class is a base class for Command and Event messages that are passed through a CQRS/ES application. It provides the most basic definition of these messages, an id and sequence. It has a single public method defined below:

  • toJSON() - can be called directly but is typically called by JSON.stringify(object) to add the class name of the object for network transport and reconstruction.

Command

The Command class extends Message by adding an abstract method for Command validation. It is meant to be extended directly to define your Commands in your CQRS implementation. Validations are meant to be superficial and are only concerned with specific data points attached to the command if there are any. Validate is called on Command construction automatically but is publicly exposed if it needs to be called directly.

  • validate() - abstract method that returns undefined by default. Override for specific validation requirements (if any). Be sure to throw an appropriate Error if your validation fails.

Event

The Event class is very much like the Command class above but is used for logging and event messaging. The only difference from the Message class it extends is that it adds an ISO timestamp before it's logged. It has no public methods but can be extended to suite your needs.

Handler

Last but not least, the Handler class is responsible for translating Commands, Events, and Aggregates at all of your service endpoints. It is essentially the glue that binds all of the above objects together in a CQRS/ES implementation. It only has one public method and should be able to cover most use cases. The class can be extended for specific handling requirements.

  • handle(data, aggregate) - takes the raw data passed through the network and instantiates the Command it's associated with. The aggregate is an instance of the Aggregate class and is created in the Application layer either from existing event store data or with new/default data in a create command/event.

Example

This is an example implementation of a contrived domain model using this library. It is an over-simplified example of Twitter content and view analytics to showcase all of the classes above.

The example is also paired with the Hive Stack, an enterprise CQRS/ES stack implementing microservice applications around a Kafka streaming event store with Redis/Redlock as a cache layer and MongoDB for projections.

Future

1.0.0

7 years ago

0.0.1-beta.2

7 years ago

0.0.1-beta.1

7 years ago

0.0.1-beta.0

7 years ago

0.0.1-alpha.10

7 years ago

0.0.1-alpha.9

7 years ago

0.0.1-alpha.8

7 years ago

0.0.1-alpha.7

7 years ago

0.0.1-alpha.6

7 years ago

0.0.1-alpha.5

7 years ago

0.0.1-alpha.4

7 years ago

0.0.1-alpha.3

7 years ago

0.0.1-alpha.2

7 years ago

0.0.1-alpha.1

7 years ago

0.0.1-alpha.0

7 years ago