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