Class DataTablesQuery

java.lang.Object
org.apache.juneau.console.datatables.adapter.DataTablesQuery

public class DataTablesQuery extends Object
Maps a DataTables request bean onto a BeanQuery, runs it against a BeanQuerySession, and copies the result onto a DataTablesResults response bean.

This adapter is the only place the two worlds meet: the DataTables JSON beans (org.apache.juneau.console.datatables) know nothing about the query engine, and the engine knows nothing about DataTables JSON. The mapping (toBeanQuery(DataTablesRequest, BeanQueryContext)):

  • Each columns[i].data resolves against context.columns(): a declared name is used as is, an all-digits string is the n-th declared column, and null/"" is skipped — resolution only happens for a column something actually uses (a non-blank per-column search, an order[] entry, or global-search eligibility), so a render-only column with an unresolvable data never errors.
  • Each searchable column's non-blank search.value becomes one raw column=expression condition (BeanQuery.Builder#search(String, String)); two DataTables columns resolving to the same key merge into one $and.
  • A non-blank global search.value becomes a top-level $or of one leaf per eligible column (searchable, resolvable), the leaf chosen by that column's SearchType: $contains for SearchType.TEXT/SearchType.ID, $prefix for SearchType.VERSION, $eqic for SearchType.ENUM, and $eq for SearchType.NUMERIC/SearchType.TIMESTAMP/SearchType.BOOLEAN when search.value parses for that type — a parse failure excludes just that column from this request's $or, it never fails the request. Resolved keys are de-duplicated in column order; one eligible column collapses to a plain leaf (a single-item group is unwrapped); an eligible key that also has a per-column search merges into that column's $and.
  • Each order[i] resolves through columns[i] to a sort / sortDesc entry; duplicate keys keep the first occurrence.
  • start/length become the page window (length=-1 means all rows; a negative start is clamped to 0).
  • Counts are always requested (CountRequest.BOTH); the context's own CountPolicy still wins.

columns.size() and order.size() are capped by BeanQueryContext.getMaxSearchClauses() / BeanQueryContext.getMaxSortKeys() before any column is resolved. A caller mistake — an unknown column, too many search clauses, too many sort keys, a malformed expression, a disallowed operator, a restricted column — raises BeanQuerySyntaxException, which run / runArrays do not catch: it propagates to RestContext.convertThrowable, which maps it to HTTP 400 with the server's message in the X-BeanQuery-Error response header (BeanQueryRequest.ERROR_HEADER) — the same contract as every other queryable endpoint. (It is not a 200 response carrying an error field.) The bundled juneau-datatables.js reads that header and shows the message through DataTables' errMode instead of a generic "Ajax error". A BeanQueryExecutionException (a genuine server fault) propagates unchanged to the REST layer's 500 mapping.

Example:

// The endpoint shape. @Rest(mixins=DataTablesMixin.class) public class ReleasesResource extends BasicRestServlet { @RestPost(path="/query", parsers=JsonParser.class) public DataTablesResults<Release> queryReleases(@Content DataTablesRequest request) { try (var session = CONTEXT.getSession(releases)) { return DataTablesQuery.run(request, session); } } }

A caller that needs to add its own condition (e.g. a tenant guard) builds the query directly and merges it with BeanQuery.copy():

BeanQuery query = DataTablesQuery.toBeanQuery(request, session.getContext()); BeanQuery guarded = query.copy().eq("tenant", tenantId).build(); var page = session.find(guarded); return DataTablesResults.<Release>create().setDraw(request.getDraw()).setData(page.rows());

Since:
10.0.0
  • Method Details

    • run

      public static <T> DataTablesResults<T> run(DataTablesRequest request, BeanQuerySession<T> session)
      Runs the DataTables request against the session and builds the response envelope.

      The caller owns the session (open it in a try-with-resources block); this method neither opens nor closes it, so the adapter works identically over an in-memory or a SQL engine. Rows come back as beans (T); use runArrays when columns[i].data are integers and the table expects array rows.

      Type Parameters:
      T - The row type.
      Parameters:
      request - The DataTables request bean. Must not be null.
      session - The open bean-query session. Must not be null.
      Returns:
      The populated DataTables response envelope.
      Throws:
      BeanQuerySyntaxException - If request describes an invalid query. Mapped centrally to HTTP 400 with an X-BeanQuery-Error header.
    • runArrays

      public static DataTablesResults<List<Object>> runArrays(DataTablesRequest request, BeanQuerySession<?> session)
      Runs the DataTables request against the session and builds the response envelope with array rows.

      For a table whose columns[i].data are integers (so there is no bean property to put named fields on): the view is set to every column in context.columns() order, rows come back from findValues, and each row Map is flattened to a List in that same order, so data: n and the n-th array cell refer to the same column.

      Parameters:
      request - The DataTables request bean. Must not be null.
      session - The open bean-query session. Must not be null.
      Returns:
      The populated DataTables response envelope.
      Throws:
      BeanQuerySyntaxException - If request describes an invalid query (see run).
    • toBeanQuery

      public static BeanQuery toBeanQuery(DataTablesRequest request, BeanQueryContext<?> context)
      Translates a DataTables request into an engine BeanQuery (search, sort, page window, counts) against the given context's declared columns.
      Parameters:
      request - The DataTables request bean. Must not be null.
      context - The context the query will run against. Must not be null. Its columns() / getColumnType(String) / getMaxSearchClauses() / getMaxSortKeys() drive every resolution and cap below. A session that narrows its columns (restrictColumns) is not visible here — the query pipeline still rejects a restricted column, reported through the same BeanQuerySyntaxException path.
      Returns:
      The equivalent query.
      Throws:
      BeanQuerySyntaxException - If columns/order exceed the context's caps, or a search/sort target names an unresolvable column.