EntityQuery filtering on list view

An EntityQuery filter supports 2 different modes:

  • basic mode allows you to select the property values to filter on using form controls

  • advanced mode give you a textbox for entering any EQL statement to use as filter

By default only advanced mode is active. Basic mode is activated if you configure the properties that should be shown in the filter. You do so by modifying the EntityQueryFilterConfiguration that is being used.

Activating the default (advanced mode) EntityQuery filter

entities.withType( Group.class )
        .listView( lvb -> lvb.entityQueryFilter( true ) );

Activating basic mode + advanced mode EntityQuery filter

entities.withType( Group.class )
        .listView( lvb -> lvb.entityQueryFilter(
                            eqf -> eqf.showProperties( "name", "active" ) ) );

By default both basic and advanced mode are available, and the UI allows switching between them. Various options are configurable via the EntityQueryFilterConfiguration on a list view.

Filtering is done by via the EntityQueryFilterProcessor, which uses an EntityQueryRequest model for parsing queries, the current filter being used and whether a query supports basic mode. The selected properties are processed via an EntityQueryRequestValueFetcher.

Basic mode

Basic mode enables the use of controls to filter by and will parse the content of the property controls to a valid EQL statement which will then be submitted. The EQL statement itself is based on the name of the property, the value in the control and the operand that has been defined for the control.

Table 1. Default query operands
Property type Operand

String

CONTAINS

Collection

CONTAINS

Default

EQ (Single value)

IN (Multi value)

To divert from the default operands, a custom operand can be set by providing the EntityAttributes.ENTITY_QUERY_OPERAND on the property itself.

Two types of elements are supported by default

Select elements

used for the following property types:

  • Class registered in the EntityRegistry

  • Boolean

  • Enum

Textbox elements

default element to be used.

Example basic filter configuration
entities.withType( Book.class )
        .listView(
            lvb -> lvb.entityQueryFilter(
              eqf -> eqf.showProperties( "title", "author") // create a control for title and author
                        .multiValue( "author" ) // It should be possible to filter on multiple authors
            )
        );
Customizing filter controls

Additional control types (like BootstrapUiElements.RADIO or BootstrapUiElements.CHECKBOX) can be used as well, but these need to be specified manually.

The basic filter form uses the following 2 view element modes which can be set per property:

Property type Operand

FILTER_FORM

Renders the form group for the property. This is a combination of the label (ViewElementMode.LABEL) and the filter control (ViewElementMode.FILTER_CONTROL) for the property. If the control is a single checkbox or radio button, the label will be omitted.

FILTER_CONTROL

Renders the actual control for the property.

Advanced mode

Advanced mode provides a single textbox in which an EQL query can be used, which allows for more complex queries to be used. If both advanced and basic mode are allowed and the EQL statement that was last executed is not convertible to basic mode, basic mode will be disabled.

Example advanced filter configuration
entities.withType( Book.class )
        .listView(
            lvb -> lvb.entityQueryFilter( true )
        );

Searching on values

When filtering items, the id is used by default for managed types. This works fine for most cases, but isn’t very handy when defining more complex queries. By defining an EntityQueryValueEnhancer as EntityAttribute.OPTIONS_ENHANCER on the property, a different, more human-readable value can be used to search on.

Providing an options enhancer
entities.withType( Book.class )
        .listView(
            lvb -> lvb.entityQueryFilter(
              eqf -> eqf.showProperties( "author") // create a control for title and author
                        .properties(
                            props -> props.property( "author" )
                                          .attribute(
                                            EntityAttributes.OPTIONS_ENHANCER,
                                            EQLStringValueOptionEnhancer.create( Author::getEmail ) (1)
                                           )
                        )
            )
        );
1 Instead of querying authors by id, we’d prefer to query them by email, which should be unique over all authors. This will not change how items are presented in the basic control, but will create a query in which the email is used as a value instead of an id.

When filtering on the author John Smith, it would result in query similar to author = 'john.smith@firm.com'.

An EntityQueryValueEnhancer influences how basic controls build the EQL statement, which makes it easier for users to switch between basic and advanced modes. For the statement to work however, you have to ensure that the value can be correctly converted to an instance. As such, in most cases you’ll have to register an additional Converter on the ConversionService that supports conversion from the enhanced value to the object type.

EQL predicate on list view

List views also support a base predicate to be configured as an EQL statement. This base predicate will always be applied to the query being executed.

Ensure deleted (flag) items are never shown

entities.withType( Group.class )
        .listView( lvb -> lvb.entityQueryPredicate( "deleted = false" )	);

Like EQL based filtering, this requires the entity configuration to have a valid EntityQueryExecutor infrastructure.

Entity Query Language
  • Listing of supported operands

  • Listing of default query functions

Customizing entity query filtering
  • Creating custom query functions

  • Query translation, for example case insensitive searching or expanding to multiple properties

  • Value conversion