001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.console.datatables;
018
019import java.util.*;
020
021/**
022 * The DataTables server-side-processing response envelope.
023 *
024 * <p>
025 * Serializes (via the normal negotiated serializer) to the JSON shape DataTables expects from a server-side source:
026 * <p class='bjson'>
027 *    {
028 *       <jf>draw</jf>: 1,
029 *       <jf>recordsTotal</jf>: 57,
030 *       <jf>recordsFiltered</jf>: 12,
031 *       <jf>data</jf>: [ ... ]
032 *    }
033 * </p>
034 *
035 * <ul class='spaced-list'>
036 *    <li>{@link #getDraw() draw} &mdash; the draw counter echoed back from the request (cast to a number by DataTables).
037 *    <li>{@link #getRecordsTotal() recordsTotal} &mdash; total records before filtering.
038 *    <li>{@link #getRecordsFiltered() recordsFiltered} &mdash; records after filtering (before paging).
039 *    <li>{@link #getData() data} &mdash; the page of rows.
040 *    <li>{@link #getError() error} &mdash; optional error message (omitted from the response when <jk>null</jk>).
041 * </ul>
042 *
043 * <h5 class='section'>Example:</h5>
044 * <p class='bjava'>
045 *    <jc>// A normal page of results.</jc>
046 *    DataTablesResults&lt;Person&gt; <jv>results</jv> = DataTablesResults.&lt;Person&gt;<jsm>create</jsm>()
047 *       .setDraw(<jv>request</jv>.getDraw())
048 *       .setRecordsTotal(<jv>page</jv>.total().orElse(0))
049 *       .setRecordsFiltered(<jv>page</jv>.matched().orElse(0))
050 *       .setData(<jv>page</jv>.rows());
051 *
052 *    <jc>// An explicit application-level error envelope (HTTP 200; DataTablesQuery itself no longer builds one).</jc>
053 *    DataTablesResults&lt;Person&gt; <jv>errorResults</jv> = DataTablesResults.<jsm>error</jsm>(<jv>request</jv>.getDraw(), <js>"Unknown column 'x'."</js>);
054 * </p>
055 *
056 * @param <T> The row type.
057 *
058 * @since 10.0.0
059 */
060public class DataTablesResults<T> {
061
062   private int draw;
063   private long recordsTotal;
064   private long recordsFiltered;
065   private List<T> data;
066   private String error;
067
068   /**
069    * Constructor.
070    */
071   public DataTablesResults() { /* All fields are populated via the fluent setters below. */ }
072
073   /**
074    * Static creator.
075    *
076    * @param <T> The row type.
077    * @return A new empty {@link DataTablesResults}.
078    */
079   public static <T> DataTablesResults<T> create() {
080      return new DataTablesResults<>();
081   }
082
083   /**
084    * Builds an error envelope: the draw counter echoed back, no rows, and no counts, with the caller's error message.
085    *
086    * <p>
087    * For an application-level failure an endpoint wants to report with HTTP 200 so DataTables surfaces {@link #getError()
088    * error} through its {@code errMode}.  Note that {@code DataTablesQuery} no longer uses this for a
089    * {@code BeanQuerySyntaxException} (unknown column, too many search clauses, ...): since 2026-10-05 that propagates
090    * and is mapped centrally to HTTP 400 with an {@code X-BeanQuery-Error} header.
091    *
092    * <h5 class='section'>Example:</h5>
093    * <p class='bjava'>
094    *    <jk>return</jk> DataTablesResults.<jsm>error</jsm>(<jv>request</jv>.getDraw(), <js>"Unknown column 'x'."</js>);
095    * </p>
096    *
097    * @param <T> The row type.
098    * @param draw The draw counter to echo back.
099    * @param message The error message to show.
100    * @return A new {@link DataTablesResults} with only {@code draw} and {@code error} set.
101    */
102   public static <T> DataTablesResults<T> error(int draw, String message) {
103      return DataTablesResults.<T>create().setDraw(draw).setError(message);
104   }
105
106   /**
107    * Returns the draw counter.
108    *
109    * @return The draw counter.
110    */
111   public int getDraw() {
112      return draw;
113   }
114
115   /**
116    * Sets the draw counter.
117    *
118    * @param value The value.
119    * @return This object.
120    */
121   public DataTablesResults<T> setDraw(int value) {
122      this.draw = value;
123      return this;
124   }
125
126   /**
127    * Returns the total record count before filtering.
128    *
129    * @return The total record count.
130    */
131   public long getRecordsTotal() {
132      return recordsTotal;
133   }
134
135   /**
136    * Sets the total record count before filtering.
137    *
138    * @param value The value.
139    * @return This object.
140    */
141   public DataTablesResults<T> setRecordsTotal(long value) {
142      this.recordsTotal = value;
143      return this;
144   }
145
146   /**
147    * Returns the record count after filtering (before paging).
148    *
149    * @return The filtered record count.
150    */
151   public long getRecordsFiltered() {
152      return recordsFiltered;
153   }
154
155   /**
156    * Sets the record count after filtering (before paging).
157    *
158    * @param value The value.
159    * @return This object.
160    */
161   public DataTablesResults<T> setRecordsFiltered(long value) {
162      this.recordsFiltered = value;
163      return this;
164   }
165
166   /**
167    * Returns the page of rows.
168    *
169    * @return The page of rows.  Can be <jk>null</jk>.
170    */
171   public List<T> getData() {
172      return data;
173   }
174
175   /**
176    * Sets the page of rows.
177    *
178    * @param value The value.
179    * @return This object.
180    */
181   public DataTablesResults<T> setData(List<T> value) {
182      this.data = value;
183      return this;
184   }
185
186   /**
187    * Returns the optional error message.
188    *
189    * @return The error message, or <jk>null</jk> if none.
190    */
191   public String getError() {
192      return error;
193   }
194
195   /**
196    * Sets the optional error message.
197    *
198    * @param value The value.
199    * @return This object.
200    */
201   public DataTablesResults<T> setError(String value) {
202      this.error = value;
203      return this;
204   }
205}