Skip to content

Conversation

dmitrykuzmin
Copy link
Contributor

@dmitrykuzmin dmitrykuzmin commented Jan 28, 2020

This PR addresses #1212.

It takes advantage of the strongly-typed fields and columns generated by base#508 and embeds them in the high-level client API.

New Client API

The old where(...) methods that are accepting plain Filter and CompositeFilter instances are now deprecated in favor of new overloads which accept the typed filters as arguments. The typed filters form a hierarchy which mirrors the hierarchy of query and entity/event subscription requests, and are created with help of generated columns and fields.

An example of the new API:

public QueryRequest<S> where(QueryFilter... filter) {
    builder().where(extractFilters(filter));
    return this;
}

public QueryRequest<S> where(CompositeQueryFilter... filter) {
    builder().where(extractFilters(filter));
    return this;
}

The QueryFilter and CompositeQueryFilter are the typed wrappers for the Filter and CompositeFilter proto messages respectively. The wrapper creation is regulated by the generated field and column types, not allowing to specify Field-based filter to a query request and vice-versa.

Event subscriptions

The event subscription request also accepts strongly-typed filters, as follows:

public EventSubscriptionRequest<E> where(EventFilter... filter) {
    builder().where(extractFilters(filter));
    return self();
}

public EventSubscriptionRequest<E> where(CompositeEventFilter... filter) {
    builder().where(extractFilters(filter));
    return self();
}

The EventFilter can be created in multiple ways to enable filtering events by the event context:

public static EventFilter eq(EventMessageField field, Object value) {
    checkNotNull(field);
    checkNotNull(value);
    return new EventFilter(field, value, EQUAL);
}

public static EventFilter eq(EventContextField field, Object value) {
    checkNotNull(field);
    checkNotNull(value);
    return new EventFilter(field, value, EQUAL);
}

// Same goes for all other operators.
// ...

The EventContextField instance may be obtained from the EventContext.Field class, in the same way as all other strongly-typed fields and columns. So an example of event subscription request could be:

 client().asGuest()
         .subscribeToEvent(UserLoggedIn.class)
         .where(all(eq(UserLoggedIn.Field.user(), userId),
                    eq(EventContext.Field.pastMessage()
                                         .actorContext()
                                         .actor(), guestUser)))
         // ...
         .post();

On the Protobuf level filtering by event context still works by appending the "context." prefix to a field path in the filter.

Additional Model Compiler configurations

To enable the behavior described above, the additional Model Compiler configurations are specified:

modelCompiler {
    fields {
        generateFor "spine.core.Event", markAs("io.spine.base.EntityStateField")
        generateFor "spine.core.EventContext", markAs("io.spine.core.EventContextField")
    }
}

Basically, they:

  1. Enable the strongly-typed fields generation for spine.core.Event, as it's a subscribable entity type (see EEntity).
  2. Enable the strongly-typed field generation for spine.core.EventContext with a custom marker superclass, to enable the typed event filter creation described above.

Other

The orderBy(...) method of QueryRequest is also switched to the new columns usage (the old version is deprecated).

Please note, that the described changes affect only the high-level Client API. The lower-level API like TargetBuilder is still capable of accepting column/field names as plain strings.

Version

The Spine version advances to 1.4.5.

dmitrykuzmin and others added 30 commits January 3, 2020 17:02
Now, using parameterized `EntityColumn` and `SubscribableField` types, the filters passed to `where(...)` will be forced to have the target type matching the filtered object.
It now wraps `Field` value instead of `FieldPath`.
The strict field and column parametrization for now is removed.
Also fetched the latest repackaging-related changes from `base`.
Also reworded the warning suppression.
@dmitrykuzmin
Copy link
Contributor Author

@armiol, @dmdashenkov PTAL. The build should pass once the corresponding changes from base and config are merged.

Copy link
Contributor

@dmdashenkov dmdashenkov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@armiol
Copy link
Contributor

armiol commented Jan 29, 2020

@dmitrykuzmin please also mention the subscription to events — i.e. how it is affected (or not) by this changeset.

@alexander-yevsyukov
Copy link
Contributor

@dmitrykuzmin, please compose a short document which explains using this feature. You can create a Google Doc, and I'll convert it into Markdown placing in the site hierarchy.

@dmitrykuzmin
Copy link
Contributor Author

@armiol, @dmdashenkov PTAL again.

@codecov
Copy link

codecov bot commented Feb 14, 2020

Codecov Report

❗ No coverage uploaded for pull request base (master@bab9e0e). Click here to learn what that means.
The diff coverage is 100%.

@@            Coverage Diff            @@
##             master    #1229   +/-   ##
=========================================
  Coverage          ?   90.82%           
  Complexity        ?     4481           
=========================================
  Files             ?      589           
  Lines             ?    14089           
  Branches          ?      776           
=========================================
  Hits              ?    12797           
  Misses            ?     1042           
  Partials          ?      250

@dmitrykuzmin dmitrykuzmin merged commit e0574e1 into master Feb 14, 2020
@dmitrykuzmin dmitrykuzmin deleted the strongly-typed-columns branch February 14, 2020 12:43
@dmitrykuzmin
Copy link
Contributor Author

@alexander-yevsyukov The short document with feature usage explanation can be found here.

@armiol armiol mentioned this pull request Mar 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants