domain-query-language / dql-server-php-defunct

A server side application that can receive and process DQL statements, leading to a fully working, event sourced, domain.
MIT License
0 stars 1 forks source link

Problem: Unsure how to build projectors/projections #74

Open barryosull opened 8 years ago

barryosull commented 8 years ago

While trying to build the projector/projection system in #67 , I've run into some problems around modelling the schema of tables. How exactly will the system process changes to schemas, how will it handle rebuilds?

This issue is about exploring this concept.

barryosull commented 8 years ago

First thought, what if we modelled this as a domain with sub contexts?

I've done a quick event storming session, here are the results.

event storming

These are the events output by the system that can be used to trigger changes and builds of projections. This would fire these events, then use workflows to plug into the application services that will perform the actual work.

barryosull commented 8 years ago

Column removed doesn't need to trigger a build.

barryosull commented 8 years ago

I think "BuildFailed" is a must, it's a way for us to see when something goes wrong in infrastructure, and see an error report. Having it as a two stage process also lets us see how long the infrastructural tasks are taking.

In the above case, the "projection" is actually an "aggregate", as in, they'll be one to one, with the same ids.

barryosull commented 8 years ago

Sample code for the interface to the domain projection application

interface DomainProjectionist
{
    /**
    * Takes in events from other domains (Schema and Domain), 
    * turns them into commands internally via an adapter 
    */
    public function handle(Event $event);

    /**
    * Takes in queries from the domain, most likely the shape of 
    * the ID of the query (Invariant) and the arguments
    */
    public function answer(Query $query);
}

The above builds up the ASTs it needs internally, by listening to schema events. This makes it completely decoupled form the rest of system, no reliance on a central AST store. Then it decides internally on whether to use those in its interpreter or to compile actual code, this complexity is completely hidden from the end user.

barryosull commented 8 years ago

I think we can build a prototype of the above, we just need to define the expected inputs and outputs.

Let's take a subset of the DQL in e-commerce domain (enough to build a working interpreter), turn that into ASTs, and then test the system.

The Event and Query objects don't need to be first class objects, they can just be stdClasses for this demo, this is really just a proof of concept.

barryosull commented 8 years ago

DQL Statements:

within aggregate 'carts':
{
    # Property that referenced
    create identifier 'shopper_id' defaults (null);

    # Event that's used to set for property
    create event 'created' (shopper_id) as (identifier) handled by (
        <:
            update aggregate
                set 'shopper_id' = shopper_id
        :>
    );

    # Invariant that defines the query
    create invariant 'shopper-has-active-cart' (shopper_id) as (identifier) satisfied by (
        <:
            from all
                count(shopper_id) as cart_count
            where 
                shopper_id == shopper_id
            check 
                cart_count > 0
        :>
    );
}
barryosull commented 8 years ago

Taking the above DQL into consideration, these are the events that are relevant to the each bounded-context.

event storming 1