001package org.avaje.ebean.typequery;
002
003import com.avaje.ebean.*;
004import com.avaje.ebean.search.MultiMatch;
005import com.avaje.ebean.search.TextCommonTerms;
006import com.avaje.ebean.search.TextQueryString;
007import com.avaje.ebean.search.TextSimple;
008import com.avaje.ebean.text.PathProperties;
009import com.avaje.ebeaninternal.server.util.ArrayStack;
010import org.jetbrains.annotations.Nullable;
011
012import java.sql.Timestamp;
013import java.util.List;
014import java.util.Map;
015import java.util.Set;
016
017/**
018 * Base root query bean.
019 * <p>
020 * With code generation for each entity bean type a query bean is created that extends this.
021 * <p>
022 * Provides common features for all root query beans
023 * </p>
024 * <p>
025 * <h2>Example - QCustomer extends TQRootBean</h2>
026 * <p>
027 * These 'query beans' like QCustomer are generated using the <code>avaje-ebeanorm-typequery-generator</code>.
028 * </p>
029 * <pre>{@code
030 *
031 *   public class QCustomer extends TQRootBean<Customer,QCustomer> {
032 *
033 *     // properties
034 *     public PLong<QCustomer> id;
035 *
036 *     public PString<QCustomer> name;
037 *     ...
038 *
039 * }</pre>
040 * <p>
041 * <h2>Example - usage of QCustomer</h2>
042 * <pre>{@code
043 *
044 *    Date fiveDaysAgo = ...
045 *
046 *    List<Customer> customers =
047 *        new QCustomer()
048 *          .name.ilike("rob")
049 *          .status.equalTo(Customer.Status.GOOD)
050 *          .registered.after(fiveDaysAgo)
051 *          .contacts.email.endsWith("@foo.com")
052 *          .orderBy()
053 *            .name.asc()
054 *            .registered.desc()
055 *          .findList();
056 *
057 * }</pre>
058 * <p>
059 * <h2>Resulting SQL where</h2>
060 * <p>
061 * <pre>{@code sql
062 *
063 *     where lower(t0.name) like ?  and t0.status = ?  and t0.registered > ?  and u1.email like ?
064 *     order by t0.name, t0.registered desc;
065 *
066 *     --bind(rob,GOOD,Mon Jul 27 12:05:37 NZST 2015,%@foo.com)
067 * }</pre>
068 *
069 * @param <T> the entity bean type (normal entity bean type e.g. Customer)
070 * @param <R> the specific root query bean type (e.g. QCustomer)
071 */
072public abstract class TQRootBean<T, R> {
073
074  /**
075   * The underlying query.
076   */
077  private final Query<T> query;
078
079  /**
080   * The underlying expression lists held as a stack. Pushed and popped based on and/or (conjunction/disjunction).
081   */
082  private ArrayStack<ExpressionList<T>> whereStack;
083
084  /**
085   * Stack of Text expressions ("query" section of ElasticSearch query rather than "filter" section).
086   */
087  private ArrayStack<ExpressionList<T>> textStack;
088
089  /**
090   * When true expressions should be added to the "text" stack - ElasticSearch "query" section
091   * rather than the "where" stack.
092   */
093  private boolean textMode;
094
095  /**
096   * The root query bean instance. Used to provide fluid query construction.
097   */
098  private R root;
099
100  /**
101   * Construct using the type of bean to query on and the default server.
102   */
103  public TQRootBean(Class<T> beanType) {
104    this(beanType, Ebean.getDefaultServer());
105  }
106
107  /**
108   * Construct using the type of bean to query on and a given server.
109   */
110  public TQRootBean(Class<T> beanType, EbeanServer server) {
111    this(server.find(beanType));
112  }
113
114  /**
115   * Construct using a query.
116   */
117  public TQRootBean(Query<T> query) {
118    this.query = query;
119  }
120
121  /**
122   * Construct for using as an 'Alias' to use the properties as known string
123   * values for select() and fetch().
124   */
125  public TQRootBean(boolean aliasDummy) {
126    this.query = null;
127  }
128
129  /**
130   * Sets the root query bean instance. Used to provide fluid query construction.
131   */
132  protected void setRoot(R root) {
133    this.root = root;
134  }
135
136  /**
137   * Return the underlying query.
138   * <p>
139   * Generally it is not expected that you will need to do this but typically use
140   * the find methods available on this 'root query bean' instance like findList().
141   * </p>
142   */
143  public Query<T> query() {
144    return query;
145  }
146
147  /**
148   * Explicitly set a comma delimited list of the properties to fetch on the
149   * 'main' root level entity bean (aka partial object). Note that '*' means all
150   * properties.
151   * <p>
152   * You use {@link #fetch(String, String)} to specify specific properties to fetch
153   * on other non-root level paths of the object graph.
154   * </p>
155   * <p>
156   * <pre>{@code
157   *
158   * List<Customer> customers =
159   *     new QCustomer()
160   *     // Only fetch the customer id, name and status.
161   *     // This is described as a "Partial Object"
162   *     .select("name, status")
163   *     .name.ilike("rob%")
164   *     .findList();
165   *
166   * }</pre>
167   *
168   * @param fetchProperties the properties to fetch for this bean (* = all properties).
169   */
170  public R select(String fetchProperties) {
171    query.select(fetchProperties);
172    return root;
173  }
174
175  /**
176   * Tune the query by specifying the properties to be loaded on the
177   * 'main' root level entity bean (aka partial object).
178   * <pre>{@code
179   *
180   *   // alias for the customer properties in select()
181   *   QCustomer cust = QCustomer.alias();
182   *
183   *   // alias for the contact properties in contacts.fetch()
184   *   QContact contact = QContact.alias();
185   *
186   *   List<Customer> customers =
187   *     new QCustomer()
188   *       // tune query
189   *       .select(cust.id, cust.name)
190   *       .contacts.fetch(contact.firstName, contact.lastName, contact.email)
191   *
192   *       // predicates
193   *       .id.greaterThan(1)
194   *       .findList();
195   *
196   * }</pre>
197   *
198   * @param properties the list of properties to fetch
199   */
200  @SafeVarargs
201  public final R select(TQProperty<R>... properties) {
202    StringBuilder selectProps = new StringBuilder(50);
203    for (int i = 0; i < properties.length; i++) {
204      if (i > 0) {
205        selectProps.append(",");
206      }
207      selectProps.append(properties[i].propertyName());
208    }
209    query.select(selectProps.toString());
210    return root;
211  }
212
213  /**
214   * Specify a path to load including all its properties.
215   * <p>
216   * The same as {@link #fetch(String, String)} with the fetchProperties as "*".
217   * </p>
218   * <pre>{@code
219   *
220   * // fetch customers (their id, name and status)
221   * List<Customer> customers =
222   *     ebeanServer.find(Customer.class)
223   *     // eager fetch the contacts
224   *     .fetch("contacts")
225   *     .findList();
226   *
227   * }</pre>
228   *
229   * @param path the property of an associated (1-1,1-M,M-1,M-M) bean.
230   */
231  public R fetch(String path) {
232    query.fetch(path);
233    return root;
234  }
235
236  /**
237   * Specify a path to <em>fetch</em> with its specific properties to include
238   * (aka partial object).
239   * <p>
240   * When you specify a join this means that property (associated bean(s)) will
241   * be fetched and populated. If you specify "*" then all the properties of the
242   * associated bean will be fetched and populated. You can specify a comma
243   * delimited list of the properties of that associated bean which means that
244   * only those properties are fetched and populated resulting in a
245   * "Partial Object" - a bean that only has some of its properties populated.
246   * </p>
247   * <p>
248   * <pre>{@code
249   *
250   * // query orders...
251   * List<Order> orders =
252   *     ebeanserver.find(Order.class)
253   *       // fetch the customer...
254   *       // ... getting the customers name and phone number
255   *       .fetch("customer", "name, phoneNumber")
256   *
257   *       // ... also fetch the customers billing address (* = all properties)
258   *       .fetch("customer.billingAddress", "*")
259   *       .findList();
260   * }</pre>
261   * <p>
262   * <p>
263   * If columns is null or "*" then all columns/properties for that path are
264   * fetched.
265   * </p>
266   * <p>
267   * <pre>{@code
268   *
269   * // fetch customers (their id, name and status)
270   * List<Customer> customers =
271   *     new QCustomer()
272   *     .select("name, status")
273   *     .fetch("contacts", "firstName,lastName,email")
274   *     .findList();
275   *
276   * }</pre>
277   *
278   * @param path            the path of an associated (1-1,1-M,M-1,M-M) bean.
279   * @param fetchProperties properties of the associated bean that you want to include in the
280   *                        fetch (* means all properties, null also means all properties).
281   */
282  public R fetch(String path, String fetchProperties) {
283    query.fetch(path, fetchProperties);
284    return root;
285  }
286
287  /**
288   * Additionally specify a FetchConfig to use a separate query or lazy loading
289   * to load this path.
290   * <p>
291   * <pre>{@code
292   *
293   * // fetch customers (their id, name and status)
294   * List<Customer> customers =
295   *     new QCustomer()
296   *     .select("name, status")
297   *     .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
298   *     .findList();
299   *
300   * }</pre>
301   */
302  public R fetch(String path, String fetchProperties, FetchConfig fetchConfig) {
303    query.fetch(path, fetchProperties, fetchConfig);
304    return root;
305  }
306
307  /**
308   * Additionally specify a FetchConfig to specify a "query join" and or define
309   * the lazy loading query.
310   * <p>
311   * <pre>{@code
312   *
313   * // fetch customers (their id, name and status)
314   * List<Customer> customers =
315   *     new QCustomer()
316   *       // lazy fetch contacts with a batch size of 100
317   *       .fetch("contacts", new FetchConfig().lazy(100))
318   *       .findList();
319   *
320   * }</pre>
321   */
322  public R fetch(String path, FetchConfig fetchConfig) {
323    query.fetch(path, fetchConfig);
324    return root;
325  }
326
327  /**
328   * Apply the path properties replacing the select and fetch clauses.
329   * <p>
330   * This is typically used when the PathProperties is applied to both the query and the JSON output.
331   * </p>
332   */
333  public R apply(PathProperties pathProperties) {
334    query.apply(pathProperties);
335    return root;
336  }
337
338  /**
339   * Perform an 'As of' query using history tables to return the object graph
340   * as of a time in the past.
341   * <p>
342   * To perform this query the DB must have underlying history tables.
343   * </p>
344   *
345   * @param asOf the date time in the past at which you want to view the data
346   */
347  public R asOf(Timestamp asOf) {
348    query.asOf(asOf);
349    return root;
350  }
351
352  /**
353   * Execute the query against the draft set of tables.
354   */
355  public R asDraft() {
356    query.asDraft();
357    return root;
358  }
359
360  /**
361   * Execute the query including soft deleted rows.
362   */
363  public R includeSoftDeletes() {
364    query.includeSoftDeletes();
365    return root;
366  }
367
368  /**
369   * Set root table alias.
370   */
371  public R alias(String alias) {
372    query.alias(alias);
373    return root;
374  }
375
376  /**
377   * Set the maximum number of rows to return in the query.
378   *
379   * @param maxRows the maximum number of rows to return in the query.
380   */
381  public R setMaxRows(int maxRows) {
382    query.setMaxRows(maxRows);
383    return root;
384  }
385
386  /**
387   * Set the first row to return for this query.
388   *
389   * @param firstRow the first row to include in the query result.
390   */
391  public R setFirstRow(int firstRow) {
392    query.setFirstRow(firstRow);
393    return root;
394  }
395
396  /**
397   * Explicitly specify whether to use AutoTune for this query.
398   * <p>
399   * If you do not call this method on a query the "Implicit AutoTune mode" is
400   * used to determine if AutoTune should be used for a given query.
401   * </p>
402   * <p>
403   * AutoTune can add additional fetch paths to the query and specify which
404   * properties are included for each path. If you have explicitly defined some
405   * fetch paths AutoTune will not remove them.
406   * </p>
407   */
408  public R setAutoTune(boolean autoTune) {
409    query.setAutoTune(autoTune);
410    return root;
411  }
412
413  /**
414   * A hint which for JDBC translates to the Statement.fetchSize().
415   * <p>
416   * Gives the JDBC driver a hint as to the number of rows that should be
417   * fetched from the database when more rows are needed for ResultSet.
418   * </p>
419   */
420  public R setBufferFetchSizeHint(int fetchSize) {
421    query.setBufferFetchSizeHint(fetchSize);
422    return root;
423  }
424
425  /**
426   * Set whether this query uses DISTINCT.
427   */
428  public R setDistinct(boolean distinct) {
429    query.setDistinct(distinct);
430    return root;
431  }
432
433  /**
434   * executed the select with "for update" which should lock the record
435   * "on read"
436   */
437  public R setForUpdate(boolean forUpdate) {
438    query.setForUpdate(forUpdate);
439    return root;
440  }
441
442  /**
443   * Set the Id value to query. This is used with findUnique().
444   * <p>
445   * You can use this to have further control over the query. For example adding
446   * fetch joins.
447   * </p>
448   * <p>
449   * <pre>{@code
450   *
451   * Order order =
452   *   new QOrder()
453   *     .setId(1)
454   *     .fetch("details")
455   *     .findUnique();
456   *
457   * // the order details were eagerly fetched
458   * List<OrderDetail> details = order.getDetails();
459   *
460   * }</pre>
461   */
462  public R setId(Object id) {
463    query.setId(id);
464    return root;
465  }
466
467  /**
468   * Set the default lazy loading batch size to use.
469   * <p>
470   * When lazy loading is invoked on beans loaded by this query then this sets the
471   * batch size used to load those beans.
472   *
473   * @param lazyLoadBatchSize the number of beans to lazy load in a single batch
474   */
475  public R setLazyLoadBatchSize(int lazyLoadBatchSize) {
476    query.setLazyLoadBatchSize(lazyLoadBatchSize);
477    return root;
478  }
479
480  /**
481   * When set to true all the beans from this query are loaded into the bean
482   * cache.
483   */
484  public R setLoadBeanCache(boolean loadBeanCache) {
485    query.setLoadBeanCache(loadBeanCache);
486    return root;
487  }
488
489  /**
490   * Set the property to use as keys for a map.
491   * <p>
492   * If no property is set then the id property is used.
493   * </p>
494   * <p>
495   * <pre>{@code
496   *
497   * // Assuming sku is unique for products...
498   *
499   * Map<?,Product> productMap =
500   *     new QProduct()
501   *     // use sku for keys...
502   *     .setMapKey("sku")
503   *     .findMap();
504   *
505   * }</pre>
506   *
507   * @param mapKey the property to use as keys for a map.
508   */
509  public R setMapKey(String mapKey) {
510    query.setMapKey(mapKey);
511    return root;
512  }
513
514  /**
515   * Specify the PersistenceContextScope to use for this query.
516   * <p>
517   * When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
518   * is used - this value defaults to {@link com.avaje.ebean.PersistenceContextScope#TRANSACTION}.
519   * <p>
520   * Note that the same persistence Context is used for subsequent lazy loading and query join queries.
521   * <p>
522   * Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for
523   * queries executed as #findIterate, #findEach, #findEachWhile.
524   *
525   * @param scope The scope to use for this query and subsequent lazy loading.
526   */
527  public R setPersistenceContextScope(PersistenceContextScope scope) {
528    query.setPersistenceContextScope(scope);
529    return root;
530  }
531
532  /**
533   * Set RawSql to use for this query.
534   */
535  public R setRawSql(RawSql rawSql) {
536    query.setRawSql(rawSql);
537    return root;
538  }
539
540  /**
541   * When set to true when you want the returned beans to be read only.
542   */
543  public R setReadOnly(boolean readOnly) {
544    query.setReadOnly(readOnly);
545    return root;
546  }
547
548  /**
549   * Set this to true to use the bean cache.
550   * <p>
551   * If the query result is in cache then by default this same instance is
552   * returned. In this sense it should be treated as a read only object graph.
553   * </p>
554   */
555  public R setUseCache(boolean useCache) {
556    query.setUseCache(useCache);
557    return root;
558  }
559
560  /**
561   * Set to true if this query should execute against the doc store.
562   * <p>
563   * When setting this you may also consider disabling lazy loading.
564   * </p>
565   */
566  public R setUseDocStore(boolean useDocStore) {
567    query.setUseDocStore(useDocStore);
568    return root;
569  }
570
571  /**
572   * Set true if you want to disable lazy loading.
573   * <p>
574   * That is, once the object graph is returned further lazy loading is disabled.
575   * </p>
576   */
577  public R setDisableLazyLoading(boolean disableLazyLoading) {
578    query.setDisableLazyLoading(disableLazyLoading);
579    return root;
580  }
581
582  /**
583   * Disable read auditing for this query.
584   * <p>
585   * This is intended to be used when the query is not a user initiated query and instead
586   * part of the internal processing in an application to load a cache or document store etc.
587   * In these cases we don't want the query to be part of read auditing.
588   * </p>
589   */
590  public R setDisableReadAuditing() {
591    query.setDisableReadAuditing();
592    return root;
593  }
594
595  /**
596   * Set this to true to use the query cache.
597   */
598  public R setUseQueryCache(boolean useCache) {
599    query.setUseQueryCache(useCache);
600    return root;
601  }
602
603  /**
604   * Set a timeout on this query.
605   * <p>
606   * This will typically result in a call to setQueryTimeout() on a
607   * preparedStatement. If the timeout occurs an exception will be thrown - this
608   * will be a SQLException wrapped up in a PersistenceException.
609   * </p>
610   *
611   * @param secs the query timeout limit in seconds. Zero means there is no limit.
612   */
613  public R setTimeout(int secs) {
614    query.setTimeout(secs);
615    return root;
616  }
617
618  /**
619   * Returns the set of properties or paths that are unknown (do not map to known properties or paths).
620   * <p>
621   * Validate the query checking the where and orderBy expression paths to confirm if
622   * they represent valid properties or paths for the given bean type.
623   * </p>
624   */
625  public Set<String> validate() {
626    return query.validate();
627  }
628
629  /**
630   * Add raw expression with no parameters.
631   * <p>
632   * When properties in the clause are fully qualified as table-column names
633   * then they are not translated. logical property name names (not fully
634   * qualified) will still be translated to their physical name.
635   * </p>
636   * <p>
637   * <pre>{@code
638   *
639   *   raw("orderQty < shipQty")
640   *
641   * }</pre>
642   */
643  public R raw(String rawExpression) {
644    peekExprList().raw(rawExpression);
645    return root;
646  }
647
648  /**
649   * Add raw expression with an array of parameters.
650   * <p>
651   * The raw expression should contain the same number of ? as there are
652   * parameters.
653   * </p>
654   * <p>
655   * When properties in the clause are fully qualified as table-column names
656   * then they are not translated. logical property name names (not fully
657   * qualified) will still be translated to their physical name.
658   * </p>
659   */
660  public R raw(String rawExpression, Object... bindValues) {
661    peekExprList().raw(rawExpression, bindValues);
662    return root;
663  }
664
665  /**
666   * Add raw expression with a single parameter.
667   * <p>
668   * The raw expression should contain a single ? at the location of the
669   * parameter.
670   * </p>
671   * <p>
672   * When properties in the clause are fully qualified as table-column names
673   * then they are not translated. logical property name names (not fully
674   * qualified) will still be translated to their physical name.
675   * </p>
676   * <p>
677   * <h4>Example:</h4>
678   * <pre>{@code
679   *
680   *   // use a database function
681   *   raw("add_days(orderDate, 10) < ?", someDate)
682   *
683   * }</pre>
684   */
685  public R raw(String rawExpression, Object bindValue) {
686    peekExprList().raw(rawExpression, bindValue);
687    return root;
688  }
689
690  /**
691   * Marker that can be used to indicate that the order by clause is defined after this.
692   * <p>
693   * order() and orderBy() are synonyms and both exist for historic reasons.
694   * </p>
695   * <p>
696   * <h2>Example: order by customer name, order date</h2>
697   * <pre>{@code
698   *   List<Order> orders =
699   *          new QOrder()
700   *            .customer.name.ilike("rob")
701   *            .orderBy()
702   *              .customer.name.asc()
703   *              .orderDate.asc()
704   *            .findList();
705   *
706   * }</pre>
707   */
708  public R orderBy() {
709    // Yes this does not actually do anything! We include it because style wise it makes
710    // the query nicer to read and suggests that order by definitions are added after this
711    return root;
712  }
713
714  /**
715   * Marker that can be used to indicate that the order by clause is defined after this.
716   * <p>
717   * order() and orderBy() are synonyms and both exist for historic reasons.
718   * </p>
719   * <p>
720   * <h2>Example: order by customer name, order date</h2>
721   * <pre>{@code
722   *   List<Order> orders =
723   *          new QOrder()
724   *            .customer.name.ilike("rob")
725   *            .order()
726   *              .customer.name.asc()
727   *              .orderDate.asc()
728   *            .findList();
729   *
730   * }</pre>
731   */
732  public R order() {
733    // Yes this does not actually do anything! We include it because style wise it makes
734    // the query nicer to read and suggests that order by definitions are added after this
735    return root;
736  }
737
738
739  /**
740   * Set the full raw order by clause replacing the existing order by clause if there is one.
741   * <p>
742   * This follows SQL syntax using commas between each property with the
743   * optional asc and desc keywords representing ascending and descending order
744   * respectively.
745   * </p>
746   * <p>
747   * This is EXACTLY the same as {@link #order(String)}.
748   * </p>
749   */
750  public R orderBy(String orderByClause) {
751    query.orderBy(orderByClause);
752    return root;
753  }
754
755  /**
756   * Set the full raw order by clause replacing the existing order by clause if there is one.
757   * <p>
758   * This follows SQL syntax using commas between each property with the
759   * optional asc and desc keywords representing ascending and descending order
760   * respectively.
761   * </p>
762   * <p>
763   * This is EXACTLY the same as {@link #orderBy(String)}.
764   * </p>
765   */
766  public R order(String orderByClause) {
767    query.order(orderByClause);
768    return root;
769  }
770
771  /**
772   * Begin a list of expressions added by 'OR'.
773   * <p>
774   * Use endJunction() to stop added to OR and 'pop' to the parent expression list.
775   * </p>
776   *
777   * <h2>Example</h2>
778   * <p>
779   * This example uses an 'OR' expression list with an inner 'AND' expression list.
780   * </p>
781   * <pre>{@code
782   *
783   *    List<Customer> customers =
784   *          new QCustomer()
785   *            .status.equalTo(Customer.Status.GOOD)
786   *            .or()
787   *              .id.greaterThan(1000)
788   *              .and()
789   *                .name.startsWith("super")
790   *                .registered.after(fiveDaysAgo)
791   *              .endAnd()
792   *            .endOr()
793   *            .orderBy().id.desc()
794   *            .findList();
795   *
796   * }</pre>
797   * <h2>Resulting SQL where clause</h2>
798   * <pre>{@code sql
799   *    where t0.status = ?  and (t0.id > ?  or (t0.name like ?  and t0.registered > ? ) )
800   *    order by t0.id desc;
801   *
802   *    --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
803   *
804   * }</pre>
805   */
806  public R or() {
807    pushExprList(peekExprList().or());
808    return root;
809  }
810
811  /**
812   * Begin a list of expressions added by 'AND'.
813   * <p>
814   * Use endJunction() to stop added to AND and 'pop' to the parent expression list.
815   * </p>
816   * <p>
817   * Note that typically the AND expression is only used inside an outer 'OR' expression.
818   * This is because the top level expression list defaults to an 'AND' expression list.
819   * </p>
820   * <h2>Example</h2>
821   * <p>
822   * This example uses an 'OR' expression list with an inner 'AND' expression list.
823   * </p>
824   * <pre>{@code
825   *
826   *    List<Customer> customers =
827   *          new QCustomer()
828   *            .status.equalTo(Customer.Status.GOOD)
829   *            .or() // OUTER 'OR'
830   *              .id.greaterThan(1000)
831   *              .and()  // NESTED 'AND' expression list
832   *                .name.startsWith("super")
833   *                .registered.after(fiveDaysAgo)
834   *                .endJunction()
835   *              .endJunction()
836   *            .orderBy().id.desc()
837   *            .findList();
838   *
839   * }</pre>
840   * <h2>Resulting SQL where clause</h2>
841   * <pre>{@code sql
842   *    where t0.status = ?  and (t0.id > ?  or (t0.name like ?  and t0.registered > ? ) )
843   *    order by t0.id desc;
844   *
845   *    --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
846   *
847   * }</pre>
848   */
849  public R and() {
850    pushExprList(peekExprList().and());
851    return root;
852  }
853
854  /**
855   * Begin a list of expressions added by NOT.
856   * <p>
857   * Use endJunction() to stop added to NOT and 'pop' to the parent expression list.
858   * </p>
859   */
860  public R not() {
861    pushExprList(peekExprList().not());
862    return root;
863  }
864
865  /**
866   * Begin a list of expressions added by MUST.
867   * <p>
868   * This automatically makes this query a document store query.
869   * </p>
870   * <p>
871   * Use endJunction() to stop added to MUST and 'pop' to the parent expression list.
872   * </p>
873   */
874  public R must() {
875    pushExprList(peekExprList().must());
876    return root;
877  }
878
879  /**
880   * Begin a list of expressions added by MUST NOT.
881   * <p>
882   * This automatically makes this query a document store query.
883   * </p>
884   * <p>
885   * Use endJunction() to stop added to MUST NOT and 'pop' to the parent expression list.
886   * </p>
887   */
888  public R mustNot() {
889    return pushExprList(peekExprList().mustNot());
890  }
891
892  /**
893   * Begin a list of expressions added by SHOULD.
894   * <p>
895   * This automatically makes this query a document store query.
896   * </p>
897   * <p>
898   * Use endJunction() to stop added to SHOULD and 'pop' to the parent expression list.
899   * </p>
900   */
901  public R should() {
902    return pushExprList(peekExprList().should());
903  }
904
905  /**
906   * End a list of expressions added by 'OR'.
907   */
908  public R endJunction() {
909    if (textMode) {
910      textStack.pop();
911    } else {
912      whereStack.pop();
913    }
914    return root;
915  }
916
917  /**
918   * Deprecated - replace with endJunction().
919   * @deprecated
920   */
921  public R endOr() {
922    return endJunction();
923  }
924
925  /**
926   * Deprecated - replace with endJunction().
927   * @deprecated
928   */
929  public R endAnd() {
930    return endJunction();
931  }
932
933  /**
934   * Push the expression list onto the appropriate stack.
935   */
936  private R pushExprList(ExpressionList<T> list) {
937    if (textMode) {
938      textStack.push(list);
939    } else {
940      whereStack.push(list);
941    }
942    return root;
943  }
944
945  /**
946   * Add expression after this to the WHERE expression list.
947   * <p>
948   * For queries against the normal database (not the doc store) this has no effect.
949   * </p>
950   * <p>
951   * This is intended for use with Document Store / ElasticSearch where expressions can be put into either
952   * the "query" section or the "filter" section of the query. Full text expressions like MATCH are in the
953   * "query" section but many expression can be in either - expressions after the where() are put into the
954   * "filter" section which means that they don't add to the relevance and are also cache-able.
955   * </p>
956   */
957  public R where() {
958    textMode = false;
959    return root;
960  }
961
962  /**
963   * Begin added expressions to the 'Text' expression list.
964   * <p>
965   * This automatically makes the query a document store query.
966   * </p>
967   * <p>
968   * For ElasticSearch expressions added to 'text' go into the ElasticSearch 'query context'
969   * and expressions added to 'where' go into the ElasticSearch 'filter context'.
970   * </p>
971   */
972  public R text() {
973    textMode = true;
974    return root;
975  }
976
977  /**
978   * Add a Text Multi-match expression (document store only).
979   * <p>
980   * This automatically makes the query a document store query.
981   * </p>
982   */
983  public R multiMatch(String query, MultiMatch multiMatch) {
984    peekExprList().multiMatch(query, multiMatch);
985    return root;
986  }
987
988  /**
989   * Add a Text Multi-match expression (document store only).
990   * <p>
991   * This automatically makes the query a document store query.
992   * </p>
993   */
994  public R multiMatch(String query, String... properties) {
995    peekExprList().multiMatch(query, properties);
996    return root;
997  }
998
999  /**
1000   * Add a Text common terms expression (document store only).
1001   * <p>
1002   * This automatically makes the query a document store query.
1003   * </p>
1004   */
1005  public R textCommonTerms(String query, TextCommonTerms options) {
1006    peekExprList().textCommonTerms(query, options);
1007    return root;
1008  }
1009
1010  /**
1011   * Add a Text simple expression (document store only).
1012   * <p>
1013   * This automatically makes the query a document store query.
1014   * </p>
1015   */
1016  public R textSimple(String query, TextSimple options) {
1017    peekExprList().textSimple(query, options);
1018    return root;
1019  }
1020
1021  /**
1022   * Add a Text query string expression (document store only).
1023   * <p>
1024   * This automatically makes the query a document store query.
1025   * </p>
1026   */
1027  public R textQueryString(String query, TextQueryString options) {
1028    peekExprList().textQueryString(query, options);
1029    return root;
1030  }
1031
1032  /**
1033   * Execute the query returning either a single bean or null (if no matching
1034   * bean is found).
1035   * <p>
1036   * If more than 1 row is found for this query then a PersistenceException is
1037   * thrown.
1038   * </p>
1039   * <p>
1040   * This is useful when your predicates dictate that your query should only
1041   * return 0 or 1 results.
1042   * </p>
1043   * <p>
1044   * <pre>{@code
1045   *
1046   * // assuming the sku of products is unique...
1047   * Product product =
1048   *     new QProduct()
1049   *         .sku.equalTo("aa113")
1050   *         .findUnique();
1051   * ...
1052   * }</pre>
1053   * <p>
1054   * <p>
1055   * It is also useful with finding objects by their id when you want to specify
1056   * further join information to optimise the query.
1057   * </p>
1058   * <p>
1059   * <pre>{@code
1060   *
1061   * // Fetch order 42 and additionally fetch join its order details...
1062   * Order order =
1063   *     new QOrder()
1064   *         .fetch("details") // eagerly load the order details
1065   *         .id.equalTo(42)
1066   *         .findUnique();
1067   *
1068   * // the order details were eagerly loaded
1069   * List<OrderDetail> details = order.getDetails();
1070   * ...
1071   * }</pre>
1072   */
1073  @Nullable
1074  public T findUnique() {
1075    return query.findUnique();
1076  }
1077
1078  /**
1079   * Execute the query returning the list of objects.
1080   * <p>
1081   * This query will execute against the EbeanServer that was used to create it.
1082   * </p>
1083   * <p>
1084   * <pre>{@code
1085   *
1086   * List<Customer> customers =
1087   *     new QCustomer()
1088   *       .name.ilike("rob%")
1089   *       .findList();
1090   *
1091   * }</pre>
1092   *
1093   * @see EbeanServer#findList(Query, Transaction)
1094   */
1095  public List<T> findList() {
1096    return query.findList();
1097  }
1098
1099  /**
1100   * Execute the query returning the list of Id's.
1101   * <p>
1102   * This query will execute against the EbeanServer that was used to create it.
1103   * </p>
1104   *
1105   * @see EbeanServer#findIds(Query, Transaction)
1106   */
1107  public List<Object> findIds() {
1108    return query.findIds();
1109  }
1110
1111  /**
1112   * Execute the query iterating over the results.
1113   * <p>
1114   * Remember that with {@link QueryIterator} you must call
1115   * {@link QueryIterator#close()} when you have finished iterating the results
1116   * (typically in a finally block).
1117   * </p>
1118   * <p>
1119   * findEach() and findEachWhile() are preferred to findIterate() as they ensure
1120   * the jdbc statement and resultSet are closed at the end of the iteration.
1121   * </p>
1122   * <p>
1123   * This query will execute against the EbeanServer that was used to create it.
1124   * </p>
1125   */
1126  public QueryIterator<T> findIterate() {
1127    return query.findIterate();
1128  }
1129
1130  /**
1131   * Execute the query returning a map of the objects.
1132   * <p>
1133   * This query will execute against the EbeanServer that was used to create it.
1134   * </p>
1135   * <p>
1136   * You can use setMapKey() so specify the property values to be used as keys
1137   * on the map. If one is not specified then the id property is used.
1138   * </p>
1139   * <p>
1140   * <pre>{@code
1141   *
1142   * Map<?, Product> map =
1143   *   ebeanServer.find(Product.class)
1144   *     .setMapKey("sku")
1145   *     .findMap();
1146   *
1147   * }</pre>
1148   *
1149   * @see EbeanServer#findMap(Query, Transaction)
1150   */
1151  public Map<?, T> findMap() {
1152    return query.findMap();
1153  }
1154
1155  /**
1156   * Return a typed map specifying the key property and type.
1157   */
1158  public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
1159    return query.findMap(keyProperty, keyType);
1160  }
1161
1162  /**
1163   * Execute the query processing the beans one at a time.
1164   * <p>
1165   * This method is appropriate to process very large query results as the
1166   * beans are consumed one at a time and do not need to be held in memory
1167   * (unlike #findList #findSet etc)
1168   * </p>
1169   * <p>
1170   * Note that internally Ebean can inform the JDBC driver that it is expecting larger
1171   * resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
1172   * from buffering the entire resultSet. As such, for smaller resultSets findList() is
1173   * generally preferable.
1174   * </p>
1175   * <p>
1176   * Compared with #findEachWhile this will always process all the beans where as
1177   * #findEachWhile provides a way to stop processing the query result early before
1178   * all the beans have been read.
1179   * </p>
1180   * <p>
1181   * This method is functionally equivalent to findIterate() but instead of using an
1182   * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
1183   * with Java8 closures.
1184   * </p>
1185   * <p>
1186   * <pre>{@code
1187   *
1188   *  new QCustomer()
1189   *     .status.equalTo(Status.NEW)
1190   *     .orderBy().id.asc()
1191   *     .findEach((Customer customer) -> {
1192   *
1193   *       // do something with customer
1194   *       System.out.println("-- visit " + customer);
1195   *     });
1196   *
1197   * }</pre>
1198   *
1199   * @param consumer the consumer used to process the queried beans.
1200   */
1201  public void findEach(QueryEachConsumer<T> consumer) {
1202    query.findEach(consumer);
1203  }
1204
1205  /**
1206   * Execute the query using callbacks to a visitor to process the resulting
1207   * beans one at a time.
1208   * <p>
1209   * This method is functionally equivalent to findIterate() but instead of using an
1210   * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
1211   * with Java8 closures.
1212   * </p>
1213   * <p>
1214   * <p>
1215   * <pre>{@code
1216   *
1217   *  new QCustomer()
1218   *     .status.equalTo(Status.NEW)
1219   *     .order().id.asc()
1220   *     .findEachWhile((Customer customer) -> {
1221   *
1222   *       // do something with customer
1223   *       System.out.println("-- visit " + customer);
1224   *
1225   *       // return true to continue processing or false to stop
1226   *       return (customer.getId() < 40);
1227   *     });
1228   *
1229   * }</pre>
1230   *
1231   * @param consumer the consumer used to process the queried beans.
1232   */
1233  public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
1234    query.findEachWhile(consumer);
1235  }
1236
1237  /**
1238   * Return versions of a @History entity bean.
1239   * <p>
1240   * Generally this query is expected to be a find by id or unique predicates query.
1241   * It will execute the query against the history returning the versions of the bean.
1242   * </p>
1243   */
1244  public List<Version<T>> findVersions() {
1245    return query.findVersions();
1246  }
1247
1248  /**
1249   * Return the count of entities this query should return.
1250   * <p>
1251   * This is the number of 'top level' or 'root level' entities.
1252   * </p>
1253   */
1254  public int findRowCount() {
1255    return query.findRowCount();
1256  }
1257
1258  /**
1259   * Execute find row count query in a background thread.
1260   * <p>
1261   * This returns a Future object which can be used to cancel, check the
1262   * execution status (isDone etc) and get the value (with or without a
1263   * timeout).
1264   * </p>
1265   *
1266   * @return a Future object for the row count query
1267   */
1268  public FutureRowCount<T> findFutureRowCount() {
1269    return query.findFutureRowCount();
1270  }
1271
1272  /**
1273   * Execute find Id's query in a background thread.
1274   * <p>
1275   * This returns a Future object which can be used to cancel, check the
1276   * execution status (isDone etc) and get the value (with or without a
1277   * timeout).
1278   * </p>
1279   *
1280   * @return a Future object for the list of Id's
1281   */
1282  public FutureIds<T> findFutureIds() {
1283    return query.findFutureIds();
1284  }
1285
1286  /**
1287   * Execute find list query in a background thread.
1288   * <p>
1289   * This query will execute in it's own PersistenceContext and using its own transaction.
1290   * What that means is that it will not share any bean instances with other queries.
1291   * </p>
1292   *
1293   * @return a Future object for the list result of the query
1294   */
1295  public FutureList<T> findFutureList() {
1296    return query.findFutureList();
1297  }
1298
1299
1300  /**
1301   * Return a PagedList for this query using pageIndex and pageSize.
1302   * <p>
1303   * The benefit of using this over just using the normal {@link Query#setFirstRow(int)} and
1304   * {@link Query#setMaxRows(int)} is that it additionally wraps an optional call to
1305   * {@link Query#findFutureRowCount()} to determine total row count, total page count etc.
1306   * </p>
1307   * <p>
1308   * Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
1309   * the query. This translates into SQL that uses limit offset, rownum or row_number function to
1310   * limit the result set.
1311   * </p>
1312   * <p>
1313   * <h4>Example: typical use including total row count</h4>
1314   * <pre>{@code
1315   *
1316   *     // We want to find the first 100 new orders
1317   *     //  ... 0 means first page
1318   *     //  ... page size is 100
1319   *
1320   *     PagedList<Order> pagedList
1321   *       = new QOrder()
1322   *       .status.equalTo(Order.Status.NEW)
1323   *       .order().id.asc()
1324   *       .findPagedList(0, 100);
1325   *
1326   *     // Optional: initiate the loading of the total
1327   *     // row count in a background thread
1328   *     pagedList.loadRowCount();
1329   *
1330   *     // fetch and return the list in the foreground thread
1331   *     List<Order> orders = pagedList.getList();
1332   *
1333   *     // get the total row count (from the future)
1334   *     int totalRowCount = pagedList.getTotalRowCount();
1335   *
1336   * }</pre>
1337   *
1338   * @param pageIndex The zero based index of the page.
1339   * @param pageSize  The number of beans to return per page.
1340   * @return The PagedList
1341   */
1342  public PagedList<T> findPagedList(int pageIndex, int pageSize) {
1343    return query.findPagedList(pageIndex, pageSize);
1344  }
1345
1346  /**
1347   * Return a PagedList for this query using firstRow and maxRows.
1348   * <p>
1349   * The benefit of using this over findList() is that it provides functionality to get the
1350   * total row count etc.
1351   * </p>
1352   * <p>
1353   * If maxRows is not set on the query prior to calling findPagedList() then a
1354   * PersistenceException is thrown.
1355   * </p>
1356   * <p>
1357   * <pre>{@code
1358   *
1359   *  PagedList<Order> pagedList = Ebean.find(Order.class)
1360   *       .setFirstRow(50)
1361   *       .setMaxRows(20)
1362   *       .findPagedList();
1363   *
1364   *       // fetch the total row count in the background
1365   *       pagedList.loadRowCount();
1366   *
1367   *       List<Order> orders = pagedList.getList();
1368   *       int totalRowCount = pagedList.getTotalRowCount();
1369   *
1370   * }</pre>
1371   *
1372   * @return The PagedList
1373   */
1374  public PagedList<T> findPagedList() {
1375    return query.findPagedList();
1376  }
1377
1378  /**
1379   * Execute as a delete query deleting the 'root level' beans that match the predicates
1380   * in the query.
1381   * <p>
1382   * Note that if the query includes joins then the generated delete statement may not be
1383   * optimal depending on the database platform.
1384   * </p>
1385   *
1386   * @return the number of beans/rows that were deleted.
1387   */
1388  public int delete() {
1389    return query.delete();
1390  }
1391
1392  /**
1393   * Return the sql that was generated for executing this query.
1394   * <p>
1395   * This is only available after the query has been executed and provided only
1396   * for informational purposes.
1397   * </p>
1398   */
1399  public String getGeneratedSql() {
1400    return query.getGeneratedSql();
1401  }
1402
1403  /**
1404   * Return the type of beans being queried.
1405   */
1406  public Class<T> getBeanType() {
1407    return query.getBeanType();
1408  }
1409
1410  /**
1411   * Return the expression list that has been built for this query.
1412   */
1413  public ExpressionList<T> getExpressionList() {
1414    return query.where();
1415  }
1416
1417  /**
1418   * Return the current expression list that expressions should be added to.
1419   */
1420  protected ExpressionList<T> peekExprList() {
1421
1422    if (textMode) {
1423      // return the current text expression list
1424      return _peekText();
1425    }
1426
1427    if (whereStack == null) {
1428      whereStack = new ArrayStack<ExpressionList<T>>();
1429      whereStack.push(query.where());
1430    }
1431    // return the current expression list
1432    return whereStack.peek();
1433  }
1434
1435  protected ExpressionList<T> _peekText() {
1436    if (textStack == null) {
1437      textStack = new ArrayStack<ExpressionList<T>>();
1438      // empty so push on the queries base expression list
1439      textStack.push(query.text());
1440    }
1441    // return the current expression list
1442    return textStack.peek();
1443  }
1444}