Getting started

This walks through the full path: model a grid’s columns, accept ag-grid’s request, and run it against Elasticsearch. It mirrors the runnable examples/opensearch-aggrid-demo.

1. Install

Available on Maven Central. Add the adapter — it pulls in gridlink-core:

Maven

<dependency>
    <groupId>io.github.codedogapp</groupId>
    <artifactId>gridlink-elasticsearch</artifactId>
    <version>0.1.0</version>
</dependency>

Gradle

implementation("io.github.codedogapp:gridlink-elasticsearch:0.1.0")

gridlink-elasticsearch declares spring-data-elasticsearch as provided — your application supplies it.

To determine the version compatible with your Spring Boot app, check Spring’s compatibility matrix

2. Model the grid’s columns

Implement FilterModel with one typed component per filterable column.

filters() maps each component to the document field it targets — the key is a field name, not a Java name, so a column may filter a differently named field.

public record ProductFilterModel(
    FieldFilter name,
    FieldFilter category,
    DateFieldFilter createdAt
) implements FilterModel {

    @Override
    public Map<String, ColumnFilter> filters() {
        final var columns = new LinkedHashMap<String, ColumnFilter>();
        columns.put("name", name);          // ag-grid column "name"      -> field "name"
        columns.put("category", category);  // ag-grid column "category"  -> field "category"
        columns.put("createdAt", createdAt);
        return columns;
    }
}
  • Use FieldFilter for text columns, DateFieldFilter for date columns.
  • Columns with no active filter arrive as null and are ignored.
  • Return a LinkedHashMap if a stable column order matters.

3. Accept the request and run the query

GridRequest<F> is generic over your FilterModel, so ag-grid’s JSON binds straight in. One call — ElasticsearchQueries.toQuery — assembles criteria, sort and paging into a CriteriaQuery:

@RestController
@RequiredArgsConstructor
class ProductController {

    private final ElasticsearchOperations operations;

    @PostMapping("/api/products/query")
    GridResponse<Product> query(@RequestBody GridRequest<ProductFilterModel> request) {
        SearchHits<Product> hits = operations.search(ElasticsearchQueries.toQuery(request), Product.class);
        var rows = hits.getSearchHits().stream().map(SearchHit::getContent).toList();
        return new GridResponse<>(rows, hits.getTotalHits());
    }
}

GridResponse<T> carries the page of rows plus lastRow (the total match count) that ag-grid’s infinite model needs to find the end of the dataset.

4. The wire contract

Request — ag-grid’s row window, sort model and filter model:

{
  "startRow": 0,
  "endRow": 50,
  "sortModel": [
    {
      "colId": "price",
      "sort": "desc"
    }
  ],
  "filterModel": {
    "name": {
      "filterType": "text",
      "type": "contains",
      "filter": "mac"
    }
  }
}

Response:

{
  "rows": [
    /* ... up to 50 Product rows ... */
  ],
  "lastRow": 122
}

Next