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}