Skip to content

Queries

Artem Dmitriev edited this page Jun 26, 2017 · 1 revision

Introduction

For the outside world Query model is defined. It automatically catches up changes from transactional one eventually, but with next guarantees:

  • At the end of every command execution all changes to the model are reflected in the query model.
  • At event handler execution, all changes made by an dispatching transaction action are reflected in query model.

Let's dive into details of how Query side is particulary implemented in the Reveno.

Views

In Reveno there is a View term, which is a reflection of entity from transactional model. For example, if you have some Account entity class, you will also need to have AccountView, which reflects all changes to any Account for the outside usage. For that specially defined ViewsMapper are required. You are free to choose how to implement your query model - with mutable or immutable objects. This is not configurable like with Repository, so concrete implementation is up to you.

View mappers

View mappers are used to map entities from transactional to query model. It should be defined for every entity class, and can be built up fluently with much of ancillary functionality. ViewsMapper has the next definition:

@FunctionalInterface
public interface ViewsMapper<Entity, View> {
	View map(long id, Entity entity, MappingContext repository);
}

Let's see how it's actually can be defined. Consider that we have some trading system, where traders have some amount of an orders:

public static class Trader {
    public final long id;
    public final List<Long> orders = new ArrayList<>();

    public Trader(long id) {
        this.id = id;
    }
}

public static class Order {
    public final long id;
    public final long size;
    public final long price;

    public Order(long id, long size, long price) {
        this.id = id;
        this.size = size;
        this.price = price;
    }
}

This entities are stored in repository, and accessed by commands and transaction actions. In order to access them from query side, we need to define appropriate views (you should note that given example is very simplified and not of production quality):

public static class TraderView {
	public final String id;
	public final List<OrderView>orders;

	public TraderView(long id, List<OrderView> orders) {
		this.id = LongUtils.longToBase64(id);
		this.orders = Collections.unmodifiableList(orders);
	}
}

public static class OrderView {
	public final String id;
	public final BigDecimal price;
	public final long amount;

	public OrderView(long id, long size, long price) {
		this.id = LongUtils.longToBase64(id);
		this.price = new BigDecimal(price).divide(PRECISION_BD);
		this.amount = size;
	}
}

Views here can have a different internal structure of the same data representation, which is might be more useful in non-transactional environment. Finally, we are ready to tell the Reveno how to perform mapping:

Reveno reveno = new Engine("/tmp/reveno-engine");
reveno.domain().viewMapper(Trader.class, TraderView.class, (id, e, r) ->
              new TraderView(e.id, r.link(e.orders.stream(), OrderView.class)));
reveno.domain().viewMapper(Order.class, OrderView.class, (id, e, r) ->
              new OrderView(e.id, e.size, e.price));

The first argument accepts an entity class, while the second one is a view class to which it'll be mapped. Views mapper has three parameters:

  • id - identifier of an entity being mapped, under which it's stored in the repository.
  • e - entity object itself.
  • r - mapping context.

Call r.link(e.orders.stream(), OrderView.class) helps us to translate a collection of IDs to their appropriate view objects with one line. To get familiar with more methods from this context, reference MappingContext javadoc.

Conclusion

By default, views in the Reveno are stored in-memory and are created via views mappers. You are free to change such behavior, either by just not using reveno.query() methods and generating views to 3rd-party storage in mappers, either by fully overriding Engine and replacing ViewsStorage instance in it.

Please reach out full example of a given aticle here .

Clone this wiki locally