| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
FJ-EventStore is an EventStore heavily inspired by the prooph/event-store v7.0.
The usage of this EventStore is recommended with TypeScript to benefit from the implemented autocompletion features for Events, ProjectionStates. This EventStore also ships with Decorators to simplify configuration.
The following descriptions using TypeScript. The integrated example serve using normal JavaScript for reference.
FJ EventStore Example is a base Project with an example integration in the NodeJS Framework NestJS. The Example includes different APIs to show you the basic features like:
For a basic overview you can use the code snippets from this example project below
// main.ts
import { createPostgresEventStore } from 'fj-event-store/postgres';
const eventStore = createPostgresEventStore({
// Postgres ConnectionString
connectionString: 'postgres://user:password@localhost:5432/event-store'
});
// Creates the event_streams and projections tables if they not exist
await eventStore.install();event-store event-stream:create <streamName>
Create a basic events with immutable values and payload autocomplete
// model/todo/event/todo-was-added.ts
import { BaseEvent } from 'fj-event-store';
interface TodoPayload {
task: string;
description: string;
date: string;
}
export class TodoWasAdded extends BaseEvent<TodoPayload> {
static with(todoId: string, task: string, description: string, date: Date) {
return this.occur(todoId, { task, description, date: date.toString() });
}
get todoId() {
return this.aggregateId;
}
get task() {
return this._payload.task;
}
get description() {
return this._payload.description;
}
get date() {
return new Date(this._payload.date);
}
}Create and configure an Todo Aggregate with the AbstractAggregate Class and Aggregate Decorater to configure them.
Use Aggregate._recordThat to append a new Event to the EventStream of the Aggregate. its not persisted yet.
Each Aggregate calls internal a method with the name-schema _when${EventClassName} if it exist. This Method is normally used to set the new State from the Events in the Aggregate.
// model/todo/todo.ts
import { AbstractAggregate } from 'fj-event-store';
import { Aggregate } from 'fj-event-store';
import { TodoWasAdded } from './event';
@Aggregate([TodoWasAdded])
export class Todo extends AbstractAggregate {
private _todoId: string;
private _task: string;
private _description: string;
private _checked: boolean;
private _date: Date;
public static add(todoId: string, task: string, description: string, date: Date): Todo {
const self = new this();
self._recordThat(TodoWasAdded.with(todoId, task, description, date));
return self;
}
protected _whenTodoWasAdded(event: TodoWasAdded) {
this._todoId = event.aggregateId;
this._task = event.task;
this._description = event.description;
this._date = event.date;
this._checked = false;
}
get todoId(): string {
return this._todoId;
}
get task(): string {
return this._task;
}
get description(): string {
return this._description;
}
get date(): Date {
return this._date;
}
get checked(): boolean {
return this._checked;
}
}Create a Repository for your Aggregate. Each Repository has 2 methods to save and load aggregates.
// model/todo/todo-repository.ts
import { AggregateRepository, Repository } from 'fj-event-store';
import { Todo } from './todo';
@Repository({ streamName: 'todos', aggregate: Todo })
export class TodoRepository extends AggregateRepository<Todo> {}// main.ts
import * as uuid from 'uuid/v4'
import { createInMemoryEventStore } from 'fj-event-store/in-memory';
import { Todo, TodoRepository } from './todo/model';
(async () => {
const eventStore = createInMemoryEventStore();
await eventStore.install();
const todo = Todo.add(
uuid(),
'Using fj-event-store',
'Using EventSourcing in my next NodeJS project',
new Date()
);
repository = new TodoRepository();
// Persist the new aggregate in your PostgresDB
await repository.save(todo);
// Load an Aggregate from your EventStream
const loadedTodo = repository.get(todo.todoId)
})();Using the AbstractProjection class and configure them with the helper Decorator
// projection/todo/todo-list.ts
import { AbstractProjection, Projection, IProjector } from 'fj-event-store';
import { TodoWasAdded } from '../../model/todo/event';
export interface TodoListState {
[id: string]: { id: string, task: string, date: string, checked: boolean };
}
@Projection('todo_list')
export class TodoListProjection extends AbstractProjection<TodoListState> {
project(): IProjector<TodoListState> {
return this
.projector
.fromStream({ streamName: 'todos' })
.init(() => ({}))
.when({
[TodoWasAdded.name]: (state, event: TodoWasAdded): TodoListState => {
return { ...state, [event.todoId]: { id: event.todoId, task: event.task, date: event.date.toString(), checked: false } };
}
});
}
}// main.ts
...
(async () => {
...
const projector = eventStore.getProjector<TodoListState>(TodoListProjection.projectionName);
await projector.run(false);
projector.getState()
})();The CLI event-store supports the usage of EventStore with different helper commands for EventStreams and Projections.
Usage: event-store [command] --help
CLI to manage EventStore streams, requires a event-store.config.js config file.
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
event-stream:create <streamName> Creates an new EventStream
event-stream:delete <streamName> Deletes an existing EventStream
projection:run [options] <name> Running a projection
projection:reset <name> Reset a projection
projection:delete [options] <name> Delete a projectiondocker-compose up -d postgresCreate your .env File under ./example. You can copy and rename the .env.default to .env and change the values to your configuration
Make the CLI Tool executable with the following command chmod +x bin/event-store
# Install the dependencies (including DEV-dependencies)
npm install
# Install peerDependencies for a Postgres EventStore
npm i pg @types/pg --no-save
# Transpile Typescript
npm run watch
# Run the Example Server
npm run serveAfter the Server started you should see the Message EventStore installed in your Terminal if the DB preparation was succeeded
Create a User: http://localhost:3000/append/user/:username (Returns the UserID you can fetch afterwards) Fetch a User Aggregate: http://localhost:3000/user/:aggregateId (Returns the latest user state) Change the Username: http://localhost:3000/user/:aggregateId/change-name?name=:username (Returns the updated user) Write a comment: http://localhost:3000/user/:aggregateId/write-comment?message=:message (Returns the updated user) Create and show a persistend Projection: User List: http://localhost:3000/user/list (Returns the updated user) Query Events: User EventHistory: http://localhost:3000/user/:id/history (Returns the updated user) Query multilpe StreamEvents: User Comment List: http://localhost:3000/user/:id/comments
| Back | FazBrowse Home | New Git URL |