dolittle / JavaScript.SDK

Dolittle JavaScript SDK
https://dolittle.io
MIT License
5 stars 2 forks source link

Add projections #44

Closed joelhoisko closed 3 years ago

joelhoisko commented 3 years ago

Summary

Adds Projections, that are a special type of event handler dealing with read models. Projections can be defined either inline in the client build steps, or declaratively with @projection() decorator.

Example for writing inline projections and registering declared projections:

const client = Client
    .forMicroservice('f39b1f61-d360-4675-b859-53c05c87c0e6')
    .withEventTypes(eventTypes => {
        eventTypes.register(DishPrepared);
        eventTypes.register(ChefFired);
    })
    .withProjections(projections => {
        projections.createProjection('4a4c5b13-d4dd-4665-a9df-27b8e9b2054c')
            .forReadModel(Chef)
            .on(DishPrepared, _ => _.keyFromProperty('Chef'), (chef, event, ctx) => {
                console.log(`Handling read model ${JSON.stringify(chef)}`);
                chef.name = event.Chef;
                chef.dishes.push(event.Dish);
                return chef;
            })
            .on(ChefFired, _ => _.keyFromProperty('Chef'), (chef, event, ctx) => {
                console.log(`Firing ${chef.name}`);
                return ProjectionResult.delete;
            });
        projections.register(Menu);
    })
    .build();

Example of @projection() decorator:

@projection('5b22e60e-f8db-494e-af5c-e8728acb2470')
export class Menu {
    dishes: string[] = [];

    @on(DishPrepared, _ => _.keyFromEventSource())
    on(event: DishPrepared, ctx: EventContext) {
        if (!this.dishes.includes(event.Dish)) {
            this.dishes.push(event.Dish);
        }
    }
}

Example of getting projections:

const {state: menu} = await client.projections
    .forTenant(TenantId.development)
    .get(Menu, 'bfe6f6e4-ada2-4344-8a3b-65a3e1fe16e9');
console.log('Got menu', menu);

console.log('Getting all chefs');
for (const [, { key, state: chef }] of await client.projections.forTenant(TenantId.development).getAll(Chef)) {
    console.log(`Found chef ${key}`, chef);
}
console.log('Getting all chefs but specify ids');
for (const [, { key, state: chef }] of await client.projections.forTenant(TenantId.development).getAll(Chef, '4a4c5b13-d4dd-4665-a9df-27b8e9b2054d')) {
    console.log(`Found chef ${key}`, chef);
}
console.log('Getting all chefs with no type');
for (const [, { key, state: chef }] of await client.projections.forTenant(TenantId.development).getAll('4a4c5b13-d4dd-4665-a9df-27b8e9b2054c', ScopeId.default)) {
    console.log(`Found chef ${key}`, chef);
}

Added

Changed

Fixed