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