001package io.ebean;
002
003import io.avaje.lang.NonNullApi;
004import io.avaje.lang.Nullable;
005import io.ebean.search.*;
006
007import javax.persistence.NonUniqueResultException;
008import java.sql.Connection;
009import java.sql.Timestamp;
010import java.util.*;
011import java.util.function.Consumer;
012import java.util.function.Predicate;
013
014/**
015 * List of Expressions that make up a where or having clause.
016 * <p>
017 * An ExpressionList is returned from {@link Query#where()}.
018 * </p>
019 * <p>
020 * The ExpressionList has a list of convenience methods that create the standard
021 * expressions and add them to this list.
022 * </p>
023 * <p>
024 * The ExpressionList also duplicates methods that are found on the Query such
025 * as findList() and order(). The purpose of these methods is provide a fluid
026 * API. The upside of this approach is that you can build and execute a query
027 * via chained methods. The down side is that this ExpressionList object has
028 * more methods than you would initially expect (the ones duplicated from
029 * Query).
030 * </p>
031 *
032 * @see Query#where()
033 */
034@NonNullApi
035public interface ExpressionList<T> {
036
037  /**
038   * Return the query that owns this expression list.
039   * <p>
040   * This is a convenience method solely to support a fluid API where the
041   * methods are chained together. Adding expressions returns this expression
042   * list and this method can be used after that to return back the original
043   * query so that further things can be added to it.
044   * </p>
045   */
046  Query<T> query();
047
048  /**
049   * Controls, if paginated queries should always append an 'order by id' statement at the end to
050   * guarantee a deterministic sort result. This may affect performance.
051   * If this is not enabled, and an orderBy is set on the query, it's up to the programmer that
052   * this query provides a deterministic result.
053   */
054  Query<T> orderById(boolean orderById);
055
056  /**
057   * Set the order by clause replacing the existing order by clause if there is
058   * one.
059   * <p>
060   * This follows SQL syntax using commas between each property with the
061   * optional asc and desc keywords representing ascending and descending order
062   * respectively.
063   */
064  ExpressionList<T> order(String orderByClause);
065
066  /**
067   * Set the order by clause replacing the existing order by clause if there is
068   * one.
069   * <p>
070   * This follows SQL syntax using commas between each property with the
071   * optional asc and desc keywords representing ascending and descending order
072   * respectively.
073   */
074  ExpressionList<T> orderBy(String orderBy);
075
076  /**
077   * Return the OrderBy so that you can append an ascending or descending
078   * property to the order by clause.
079   * <p>
080   * This will never return a null. If no order by clause exists then an 'empty'
081   * OrderBy object is returned.
082   * <p>
083   * This is the same as <code>orderBy()</code>
084   */
085  OrderBy<T> order();
086
087  /**
088   * Return the OrderBy so that you can append an ascending or descending
089   * property to the order by clause.
090   * <p>
091   * This will never return a null. If no order by clause exists then an 'empty'
092   * OrderBy object is returned.
093   * <p>
094   * This is the same as <code>order()</code>
095   */
096  OrderBy<T> orderBy();
097
098  /**
099   * Deprecated migrate to {@link #orderBy(String)}
100   */
101  @Deprecated
102  Query<T> setOrderBy(String orderBy);
103
104  /**
105   * Apply the path properties to the query replacing the select and fetch clauses.
106   */
107  Query<T> apply(FetchPath fetchPath);
108
109  /**
110   * Perform an 'As of' query using history tables to return the object graph
111   * as of a time in the past.
112   * <p>
113   * To perform this query the DB must have underlying history tables.
114   * </p>
115   *
116   * @param asOf the date time in the past at which you want to view the data
117   */
118  Query<T> asOf(Timestamp asOf);
119
120  /**
121   * Execute the query against the draft set of tables.
122   */
123  Query<T> asDraft();
124
125  /**
126   * Convert the query to a DTO bean query.
127   * <p>
128   * We effectively use the underlying ORM query to build the SQL and then execute
129   * and map it into DTO beans.
130   */
131  <D> DtoQuery<D> asDto(Class<D> dtoClass);
132
133  /**
134   * Return the underlying query as an UpdateQuery.
135   * <p>
136   * Typically this is used with query beans to covert a query bean
137   * query into an UpdateQuery like the examples below.
138   * </p>
139   *
140   * <pre>{@code
141   *
142   *  int rowsUpdated = new QCustomer()
143   *       .name.startsWith("Rob")
144   *       .asUpdate()
145   *       .set("active", false)
146   *       .update();;
147   *
148   * }</pre>
149   *
150   * <pre>{@code
151   *
152   *   int rowsUpdated = new QContact()
153   *       .notes.note.startsWith("Make Inactive")
154   *       .email.endsWith("@foo.com")
155   *       .customer.id.equalTo(42)
156   *       .asUpdate()
157   *       .set("inactive", true)
158   *       .setRaw("email = lower(email)")
159   *       .update();
160   *
161   * }</pre>
162   */
163  UpdateQuery<T> asUpdate();
164
165  /**
166   * Execute the query with the given lock type and WAIT.
167   * <p>
168   * Note that <code>forUpdate()</code> is the same as
169   * <code>withLock(LockType.UPDATE)</code>.
170   * <p>
171   * Provides us with the ability to explicitly use Postgres
172   * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
173   */
174  Query<T> withLock(Query.LockType lockType);
175
176  /**
177   * Execute the query with the given lock type and lock wait.
178   * <p>
179   * Note that <code>forUpdateNoWait()</code> is the same as
180   * <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
181   * <p>
182   * Provides us with the ability to explicitly use Postgres
183   * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
184   */
185  Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait);
186
187  /**
188   * Execute using "for update" clause which results in the DB locking the record.
189   */
190  Query<T> forUpdate();
191
192  /**
193   * Execute using "for update" clause with No Wait option.
194   * <p>
195   * This is typically a Postgres and Oracle only option at this stage.
196   * </p>
197   */
198  Query<T> forUpdateNoWait();
199
200  /**
201   * Execute using "for update" clause with Skip Locked option.
202   * <p>
203   * This is typically a Postgres and Oracle only option at this stage.
204   * </p>
205   */
206  Query<T> forUpdateSkipLocked();
207
208  /**
209   * Execute the query including soft deleted rows.
210   */
211  Query<T> setIncludeSoftDeletes();
212
213  /**
214   * Execute the query using the given transaction.
215   */
216  Query<T> usingTransaction(Transaction transaction);
217
218  /**
219   * Execute the query using the given connection.
220   */
221  Query<T> usingConnection(Connection connection);
222
223  /**
224   * Execute as a delete query deleting the 'root level' beans that match the predicates
225   * in the query.
226   * <p>
227   * Note that if the query includes joins then the generated delete statement may not be
228   * optimal depending on the database platform.
229   * </p>
230   *
231   * @return the number of rows that were deleted.
232   */
233  int delete();
234
235  /**
236   * Execute as a delete query deleting the 'root level' beans that match the predicates
237   * in the query.
238   * <p>
239   * Note that if the query includes joins then the generated delete statement may not be
240   * optimal depending on the database platform.
241   * </p>
242   *
243   * @return the number of rows that were deleted.
244   */
245  int delete(Transaction transaction);
246
247  /**
248   * Execute as a update query.
249   *
250   * @return the number of rows that were updated.
251   * @see UpdateQuery
252   */
253  int update();
254
255  /**
256   * Execute as a update query with the given transaction.
257   *
258   * @return the number of rows that were updated.
259   * @see UpdateQuery
260   */
261  int update(Transaction transaction);
262
263  /**
264   * Execute the query returning true if a row is found.
265   * <p>
266   * The query is executed using max rows of 1 and will only select the id property.
267   * This method is really just a convenient way to optimise a query to perform a
268   * 'does a row exist in the db' check.
269   * </p>
270   *
271   * <h2>Example:</h2>
272   * <pre>{@code
273   *
274   *   boolean userExists = query().where().eq("email", "[email protected]").exists();
275   *
276   * }</pre>
277   *
278   * <h2>Example using a query bean:</h2>
279   * <pre>{@code
280   *
281   *   boolean userExists = new QContact().email.equalTo("[email protected]").exists();
282   *
283   * }</pre>
284   *
285   * @return True if the query finds a matching row in the database
286   */
287  boolean exists();
288
289  /**
290   * Execute the query iterating over the results.
291   *
292   * @see Query#findIterate()
293   */
294  QueryIterator<T> findIterate();
295
296  /**
297   * Execute the query process the beans one at a time.
298   *
299   * @see Query#findEach(Consumer)
300   */
301  void findEach(Consumer<T> consumer);
302
303  /**
304   * Execute findEach with a batch consumer.
305   *
306   * @see Query#findEach(int, Consumer)
307   */
308  void findEach(int batch, Consumer<List<T>> consumer);
309
310  /**
311   * Execute the query processing the beans one at a time with the ability to
312   * stop processing before reading all the beans.
313   *
314   * @see Query#findEachWhile(Predicate)
315   */
316  void findEachWhile(Predicate<T> consumer);
317
318  /**
319   * Execute the query returning a list.
320   *
321   * @see Query#findList()
322   */
323  List<T> findList();
324
325  /**
326   * Execute the query returning the list of Id's.
327   *
328   * @see Query#findIds()
329   */
330  <A> List<A> findIds();
331
332  /**
333   * Return the count of entities this query should return.
334   * <p>
335   * This is the number of 'top level' or 'root level' entities.
336   * </p>
337   */
338  int findCount();
339
340  /**
341   * Execute the query returning a set.
342   *
343   * @see Query#findSet()
344   */
345  Set<T> findSet();
346
347  /**
348   * Execute the query returning a map.
349   *
350   * @see Query#findMap()
351   */
352  <K> Map<K, T> findMap();
353
354  /**
355   * Execute the query returning a list of values for a single property.
356   *
357   * <h3>Example 1:</h3>
358   * <pre>{@code
359   *
360   *  List<String> names =
361   *    DB.find(Customer.class)
362   *      .select("name")
363   *      .order().asc("name")
364   *      .findSingleAttributeList();
365   *
366   * }</pre>
367   *
368   * <h3>Example 2:</h3>
369   * <pre>{@code
370   *
371   *  List<String> names =
372   *    DB.find(Customer.class)
373   *      .setDistinct(true)
374   *      .select("name")
375   *      .where().eq("status", Customer.Status.NEW)
376   *      .order().asc("name")
377   *      .setMaxRows(100)
378   *      .findSingleAttributeList();
379   *
380   * }</pre>
381   *
382   * @return the list of values for the selected property
383   */
384  <A> List<A> findSingleAttributeList();
385
386  /**
387   * Execute a query returning a single value of a single property/column.
388   * <pre>{@code
389   *
390   *  String name =
391   *    DB.find(Customer.class)
392   *      .select("name")
393   *      .where().eq("id", 42)
394   *      .findSingleAttribute();
395   *
396   * }</pre>
397   */
398  default <A> A findSingleAttribute() {
399    List<A> list = findSingleAttributeList();
400    return !list.isEmpty() ? list.get(0) : null;
401  }
402
403  /**
404   * Execute the query returning a single bean or null (if no matching
405   * bean is found).
406   * <p>
407   * If more than 1 row is found for this query then a NonUniqueResultException is
408   * thrown.
409   * </p>
410   *
411   * @throws NonUniqueResultException if more than one result was found
412   * @see Query#findOne()
413   */
414  @Nullable
415  T findOne();
416
417  /**
418   * Execute the query returning an optional bean.
419   */
420  Optional<T> findOneOrEmpty();
421
422  /**
423   * Execute find row count query in a background thread.
424   * <p>
425   * This returns a Future object which can be used to cancel, check the
426   * execution status (isDone etc) and get the value (with or without a
427   * timeout).
428   * </p>
429   *
430   * @return a Future object for the row count query
431   */
432  FutureRowCount<T> findFutureCount();
433
434  /**
435   * Execute find Id's query in a background thread.
436   * <p>
437   * This returns a Future object which can be used to cancel, check the
438   * execution status (isDone etc) and get the value (with or without a
439   * timeout).
440   * </p>
441   *
442   * @return a Future object for the list of Id's
443   */
444  FutureIds<T> findFutureIds();
445
446  /**
447   * Execute find list query in a background thread.
448   * <p>
449   * This returns a Future object which can be used to cancel, check the
450   * execution status (isDone etc) and get the value (with or without a
451   * timeout).
452   * </p>
453   *
454   * @return a Future object for the list result of the query
455   */
456  FutureList<T> findFutureList();
457
458  /**
459   * Return a PagedList for this query using firstRow and maxRows.
460   * <p>
461   * The benefit of using this over findList() is that it provides functionality to get the
462   * total row count etc.
463   * </p>
464   * <p>
465   * If maxRows is not set on the query prior to calling findPagedList() then a
466   * PersistenceException is thrown.
467   * </p>
468   * <pre>{@code
469   *
470   *  PagedList<Order> pagedList = DB.find(Order.class)
471   *       .setFirstRow(50)
472   *       .setMaxRows(20)
473   *       .findPagedList();
474   *
475   *       // fetch the total row count in the background
476   *       pagedList.loadRowCount();
477   *
478   *       List<Order> orders = pagedList.getList();
479   *       int totalRowCount = pagedList.getTotalRowCount();
480   *
481   * }</pre>
482   *
483   * @return The PagedList
484   * @see Query#findPagedList()
485   */
486  PagedList<T> findPagedList();
487
488  /**
489   * Return versions of a @History entity bean.
490   * <p>
491   * Generally this query is expected to be a find by id or unique predicates query.
492   * It will execute the query against the history returning the versions of the bean.
493   * </p>
494   */
495  List<Version<T>> findVersions();
496
497  /**
498   * Return versions of a @History entity bean between the 2 timestamps.
499   * <p>
500   * Generally this query is expected to be a find by id or unique predicates query.
501   * It will execute the query against the history returning the versions of the bean.
502   * </p>
503   */
504  List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
505
506  /**
507   * Add some filter predicate expressions to the many property.
508   */
509  ExpressionList<T> filterMany(String manyProperty);
510
511  /**
512   * Add filter expressions to the many property.
513   *
514   * <pre>{@code
515   *
516   *   DB.find(Customer.class)
517   *   .where()
518   *   .eq("name", "Rob")
519   *   .filterMany("orders", "status = ?", Status.NEW)
520   *   .findList();
521   *
522   * }</pre>
523   *
524   * @param manyProperty The many property
525   * @param expressions  Filter expressions with and, or and ? or ?1 type bind parameters
526   * @param params       Bind parameters used in the expressions
527   */
528  ExpressionList<T> filterMany(String manyProperty, String expressions, Object... params);
529
530  /**
531   * Specify specific properties to fetch on the main/root bean (aka partial
532   * object).
533   *
534   * @see Query#select(String)
535   */
536  Query<T> select(String properties);
537
538  /**
539   * Apply the fetchGroup which defines what part of the object graph to load.
540   */
541  Query<T> select(FetchGroup<T> fetchGroup);
542
543  /**
544   * Set whether this query uses DISTINCT.
545   * <p>
546   * The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
547   * generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
548   * </p>
549   * <pre>{@code
550   *
551   *   List<Customer> customers =
552   *       DB.find(Customer.class)
553   *          .setDistinct(true)
554   *          .select("name")     // only select the customer name
555   *          .findList();
556   *
557   * }</pre>
558   */
559  Query<T> setDistinct(boolean distinct);
560
561  /**
562   * Set the index(es) to search for a document store which uses partitions.
563   * <p>
564   * For example, when executing a query against ElasticSearch with daily indexes we can
565   * explicitly specify the indexes to search against.
566   * </p>
567   *
568   * @param indexName The index or indexes to search against
569   * @return This query
570   * @see Query#setDocIndexName(String)
571   */
572  Query<T> setDocIndexName(String indexName);
573
574  /**
575   * Set the first row to fetch.
576   *
577   * @see Query#setFirstRow(int)
578   */
579  ExpressionList<T> setFirstRow(int firstRow);
580
581  /**
582   * Set the maximum number of rows to fetch.
583   *
584   * @see Query#setMaxRows(int)
585   */
586  ExpressionList<T> setMaxRows(int maxRows);
587
588  /**
589   * Set the name of the property which values become the key of a map.
590   *
591   * @see Query#setMapKey(String)
592   */
593  Query<T> setMapKey(String mapKey);
594
595  /**
596   * Set to true when this query should use the bean cache.
597   * <p>
598   * This is now the same as setUseBeanCache(CacheMode.ON) and will be deprecated.
599   * </p>
600   *
601   * @see Query#setUseCache(boolean)
602   */
603  Query<T> setUseCache(boolean useCache);
604
605  /**
606   * Set the mode to use the bean cache when executing this query.
607   *
608   * @see Query#setBeanCacheMode(CacheMode)
609   */
610  Query<T> setBeanCacheMode(CacheMode beanCacheMode);
611
612  /**
613   * Set the {@link CacheMode} to use the query cache for executing this query.
614   *
615   * @see Query#setUseQueryCache(boolean)
616   */
617  Query<T> setUseQueryCache(CacheMode useCache);
618
619  /**
620   * Extended version for setDistinct in conjunction with "findSingleAttributeList";
621   * <pre>{@code
622   *
623   *  List<CountedValue<Order.Status>> orderStatusCount =
624   *
625   *     DB.find(Order.class)
626   *      .select("status")
627   *      .where()
628   *      .gt("orderDate", LocalDate.now().minusMonths(3))
629   *
630   *      // fetch as single attribute with a COUNT
631   *      .setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
632   *      .findSingleAttributeList();
633   *
634   *     for (CountedValue<Order.Status> entry : orderStatusCount) {
635   *       System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
636   *     }
637   *
638   *   // produces
639   *
640   *   count:3 orderStatus:NEW
641   *   count:1 orderStatus:SHIPPED
642   *   count:1 orderStatus:COMPLETE
643   *
644   * }</pre>
645   */
646  Query<T> setCountDistinct(CountDistinctOrder orderBy);
647
648  /**
649   * Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
650   *
651   * @see Query#setUseQueryCache(CacheMode)
652   */
653  default Query<T> setUseQueryCache(boolean enabled) {
654    return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
655  }
656
657  /**
658   * Set to true if this query should execute against the doc store.
659   * <p>
660   * When setting this you may also consider disabling lazy loading.
661   * </p>
662   */
663  Query<T> setUseDocStore(boolean useDocsStore);
664
665  /**
666   * Set true if you want to disable lazy loading.
667   * <p>
668   * That is, once the object graph is returned further lazy loading is disabled.
669   * </p>
670   */
671  Query<T> setDisableLazyLoading(boolean disableLazyLoading);
672
673  /**
674   * Disable read auditing for this query.
675   * <p>
676   * This is intended to be used when the query is not a user initiated query and instead
677   * part of the internal processing in an application to load a cache or document store etc.
678   * In these cases we don't want the query to be part of read auditing.
679   * </p>
680   */
681  Query<T> setDisableReadAuditing();
682
683  /**
684   * Set a label on the query (to help identify query execution statistics).
685   */
686  Query<T> setLabel(String label);
687
688  /**
689   * Add expressions to the having clause.
690   * <p>
691   * The having clause is only used for queries based on raw sql (via SqlSelect
692   * annotation etc).
693   * </p>
694   */
695  ExpressionList<T> having();
696
697  /**
698   * Add another expression to the where clause.
699   */
700  ExpressionList<T> where();
701
702  /**
703   * Add the expressions to this expression list.
704   *
705   * @param expressions The expressions that are parsed and added to this expression list
706   * @param params      Bind parameters to match ? or ?1 bind positions.
707   */
708  ExpressionList<T> where(String expressions, Object... params);
709
710  /**
711   * Path exists - for the given path in a JSON document.
712   * <pre>{@code
713   *
714   *   where().jsonExists("content", "path.other")
715   *
716   * }</pre>
717   *
718   * @param propertyName the property that holds a JSON document
719   * @param path         the nested path in the JSON document in dot notation
720   */
721  ExpressionList<T> jsonExists(String propertyName, String path);
722
723  /**
724   * Path does not exist - for the given path in a JSON document.
725   * <pre>{@code
726   *
727   *   where().jsonNotExists("content", "path.other")
728   *
729   * }</pre>
730   *
731   * @param propertyName the property that holds a JSON document
732   * @param path         the nested path in the JSON document in dot notation
733   */
734  ExpressionList<T> jsonNotExists(String propertyName, String path);
735
736  /**
737   * Equal to expression for the value at the given path in the JSON document.
738   * <pre>{@code
739   *
740   *   where().jsonEqualTo("content", "path.other", 34)
741   *
742   * }</pre>
743   *
744   * @param propertyName the property that holds a JSON document
745   * @param path         the nested path in the JSON document in dot notation
746   * @param value        the value used to test against the document path's value
747   */
748  ExpressionList<T> jsonEqualTo(String propertyName, String path, Object value);
749
750  /**
751   * Not Equal to - for the given path in a JSON document.
752   * <pre>{@code
753   *
754   *   where().jsonNotEqualTo("content", "path.other", 34)
755   *
756   * }</pre>
757   *
758   * @param propertyName the property that holds a JSON document
759   * @param path         the nested path in the JSON document in dot notation
760   * @param value        the value used to test against the document path's value
761   */
762  ExpressionList<T> jsonNotEqualTo(String propertyName, String path, Object value);
763
764  /**
765   * Greater than - for the given path in a JSON document.
766   * <pre>{@code
767   *
768   *   where().jsonGreaterThan("content", "path.other", 34)
769   *
770   * }</pre>
771   */
772  ExpressionList<T> jsonGreaterThan(String propertyName, String path, Object value);
773
774  /**
775   * Greater than or equal to - for the given path in a JSON document.
776   * <pre>{@code
777   *
778   *   where().jsonGreaterOrEqual("content", "path.other", 34)
779   *
780   * }</pre>
781   */
782  ExpressionList<T> jsonGreaterOrEqual(String propertyName, String path, Object value);
783
784  /**
785   * Less than - for the given path in a JSON document.
786   * <pre>{@code
787   *
788   *   where().jsonLessThan("content", "path.other", 34)
789   *
790   * }</pre>
791   */
792  ExpressionList<T> jsonLessThan(String propertyName, String path, Object value);
793
794  /**
795   * Less than or equal to - for the given path in a JSON document.
796   * <pre>{@code
797   *
798   *   where().jsonLessOrEqualTo("content", "path.other", 34)
799   *
800   * }</pre>
801   */
802  ExpressionList<T> jsonLessOrEqualTo(String propertyName, String path, Object value);
803
804  /**
805   * Between - for the given path in a JSON document.
806   * <pre>{@code
807   *
808   *   where().jsonBetween("content", "orderDate", lowerDateTime, upperDateTime)
809   *
810   * }</pre>
811   */
812  ExpressionList<T> jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
813
814  /**
815   * Add an Expression to the list.
816   */
817  ExpressionList<T> add(Expression expr);
818
819  /**
820   * Add a list of Expressions to this ExpressionList.s
821   */
822  ExpressionList<T> addAll(ExpressionList<T> exprList);
823
824  /**
825   * Equal To - property is equal to a given value.
826   */
827  ExpressionList<T> eq(String propertyName, Object value);
828
829  /**
830   * Equal To or Null - property is equal to a given value or null.
831   */
832  ExpressionList<T> eqOrNull(String propertyName, Object value);
833
834  /**
835   * Not Equal To - property not equal to the given value.
836   */
837  ExpressionList<T> ne(String propertyName, Object value);
838
839  /**
840   * Case Insensitive Equal To - property equal to the given value (typically
841   * using a lower() function to make it case insensitive).
842   */
843  ExpressionList<T> ieq(String propertyName, String value);
844
845  /**
846   * Case Insensitive Not Equal To - property not equal to the given value (typically
847   * using a lower() function to make it case insensitive).
848   */
849  ExpressionList<T> ine(String propertyName, String value);
850
851  /**
852   * Value in Range between 2 properties.
853   *
854   * <pre>{@code
855   *
856   *    .startDate.inRangeWith(endDate, now)
857   *
858   *    // which equates to
859   *    startDate <= now and (endDate > now or endDate is null)
860   *
861   * }</pre>
862   *
863   * <p>
864   * This is a convenience expression combining a number of simple expressions.
865   * The most common use of this could be called "effective dating" where 2 date or
866   * timestamp columns represent the date range in which
867   */
868  ExpressionList<T> inRangeWith(String lowProperty, String highProperty, Object value);
869
870  /**
871   * In Range - {@code property >= value1 and property < value2}.
872   * <p>
873   * Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
874   * </p>
875   */
876  ExpressionList<T> inRange(String propertyName, Object value1, Object value2);
877
878  /**
879   * Between - property between the two given values.
880   */
881  ExpressionList<T> between(String propertyName, Object value1, Object value2);
882
883  /**
884   * Between - value between the two properties.
885   */
886  ExpressionList<T> betweenProperties(String lowProperty, String highProperty, Object value);
887
888  /**
889   * Greater Than - property greater than the given value.
890   */
891  ExpressionList<T> gt(String propertyName, Object value);
892
893  /**
894   * Greater Than or Null - property greater than the given value or null.
895   */
896  ExpressionList<T> gtOrNull(String propertyName, Object value);
897
898  /**
899   * Greater Than or Equal to OR Null - ({@code >= or null }).
900   */
901  ExpressionList<T> geOrNull(String propertyName, Object value);
902
903  /**
904   * Greater Than or Equal to - property greater than or equal to the given
905   * value.
906   */
907  ExpressionList<T> ge(String propertyName, Object value);
908
909  /**
910   * Less Than - property less than the given value.
911   */
912  ExpressionList<T> lt(String propertyName, Object value);
913
914  /**
915   * Less Than or Null - property less than the given value or null.
916   */
917  ExpressionList<T> ltOrNull(String propertyName, Object value);
918
919  /**
920   * Less Than or Equal to OR Null - ({@code <= or null }).
921   */
922  ExpressionList<T> leOrNull(String propertyName, Object value);
923
924  /**
925   * Less Than or Equal to - property less than or equal to the given value.
926   */
927  ExpressionList<T> le(String propertyName, Object value);
928
929  /**
930   * Is Null - property is null.
931   */
932  ExpressionList<T> isNull(String propertyName);
933
934  /**
935   * Is Not Null - property is not null.
936   */
937  ExpressionList<T> isNotNull(String propertyName);
938
939  /**
940   * A "Query By Example" type of expression.
941   * <p>
942   * Pass in an example entity and for each non-null scalar properties an
943   * expression is added.
944   * </p>
945   * <p>
946   * By Default this case sensitive, will ignore numeric zero values and will
947   * use a Like for string values (you must put in your own wildcards).
948   * </p>
949   * <p>
950   * To get control over the options you can create an ExampleExpression and set
951   * those options such as case insensitive etc.
952   * </p>
953   * <pre>{@code
954   *
955   * // create an example bean and set the properties
956   * // with the query parameters you want
957   * Customer example = new Customer();
958   * example.setName("Rob%");
959   * example.setNotes("%something%");
960   *
961   * List<Customer> list =
962   *   DB.find(Customer.class)
963   *     .where().exampleLike(example)
964   *     .findList();
965   *
966   * }</pre>
967   * <p>
968   * Similarly you can create an ExampleExpression
969   * </p>
970   * <pre>{@code
971   *
972   * Customer example = new Customer();
973   * example.setName("Rob%");
974   * example.setNotes("%something%");
975   *
976   * // create a ExampleExpression with more control
977   * ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
978   *
979   * List<Customer> list = DB.find(Customer.class).where().add(qbe).findList();
980   *
981   * }</pre>
982   */
983  ExpressionList<T> exampleLike(Object example);
984
985  /**
986   * Case insensitive version of {@link #exampleLike(Object)}
987   */
988  ExpressionList<T> iexampleLike(Object example);
989
990  /**
991   * Like - property like value where the value contains the SQL wild card
992   * characters % (percentage) and _ (underscore).
993   */
994  ExpressionList<T> like(String propertyName, String value);
995
996  /**
997   * Case insensitive Like - property like value where the value contains the
998   * SQL wild card characters % (percentage) and _ (underscore). Typically uses
999   * a lower() function to make the expression case insensitive.
1000   */
1001  ExpressionList<T> ilike(String propertyName, String value);
1002
1003  /**
1004   * Starts With - property like value%.
1005   */
1006  ExpressionList<T> startsWith(String propertyName, String value);
1007
1008  /**
1009   * Case insensitive Starts With - property like value%. Typically uses a
1010   * lower() function to make the expression case insensitive.
1011   */
1012  ExpressionList<T> istartsWith(String propertyName, String value);
1013
1014  /**
1015   * Ends With - property like %value.
1016   */
1017  ExpressionList<T> endsWith(String propertyName, String value);
1018
1019  /**
1020   * Case insensitive Ends With - property like %value. Typically uses a lower()
1021   * function to make the expression case insensitive.
1022   */
1023  ExpressionList<T> iendsWith(String propertyName, String value);
1024
1025  /**
1026   * Contains - property like %value%.
1027   */
1028  ExpressionList<T> contains(String propertyName, String value);
1029
1030  /**
1031   * Case insensitive Contains - property like %value%. Typically uses a lower()
1032   * function to make the expression case insensitive.
1033   */
1034  ExpressionList<T> icontains(String propertyName, String value);
1035
1036  /**
1037   * In expression using pairs of value objects.
1038   */
1039  ExpressionList<T> inPairs(Pairs pairs);
1040
1041  /**
1042   * In - using a subQuery.
1043   */
1044  ExpressionList<T> in(String propertyName, Query<?> subQuery);
1045
1046  /**
1047   * In - property has a value in the array of values.
1048   */
1049  ExpressionList<T> in(String propertyName, Object... values);
1050
1051  /**
1052   * In - property has a value in the collection of values.
1053   */
1054  ExpressionList<T> in(String propertyName, Collection<?> values);
1055
1056  /**
1057   * In where null or empty values means that no predicate is added to the query.
1058   * <p>
1059   * That is, only add the IN predicate if the values are not null or empty.
1060   * <p>
1061   * Without this we typically need to code an <code>if</code> block to only add
1062   * the IN predicate if the collection is not empty like:
1063   * </p>
1064   *
1065   * <h3>Without inOrEmpty()</h3>
1066   * <pre>{@code
1067   *
1068   *   query.where() // add some predicates
1069   *     .eq("status", Status.NEW);
1070   *
1071   *   if (ids != null && !ids.isEmpty()) {
1072   *     query.where().in("customer.id", ids);
1073   *   }
1074   *
1075   *   query.findList();
1076   *
1077   * }</pre>
1078   *
1079   * <h3>Using inOrEmpty()</h3>
1080   * <pre>{@code
1081   *
1082   *   query.where()
1083   *     .eq("status", Status.NEW)
1084   *     .inOrEmpty("customer.id", ids)
1085   *     .findList();
1086   *
1087   * }</pre>
1088   */
1089  ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values);
1090
1091  /**
1092   * In - using a subQuery.
1093   * <p>
1094   * This is exactly the same as in() and provided due to "in" being a Kotlin keyword
1095   * (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
1096   */
1097  default ExpressionList<T> isIn(String propertyName, Query<?> subQuery) {
1098    return in(propertyName, subQuery);
1099  }
1100
1101  /**
1102   * In - property has a value in the array of values.
1103   * <p>
1104   * This is exactly the same as in() and provided due to "in" being a Kotlin keyword
1105   * (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
1106   */
1107  default ExpressionList<T> isIn(String propertyName, Object... values) {
1108    return in(propertyName, values);
1109  }
1110
1111  /**
1112   * In - property has a value in the collection of values.
1113   * <p>
1114   * This is exactly the same as in() and provided due to "in" being a Kotlin keyword
1115   * (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
1116   */
1117  default ExpressionList<T> isIn(String propertyName, Collection<?> values) {
1118    return in(propertyName, values);
1119  }
1120
1121  /**
1122   * Not In - property has a value in the array of values.
1123   */
1124  ExpressionList<T> notIn(String propertyName, Object... values);
1125
1126  /**
1127   * Not In - property has a value in the collection of values.
1128   */
1129  ExpressionList<T> notIn(String propertyName, Collection<?> values);
1130
1131  /**
1132   * Not In - using a subQuery.
1133   */
1134  ExpressionList<T> notIn(String propertyName, Query<?> subQuery);
1135
1136  /**
1137   * Is empty expression for collection properties.
1138   */
1139  ExpressionList<T> isEmpty(String propertyName);
1140
1141  /**
1142   * Is not empty expression for collection properties.
1143   */
1144  ExpressionList<T> isNotEmpty(String propertyName);
1145
1146  /**
1147   * Exists expression
1148   */
1149  ExpressionList<T> exists(Query<?> subQuery);
1150
1151  /**
1152   * Not exists expression
1153   */
1154  ExpressionList<T> notExists(Query<?> subQuery);
1155
1156  /**
1157   * Id IN a list of id values.
1158   */
1159  ExpressionList<T> idIn(Object... idValues);
1160
1161  /**
1162   * Id IN a collection of id values.
1163   */
1164  ExpressionList<T> idIn(Collection<?> idValues);
1165
1166  /**
1167   * Id Equal to - ID property is equal to the value.
1168   */
1169  ExpressionList<T> idEq(Object value);
1170
1171  /**
1172   * All Equal - Map containing property names and their values.
1173   * <p>
1174   * Expression where all the property names in the map are equal to the
1175   * corresponding value.
1176   * </p>
1177   *
1178   * @param propertyMap a map keyed by property names.
1179   */
1180  ExpressionList<T> allEq(Map<String, Object> propertyMap);
1181
1182  /**
1183   * Array property contains entries with the given values.
1184   */
1185  ExpressionList<T> arrayContains(String propertyName, Object... values);
1186
1187  /**
1188   * Array does not contain the given values.
1189   * <p>
1190   * Array support is effectively limited to Postgres at this time.
1191   * </p>
1192   */
1193  ExpressionList<T> arrayNotContains(String propertyName, Object... values);
1194
1195  /**
1196   * Array is empty - for the given array property.
1197   * <p>
1198   * Array support is effectively limited to Postgres at this time.
1199   * </p>
1200   */
1201  ExpressionList<T> arrayIsEmpty(String propertyName);
1202
1203  /**
1204   * Array is not empty - for the given array property.
1205   * <p>
1206   * Array support is effectively limited to Postgres at this time.
1207   * </p>
1208   */
1209  ExpressionList<T> arrayIsNotEmpty(String propertyName);
1210
1211  /**
1212   * Add expression for ANY of the given bit flags to be set.
1213   * <pre>{@code
1214   *
1215   * where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
1216   *
1217   * }</pre>
1218   *
1219   * @param propertyName The property that holds the flags value
1220   * @param flags        The flags we are looking for
1221   */
1222  ExpressionList<T> bitwiseAny(String propertyName, long flags);
1223
1224  /**
1225   * Add expression for ALL of the given bit flags to be set.
1226   * <pre>{@code
1227   *
1228   * where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
1229   *
1230   * }</pre>
1231   *
1232   * @param propertyName The property that holds the flags value
1233   * @param flags        The flags we are looking for
1234   */
1235  ExpressionList<T> bitwiseAll(String propertyName, long flags);
1236
1237  /**
1238   * Add expression for the given bit flags to be NOT set.
1239   * <pre>{@code
1240   *
1241   * where().bitwiseNot("flags", BwFlags.HAS_COLOUR)
1242   *
1243   * }</pre>
1244   *
1245   * @param propertyName The property that holds the flags value
1246   * @param flags        The flags we are looking for
1247   */
1248  ExpressionList<T> bitwiseNot(String propertyName, long flags);
1249
1250  /**
1251   * Add bitwise AND expression of the given bit flags to compare with the match/mask.
1252   * <p>
1253   * <pre>{@code
1254   *
1255   * // Flags Bulk + Size = Size
1256   * // ... meaning Bulk is not set and Size is set
1257   *
1258   * long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
1259   * long mask = BwFlags.HAS_SIZE; // Only Size flag set
1260   *
1261   * where().bitwiseAnd("flags", selectedFlags, mask)
1262   *
1263   * }</pre>
1264   *
1265   * @param propertyName The property that holds the flags value
1266   * @param flags        The flags we are looking for
1267   */
1268  ExpressionList<T> bitwiseAnd(String propertyName, long flags, long match);
1269
1270  /**
1271   * Add raw expression with a single parameter.
1272   * <p>
1273   * The raw expression should contain a single ? or ?1
1274   * at the location of the parameter.  We use ?1 when binding a
1275   * collection for an IN expression.
1276   * <p>
1277   * When properties in the clause are fully qualified as table-column names
1278   * then they are not translated. logical property name names (not fully
1279   * qualified) will still be translated to their physical name.
1280   * <p>
1281   * <h4>Examples:</h4>
1282   * <pre>{@code
1283   *
1284   *   // use a database function
1285   *   raw("add_days(orderDate, 10) < ?", someDate)
1286   *
1287   *   raw("name like ?", "Rob%")
1288   *
1289   *   raw("name in (?1)", asList("Rob", "Fiona", "Jack"))
1290   *
1291   *   raw("name = any(?)", asList("Rob", "Fiona", "Jack"))
1292   *
1293   * }</pre>
1294   *
1295   * <h4>Subquery examples:</h4>
1296   * <pre>{@code
1297   *
1298   *   // Bind collection using ?1
1299   *   .raw("id in (select c.id from o_customer c where c.name in (?1))", asList("Rob", "Fiona", "Jack"))
1300   *
1301   *   // Using Postgres ANY expression
1302   *   .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
1303   *
1304   * }</pre>
1305   */
1306  ExpressionList<T> raw(String raw, Object value);
1307
1308  /**
1309   * Add raw expression with an array of parameters.
1310   * <p>
1311   * The raw expression should contain the same number of ? or ?1, ?2 ... bind parameters
1312   * as there are values. We use ?1, ?2 etc when binding a collection for an IN expression.
1313   * <p>
1314   * When properties in the clause are fully qualified as table-column names
1315   * then they are not translated. logical property name names (not fully
1316   * qualified) will still be translated to their physical name.
1317   * </p>
1318   *
1319   * <h4>Examples:</h4>
1320   * <pre>{@code
1321   *
1322   *   raw("unitPrice > ? and product.id > ?", 2, 3)
1323   *
1324   *   raw("(status = ? or (orderDate < ? and shipDate is null) or customer.name like ?)",
1325   *         Order.Status.APPROVED,
1326   *         new Timestamp(System.currentTimeMillis()),
1327   *         "Rob")
1328   *
1329   * }</pre></pre>
1330   */
1331  ExpressionList<T> raw(String raw, Object... values);
1332
1333  /**
1334   * Add raw expression with no parameters.
1335   * <p>
1336   * When properties in the clause are fully qualified as table-column names
1337   * then they are not translated. logical property name names (not fully
1338   * qualified) will still be translated to their physical name.
1339   * </p>
1340   * <pre>{@code
1341   *
1342   *   raw("orderQty < shipQty")
1343   *
1344   * }</pre>
1345   *
1346   * <h4>Subquery example:</h4>
1347   * <pre>{@code
1348   *
1349   *   .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
1350   *
1351   * }</pre>
1352   */
1353  ExpressionList<T> raw(String raw);
1354
1355  /**
1356   * Only add the raw expression if the values is not null or empty.
1357   * <p>
1358   * This is a pure convenience expression to make it nicer to deal with the pattern where we use
1359   * raw() expression with a subquery and only want to add the subquery predicate when the collection
1360   * of values is not empty.
1361   * </p>
1362   * <h3>Without inOrEmpty()</h3>
1363   * <pre>{@code
1364   *
1365   *   query.where() // add some predicates
1366   *     .eq("status", Status.NEW);
1367   *
1368   *   // common pattern - we can use rawOrEmpty() instead
1369   *   if (orderIds != null && !orderIds.isEmpty()) {
1370   *     query.where().raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
1371   *   }
1372   *
1373   *   query.findList();
1374   *
1375   * }</pre>
1376   *
1377   * <h3>Using rawOrEmpty()</h3>
1378   * Note that in the example below we use the <code>?1</code> bind parameter to get  "parameter expansion"
1379   * for each element in the collection.
1380   *
1381   * <pre>{@code
1382   *
1383   *   query.where()
1384   *     .eq("status", Status.NEW)
1385   *     // only add the expression if orderIds is not empty
1386   *     .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
1387   *     .findList();
1388   *
1389   * }</pre>
1390   *
1391   * <h3>Postgres ANY</h3>
1392   * With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding
1393   * rather than <code>IN</code>.
1394   *
1395   * <pre>{@code
1396   *
1397   *   query.where()
1398   *     .eq("status", Status.NEW)
1399   *     .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
1400   *     .findList();
1401   *
1402   * }</pre>
1403   * <p>
1404   * Note that we need to cast the Postgres array for UUID types like:
1405   * </p>
1406   * <pre>{@code
1407   *
1408   *   " ... = any(?::uuid[])"
1409   *
1410   * }</pre>
1411   *
1412   * @param raw    The raw expression that is typically a subquery
1413   * @param values The values which is typically a list or set of id values.
1414   */
1415  ExpressionList<T> rawOrEmpty(String raw, Collection<?> values);
1416
1417  /**
1418   * Add a match expression.
1419   *
1420   * @param propertyName The property name for the match
1421   * @param search       The search value
1422   */
1423  ExpressionList<T> match(String propertyName, String search);
1424
1425  /**
1426   * Add a match expression with options.
1427   *
1428   * @param propertyName The property name for the match
1429   * @param search       The search value
1430   */
1431  ExpressionList<T> match(String propertyName, String search, Match options);
1432
1433  /**
1434   * Add a multi-match expression.
1435   */
1436  ExpressionList<T> multiMatch(String search, String... properties);
1437
1438  /**
1439   * Add a multi-match expression using options.
1440   */
1441  ExpressionList<T> multiMatch(String search, MultiMatch options);
1442
1443  /**
1444   * Add a simple query string expression.
1445   */
1446  ExpressionList<T> textSimple(String search, TextSimple options);
1447
1448  /**
1449   * Add a query string expression.
1450   */
1451  ExpressionList<T> textQueryString(String search, TextQueryString options);
1452
1453  /**
1454   * Add common terms expression.
1455   */
1456  ExpressionList<T> textCommonTerms(String search, TextCommonTerms options);
1457
1458  /**
1459   * And - join two expressions with a logical and.
1460   */
1461  ExpressionList<T> and(Expression expOne, Expression expTwo);
1462
1463  /**
1464   * Or - join two expressions with a logical or.
1465   */
1466  ExpressionList<T> or(Expression expOne, Expression expTwo);
1467
1468  /**
1469   * Negate the expression (prefix it with NOT).
1470   */
1471  ExpressionList<T> not(Expression exp);
1472
1473  /**
1474   * Start a list of expressions that will be joined by AND's
1475   * returning the expression list the expressions are added to.
1476   * <p>
1477   * This is exactly the same as conjunction();
1478   * </p>
1479   * <p>
1480   * Use endAnd() or endJunction() to end the AND junction.
1481   * </p>
1482   * <p>
1483   * Note that a where() clause defaults to an AND junction so
1484   * typically you only explicitly need to use the and() junction
1485   * when it is nested inside an or() or not() junction.
1486   * </p>
1487   * <pre>{@code
1488   *
1489   *  // Example: Nested and()
1490   *
1491   *    .where()
1492   *    .or()
1493   *      .and() // nested and
1494   *        .startsWith("name", "r")
1495   *        .eq("anniversary", onAfter)
1496   *        .endAnd()
1497   *      .and()
1498   *        .eq("status", Customer.Status.ACTIVE)
1499   *        .gt("id", 0)
1500   *        .endAnd()
1501   *      .order().asc("name")
1502   *      .findList();
1503   * }</pre>
1504   */
1505  Junction<T> and();
1506
1507  /**
1508   * Return a list of expressions that will be joined by OR's.
1509   * This is exactly the same as disjunction();
1510   * <p>
1511   * Use endOr() or endJunction() to end the OR junction.
1512   * </p>
1513   *
1514   * <pre>{@code
1515   *
1516   *  // Example: (status active OR anniversary is null)
1517   *
1518   *    .where()
1519   *    .or()
1520   *      .eq("status", Customer.Status.ACTIVE)
1521   *      .isNull("anniversary")
1522   *    .order().asc("name")
1523   *    .findList();
1524   *
1525   * }</pre>
1526   *
1527   * <pre>{@code
1528   *
1529   *  // Example: Use or() to join
1530   *  // two nested and() expressions
1531   *
1532   *    .where()
1533   *    .or()
1534   *      .and()
1535   *        .startsWith("name", "r")
1536   *        .eq("anniversary", onAfter)
1537   *        .endAnd()
1538   *      .and()
1539   *        .eq("status", Customer.Status.ACTIVE)
1540   *        .gt("id", 0)
1541   *        .endAnd()
1542   *      .order().asc("name")
1543   *      .findList();
1544   *
1545   * }</pre>
1546   */
1547  Junction<T> or();
1548
1549  /**
1550   * Return a list of expressions that will be wrapped by NOT.
1551   * <p>
1552   * Use endNot() or endJunction() to end expressions being added to the
1553   * NOT expression list.
1554   * </p>
1555   *
1556   * <pre>{@code
1557   *
1558   *    .where()
1559   *      .not()
1560   *        .gt("id", 1)
1561   *        .eq("anniversary", onAfter)
1562   *        .endNot()
1563   *
1564   * }</pre>
1565   *
1566   * <pre>{@code
1567   *
1568   * // Example: nested not()
1569   *
1570   *   .where()
1571   *     .eq("status", Customer.Status.ACTIVE)
1572   *     .not()
1573   *       .gt("id", 1)
1574   *       .eq("anniversary", onAfter)
1575   *       .endNot()
1576   *     .order()
1577   *       .asc("name")
1578   *     .findList();
1579   *
1580   * }</pre>
1581   */
1582  Junction<T> not();
1583
1584  /**
1585   * Start (and return) a list of expressions that will be joined by AND's.
1586   * <p>
1587   * This is the same as and().
1588   * </p>
1589   */
1590  Junction<T> conjunction();
1591
1592  /**
1593   * Start (and return) a list of expressions that will be joined by OR's.
1594   * <p>
1595   * This is the same as or().
1596   * </p>
1597   */
1598  Junction<T> disjunction();
1599
1600  /**
1601   * Start a list of expressions that will be joined by MUST.
1602   * <p>
1603   * This automatically makes the query a useDocStore(true) query that
1604   * will execute against the document store (ElasticSearch etc).
1605   * </p>
1606   * <p>
1607   * This is logically similar to and().
1608   * </p>
1609   */
1610  Junction<T> must();
1611
1612  /**
1613   * Start a list of expressions that will be joined by SHOULD.
1614   * <p>
1615   * This automatically makes the query a useDocStore(true) query that
1616   * will execute against the document store (ElasticSearch etc).
1617   * </p>
1618   * <p>
1619   * This is logically similar to or().
1620   * </p>
1621   */
1622  Junction<T> should();
1623
1624  /**
1625   * Start a list of expressions that will be joined by MUST NOT.
1626   * <p>
1627   * This automatically makes the query a useDocStore(true) query that
1628   * will execute against the document store (ElasticSearch etc).
1629   * </p>
1630   * <p>
1631   * This is logically similar to not().
1632   * </p>
1633   */
1634  Junction<T> mustNot();
1635
1636  /**
1637   * End a junction returning the parent expression list.
1638   * <p>
1639   * Ends a and(), or(), not(), must(), mustNot() or should() junction
1640   * such that you get the parent expression.
1641   * </p>
1642   * <p>
1643   * Alternatively you can always use where() to return the top level expression list.
1644   * </p>
1645   */
1646  ExpressionList<T> endJunction();
1647
1648  /**
1649   * End a AND junction - synonym for endJunction().
1650   */
1651  ExpressionList<T> endAnd();
1652
1653  /**
1654   * End a OR junction - synonym for endJunction().
1655   */
1656  ExpressionList<T> endOr();
1657
1658  /**
1659   * End a NOT junction - synonym for endJunction().
1660   */
1661  ExpressionList<T> endNot();
1662
1663}