001package io.ebean.typequery; 002 003import io.ebean.CacheMode; 004import io.ebean.DB; 005import io.ebean.Database; 006import io.ebean.DtoQuery; 007import io.ebean.ExpressionList; 008import io.ebean.FetchConfig; 009import io.ebean.FetchGroup; 010import io.ebean.FutureIds; 011import io.ebean.FutureList; 012import io.ebean.FutureRowCount; 013import io.ebean.PagedList; 014import io.ebean.PersistenceContextScope; 015import io.ebean.ProfileLocation; 016import io.ebean.Query; 017import io.ebean.QueryIterator; 018import io.ebean.RawSql; 019import io.ebean.Transaction; 020import io.ebean.UpdateQuery; 021import io.ebean.Version; 022import io.ebean.search.MultiMatch; 023import io.ebean.search.TextCommonTerms; 024import io.ebean.search.TextQueryString; 025import io.ebean.search.TextSimple; 026import io.ebean.service.SpiFetchGroupQuery; 027import io.ebean.text.PathProperties; 028import io.ebeaninternal.server.util.ArrayStack; 029 030import javax.annotation.Nonnull; 031import javax.annotation.Nullable; 032import java.sql.Connection; 033import java.sql.Timestamp; 034import java.util.Collection; 035import java.util.List; 036import java.util.Map; 037import java.util.Optional; 038import java.util.Set; 039import java.util.function.Consumer; 040import java.util.function.Predicate; 041import java.util.stream.Stream; 042 043/** 044 * Base root query bean. 045 * <p> 046 * With code generation for each entity bean type a query bean is created that extends this. 047 * <p> 048 * Provides common features for all root query beans 049 * </p> 050 * <p> 051 * <h2>Example - QCustomer extends TQRootBean</h2> 052 * <p> 053 * These 'query beans' like QCustomer are generated using the <code>avaje-ebeanorm-typequery-generator</code>. 054 * </p> 055 * <pre>{@code 056 * 057 * public class QCustomer extends TQRootBean<Customer,QCustomer> { 058 * 059 * // properties 060 * public PLong<QCustomer> id; 061 * 062 * public PString<QCustomer> name; 063 * ... 064 * 065 * }</pre> 066 * <p> 067 * <h2>Example - usage of QCustomer</h2> 068 * <pre>{@code 069 * 070 * Date fiveDaysAgo = ... 071 * 072 * List<Customer> customers = 073 * new QCustomer() 074 * .name.ilike("rob") 075 * .status.equalTo(Customer.Status.GOOD) 076 * .registered.after(fiveDaysAgo) 077 * .contacts.email.endsWith("@foo.com") 078 * .orderBy() 079 * .name.asc() 080 * .registered.desc() 081 * .findList(); 082 * 083 * }</pre> 084 * <p> 085 * <h2>Resulting SQL where</h2> 086 * <p> 087 * <pre>{@code sql 088 * 089 * where lower(t0.name) like ? and t0.status = ? and t0.registered > ? and u1.email like ? 090 * order by t0.name, t0.registered desc; 091 * 092 * --bind(rob,GOOD,Mon Jul 27 12:05:37 NZST 2015,%@foo.com) 093 * }</pre> 094 * 095 * @param <T> the entity bean type (normal entity bean type e.g. Customer) 096 * @param <R> the specific root query bean type (e.g. QCustomer) 097 */ 098public abstract class TQRootBean<T, R> { 099 100 /** 101 * The underlying query. 102 */ 103 private final Query<T> query; 104 105 /** 106 * The underlying expression lists held as a stack. Pushed and popped based on and/or (conjunction/disjunction). 107 */ 108 private ArrayStack<ExpressionList<T>> whereStack; 109 110 /** 111 * Stack of Text expressions ("query" section of ElasticSearch query rather than "filter" section). 112 */ 113 private ArrayStack<ExpressionList<T>> textStack; 114 115 /** 116 * When true expressions should be added to the "text" stack - ElasticSearch "query" section 117 * rather than the "where" stack. 118 */ 119 private boolean textMode; 120 121 /** 122 * The root query bean instance. Used to provide fluid query construction. 123 */ 124 private R root; 125 126 /** 127 * Construct using the type of bean to query on and the default database. 128 */ 129 public TQRootBean(Class<T> beanType) { 130 this(beanType, DB.getDefault()); 131 } 132 133 /** 134 * Construct using the type of bean to query on and a given database. 135 */ 136 public TQRootBean(Class<T> beanType, Database database) { 137 this(database.find(beanType)); 138 } 139 140 /** 141 * Construct with a transaction. 142 */ 143 protected TQRootBean(Class<T> beanType, Transaction transaction) { 144 this(beanType); 145 query.usingTransaction(transaction); 146 } 147 148 /** 149 * Construct with a database and transaction. 150 */ 151 protected TQRootBean(Class<T> beanType, Database database, Transaction transaction) { 152 this(beanType, database); 153 query.usingTransaction(transaction); 154 } 155 156 /** 157 * Construct using a query. 158 */ 159 @SuppressWarnings("unchecked") 160 public TQRootBean(Query<T> query) { 161 this.query = query; 162 this.root = (R) this; 163 } 164 165 /** 166 * Construct for using as an 'Alias' to use the properties as known string 167 * values for select() and fetch(). 168 */ 169 public TQRootBean(boolean aliasDummy) { 170 this.query = null; 171 } 172 173 /** 174 * Return the fetch group. 175 */ 176 public FetchGroup<T> buildFetchGroup() { 177 return ((SpiFetchGroupQuery) query()).buildFetchGroup(); 178 } 179 180 /** 181 * Sets the root query bean instance. Used to provide fluid query construction. 182 */ 183 protected void setRoot(R root) { 184 this.root = root; 185 } 186 187 /** 188 * Return the underlying query. 189 * <p> 190 * Generally it is not expected that you will need to do this but typically use 191 * the find methods available on this 'root query bean' instance like findList(). 192 * </p> 193 */ 194 @Nonnull 195 public Query<T> query() { 196 return query; 197 } 198 199 /** 200 * Explicitly set a comma delimited list of the properties to fetch on the 201 * 'main' root level entity bean (aka partial object). Note that '*' means all 202 * properties. 203 * <p> 204 * You use {@link #fetch(String, String)} to specify specific properties to fetch 205 * on other non-root level paths of the object graph. 206 * </p> 207 * <p> 208 * <pre>{@code 209 * 210 * List<Customer> customers = 211 * new QCustomer() 212 * // Only fetch the customer id, name and status. 213 * // This is described as a "Partial Object" 214 * .select("name, status") 215 * .name.ilike("rob%") 216 * .findList(); 217 * 218 * }</pre> 219 * 220 * @param properties the properties to fetch for this bean (* = all properties). 221 */ 222 public R select(String properties) { 223 query.select(properties); 224 return root; 225 } 226 227 /** 228 * Set a FetchGroup to control what part of the object graph is loaded. 229 * <p> 230 * This is an alternative to using select() and fetch() providing a nice clean separation 231 * between what a query should load and the query predicates. 232 * </p> 233 * 234 * <pre>{@code 235 * 236 * FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class) 237 * .select("name, status") 238 * .fetch("contacts", "firstName, lastName, email") 239 * .build(); 240 * 241 * List<Customer> customers = 242 * 243 * new QCustomer() 244 * .select(fetchGroup) 245 * .findList(); 246 * 247 * }</pre> 248 */ 249 public R select(FetchGroup<T> fetchGroup) { 250 query.select(fetchGroup); 251 return root; 252 } 253 254 /** 255 * Tune the query by specifying the properties to be loaded on the 256 * 'main' root level entity bean (aka partial object). 257 * <pre>{@code 258 * 259 * // alias for the customer properties in select() 260 * QCustomer cust = QCustomer.alias(); 261 * 262 * // alias for the contact properties in contacts.fetch() 263 * QContact contact = QContact.alias(); 264 * 265 * List<Customer> customers = 266 * new QCustomer() 267 * // tune query 268 * .select(cust.id, cust.name) 269 * .contacts.fetch(contact.firstName, contact.lastName, contact.email) 270 * 271 * // predicates 272 * .id.greaterThan(1) 273 * .findList(); 274 * 275 * }</pre> 276 * 277 * @param properties the list of properties to fetch 278 */ 279 @SafeVarargs 280 public final R select(TQProperty<R>... properties) { 281 StringBuilder selectProps = new StringBuilder(50); 282 for (int i = 0; i < properties.length; i++) { 283 if (i > 0) { 284 selectProps.append(","); 285 } 286 selectProps.append(properties[i].propertyName()); 287 } 288 query.select(selectProps.toString()); 289 return root; 290 } 291 292 /** 293 * Specify a path to load including all its properties. 294 * <p> 295 * The same as {@link #fetch(String, String)} with the fetchProperties as "*". 296 * </p> 297 * <pre>{@code 298 * 299 * List<Customer> customers = 300 * new QCustomer() 301 * // eager fetch the contacts 302 * .fetch("contacts") 303 * .findList(); 304 * 305 * }</pre> 306 * 307 * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean. 308 */ 309 public R fetch(String path) { 310 query.fetch(path); 311 return root; 312 } 313 314 /** 315 * Specify a path to load including all its properties using a "query join". 316 * 317 * <pre>{@code 318 * 319 * List<Customer> customers = 320 * new QCustomer() 321 * // eager fetch the contacts using a "query join" 322 * .fetchQuery("contacts") 323 * .findList(); 324 * 325 * }</pre> 326 * 327 * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean. 328 */ 329 public R fetchQuery(String path) { 330 query.fetchQuery(path); 331 return root; 332 } 333 334 /** 335 * Specify a path to load from L2 cache including all its properties. 336 * 337 * <pre>{@code 338 * 339 * List<Order> orders = 340 * new QOrder() 341 * // eager fetch the customer using L2 cache 342 * .fetchCache("customer") 343 * .findList(); 344 * 345 * }</pre> 346 * 347 * @param path the property path to load from L2 cache. 348 */ 349 public R fetchCache(String path) { 350 query.fetchCache(path); 351 return root; 352 } 353 354 /** 355 * Specify a path and properties to load using a "query join". 356 * 357 * <pre>{@code 358 * 359 * List<Customer> customers = 360 * new QCustomer() 361 * // eager fetch contacts using a "query join" 362 * .fetchQuery("contacts", "email, firstName, lastName") 363 * .findList(); 364 * 365 * }</pre> 366 * 367 * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean. 368 * @param properties the properties to load for this path. 369 */ 370 public R fetchQuery(String path, String properties) { 371 query.fetchQuery(path, properties); 372 return root; 373 } 374 375 /** 376 * Specify a path and properties to load from L2 cache. 377 * 378 * <pre>{@code 379 * 380 * List<Order> orders = 381 * new QOrder() 382 * // eager fetch the customer using L2 cache 383 * .fetchCache("customer", "name,status") 384 * .findList(); 385 * 386 * }</pre> 387 * 388 * @param path the property path to load from L2 cache. 389 * @param properties the properties to load for this path. 390 */ 391 public R fetchCache(String path, String properties) { 392 query.fetchCache(path, properties); 393 return root; 394 } 395 396 /** 397 * Specify a path to <em>fetch</em> with its specific properties to include 398 * (aka partial object). 399 * <p> 400 * When you specify a join this means that property (associated bean(s)) will 401 * be fetched and populated. If you specify "*" then all the properties of the 402 * associated bean will be fetched and populated. You can specify a comma 403 * delimited list of the properties of that associated bean which means that 404 * only those properties are fetched and populated resulting in a 405 * "Partial Object" - a bean that only has some of its properties populated. 406 * </p> 407 * <p> 408 * <pre>{@code 409 * 410 * // query orders... 411 * List<Order> orders = 412 * new QOrder() 413 * .fetch("customer", "name, phoneNumber") 414 * .fetch("customer.billingAddress", "*") 415 * .findList(); 416 * 417 * }</pre> 418 * <p> 419 * If columns is null or "*" then all columns/properties for that path are fetched. 420 * </p> 421 * 422 * <pre>{@code 423 * 424 * List<Customer> customers = 425 * new QCustomer() 426 * .select("name, status") 427 * .fetch("contacts", "firstName,lastName,email") 428 * .findList(); 429 * 430 * }</pre> 431 * 432 * @param path the path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean. 433 * @param properties properties of the associated bean that you want to include in the 434 * fetch (* means all properties, null also means all properties). 435 */ 436 public R fetch(String path, String properties) { 437 query.fetch(path, properties); 438 return root; 439 } 440 441 /** 442 * Additionally specify a FetchConfig to use a separate query or lazy loading 443 * to load this path. 444 * <p> 445 * <pre>{@code 446 * 447 * // fetch customers (their id, name and status) 448 * List<Customer> customers = 449 * new QCustomer() 450 * .select("name, status") 451 * .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10)) 452 * .findList(); 453 * 454 * }</pre> 455 */ 456 public R fetch(String path, String properties, FetchConfig fetchConfig) { 457 query.fetch(path, properties, fetchConfig); 458 return root; 459 } 460 461 /** 462 * Additionally specify a FetchConfig to specify a "query join" and or define 463 * the lazy loading query. 464 * <p> 465 * <pre>{@code 466 * 467 * // fetch customers (their id, name and status) 468 * List<Customer> customers = 469 * new QCustomer() 470 * // lazy fetch contacts with a batch size of 100 471 * .fetch("contacts", new FetchConfig().lazy(100)) 472 * .findList(); 473 * 474 * }</pre> 475 */ 476 public R fetch(String path, FetchConfig fetchConfig) { 477 query.fetch(path, fetchConfig); 478 return root; 479 } 480 481 /** 482 * Apply the path properties replacing the select and fetch clauses. 483 * <p> 484 * This is typically used when the PathProperties is applied to both the query and the JSON output. 485 * </p> 486 */ 487 public R apply(PathProperties pathProperties) { 488 query.apply(pathProperties); 489 return root; 490 } 491 492 /** 493 * Perform an 'As of' query using history tables to return the object graph 494 * as of a time in the past. 495 * <p> 496 * To perform this query the DB must have underlying history tables. 497 * </p> 498 * 499 * @param asOf the date time in the past at which you want to view the data 500 */ 501 public R asOf(Timestamp asOf) { 502 query.asOf(asOf); 503 return root; 504 } 505 506 /** 507 * Execute the query against the draft set of tables. 508 */ 509 public R asDraft() { 510 query.asDraft(); 511 return root; 512 } 513 514 /** 515 * Execute the query including soft deleted rows. 516 */ 517 public R setIncludeSoftDeletes() { 518 query.setIncludeSoftDeletes(); 519 return root; 520 } 521 522 /** 523 * Set root table alias. 524 */ 525 public R alias(String alias) { 526 query.alias(alias); 527 return root; 528 } 529 530 /** 531 * Set the maximum number of rows to return in the query. 532 * 533 * @param maxRows the maximum number of rows to return in the query. 534 */ 535 public R setMaxRows(int maxRows) { 536 query.setMaxRows(maxRows); 537 return root; 538 } 539 540 /** 541 * Set the first row to return for this query. 542 * 543 * @param firstRow the first row to include in the query result. 544 */ 545 public R setFirstRow(int firstRow) { 546 query.setFirstRow(firstRow); 547 return root; 548 } 549 550 /** 551 * Execute the query allowing properties with invalid JSON to be collected and not fail the query. 552 * <pre>{@code 553 * 554 * // fetch a bean with JSON content 555 * EBasicJsonList bean= new QEBasicJsonList() 556 * .id.equalTo(42) 557 * .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON 558 * .findOne(); 559 * 560 * 561 * // get the invalid JSON errors from the bean state 562 * Map<String, Exception> errors = server().getBeanState(bean).getLoadErrors(); 563 * 564 * // If this map is not empty tell we have invalid JSON 565 * // and should try and fix the JSON content or inform the user 566 * 567 * }</pre> 568 */ 569 public R setAllowLoadErrors() { 570 query.setAllowLoadErrors(); 571 return root; 572 } 573 574 /** 575 * Explicitly specify whether to use AutoTune for this query. 576 * <p> 577 * If you do not call this method on a query the "Implicit AutoTune mode" is 578 * used to determine if AutoTune should be used for a given query. 579 * </p> 580 * <p> 581 * AutoTune can add additional fetch paths to the query and specify which 582 * properties are included for each path. If you have explicitly defined some 583 * fetch paths AutoTune will not remove them. 584 * </p> 585 */ 586 public R setAutoTune(boolean autoTune) { 587 query.setAutoTune(autoTune); 588 return root; 589 } 590 591 /** 592 * A hint which for JDBC translates to the Statement.fetchSize(). 593 * <p> 594 * Gives the JDBC driver a hint as to the number of rows that should be 595 * fetched from the database when more rows are needed for ResultSet. 596 * </p> 597 */ 598 public R setBufferFetchSizeHint(int fetchSize) { 599 query.setBufferFetchSizeHint(fetchSize); 600 return root; 601 } 602 603 /** 604 * Set whether this query uses DISTINCT. 605 */ 606 public R setDistinct(boolean distinct) { 607 query.setDistinct(distinct); 608 return root; 609 } 610 611 /** 612 * Set the index(es) to search for a document store which uses partitions. 613 * <p> 614 * For example, when executing a query against ElasticSearch with daily indexes we can 615 * explicitly specify the indexes to search against. 616 * </p> 617 * <pre>{@code 618 * 619 * // explicitly specify the indexes to search 620 * query.setDocIndexName("logstash-2016.11.5,logstash-2016.11.6") 621 * 622 * // search today's index 623 * query.setDocIndexName("$today") 624 * 625 * // search the last 3 days 626 * query.setDocIndexName("$last-3") 627 * 628 * }</pre> 629 * <p> 630 * If the indexName is specified with ${daily} e.g. "logstash-${daily}" ... then we can use 631 * $today and $last-x as the search docIndexName like the examples below. 632 * </p> 633 * <pre>{@code 634 * 635 * // search today's index 636 * query.setDocIndexName("$today") 637 * 638 * // search the last 3 days 639 * query.setDocIndexName("$last-3") 640 * 641 * }</pre> 642 * 643 * @param indexName The index or indexes to search against 644 * @return This query 645 */ 646 public R setDocIndexName(String indexName) { 647 query.setDocIndexName(indexName); 648 return root; 649 } 650 651 /** 652 * Restrict the query to only return subtypes of the given inherit type. 653 * <pre>{@code 654 * 655 * List<Animal> animals = 656 * new QAnimal() 657 * .name.startsWith("Fluffy") 658 * .setInheritType(Cat.class) 659 * .findList(); 660 * 661 * }</pre> 662 */ 663 public R setInheritType(Class<? extends T> type) { 664 query.setInheritType(type); 665 return root; 666 } 667 668 /** 669 * Set the base table to use for this query. 670 * <p> 671 * Typically this is used when a table has partitioning and we wish to specify a specific 672 * partition/table to query against. 673 * </p> 674 * <pre>{@code 675 * 676 * QOrder() 677 * .setBaseTable("order_2019_05") 678 * .status.equalTo(Status.NEW) 679 * .findList(); 680 * 681 * }</pre> 682 */ 683 public R setBaseTable(String baseTable) { 684 query.setBaseTable(baseTable); 685 return root; 686 } 687 688 /** 689 * Execute the query with the given lock type and WAIT. 690 * <p> 691 * Note that <code>forUpdate()</code> is the same as 692 * <code>withLock(LockType.UPDATE)</code>. 693 * <p> 694 * Provides us with the ability to explicitly use Postgres 695 * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. 696 */ 697 R withLock(Query.LockType lockType) { 698 query.withLock(lockType); 699 return root; 700 } 701 702 /** 703 * Execute the query with the given lock type and lock wait. 704 * <p> 705 * Note that <code>forUpdateNoWait()</code> is the same as 706 * <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>. 707 * <p> 708 * Provides us with the ability to explicitly use Postgres 709 * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. 710 */ 711 R withLock(Query.LockType lockType, Query.LockWait lockWait) { 712 query.withLock(lockType, lockWait); 713 return root; 714 } 715 716 /** 717 * Execute using "for update" clause which results in the DB locking the record. 718 */ 719 public R forUpdate() { 720 query.forUpdate(); 721 return root; 722 } 723 724 /** 725 * Deprecated - migrate to withLock(). 726 * Execute using "for update" with given lock type (currently Postgres only). 727 */ 728 @Deprecated 729 public R forUpdate(Query.LockType lockType) { 730 query.forUpdate(lockType); 731 return root; 732 } 733 734 /** 735 * Execute using "for update" clause with "no wait" option. 736 * <p> 737 * This is typically a Postgres and Oracle only option at this stage. 738 */ 739 public R forUpdateNoWait() { 740 query.forUpdateNoWait(); 741 return root; 742 } 743 744 /** 745 * Deprecated - migrate to withLock(). 746 * Execute using "for update nowait" with given lock type (currently Postgres only). 747 */ 748 @Deprecated 749 public R forUpdateNoWait(Query.LockType lockType) { 750 query.forUpdateNoWait(lockType); 751 return root; 752 } 753 754 /** 755 * Execute using "for update" clause with "skip locked" option. 756 * <p> 757 * This is typically a Postgres and Oracle only option at this stage. 758 * </p> 759 */ 760 public R forUpdateSkipLocked() { 761 query.forUpdateSkipLocked(); 762 return root; 763 } 764 765 /** 766 * Deprecated - migrate to withLock(). 767 * Execute using "for update skip locked" with given lock type (currently Postgres only). 768 */ 769 @Deprecated 770 public R forUpdateSkipLocked(Query.LockType lockType) { 771 query.forUpdateSkipLocked(lockType); 772 return root; 773 } 774 775 /** 776 * Return this query as an UpdateQuery. 777 * 778 * <pre>{@code 779 * 780 * int rows = 781 * new QCustomer() 782 * .name.startsWith("Rob") 783 * .organisation.id.equalTo(42) 784 * .asUpdate() 785 * .set("active", false) 786 * .update() 787 * 788 * }</pre> 789 * 790 * @return This query as an UpdateQuery 791 */ 792 public UpdateQuery<T> asUpdate() { 793 return query.asUpdate(); 794 } 795 796 /** 797 * Convert the query to a DTO bean query. 798 * <p> 799 * We effectively use the underlying ORM query to build the SQL and then execute 800 * and map it into DTO beans. 801 */ 802 public <D> DtoQuery<D> asDto(Class<D> dtoClass) { 803 return query.asDto(dtoClass); 804 } 805 806 /** 807 * Set the Id value to query. This is used with findOne(). 808 * <p> 809 * You can use this to have further control over the query. For example adding 810 * fetch joins. 811 * </p> 812 * <p> 813 * <pre>{@code 814 * 815 * Order order = 816 * new QOrder() 817 * .setId(1) 818 * .fetch("details") 819 * .findOne(); 820 * 821 * // the order details were eagerly fetched 822 * List<OrderDetail> details = order.getDetails(); 823 * 824 * }</pre> 825 */ 826 public R setId(Object id) { 827 query.setId(id); 828 return root; 829 } 830 831 /** 832 * Set a list of Id values to match. 833 * <p> 834 * <pre>{@code 835 * 836 * List<Order> orders = 837 * new QOrder() 838 * .setIdIn(42, 43, 44) 839 * .findList(); 840 * 841 * // the order details were eagerly fetched 842 * List<OrderDetail> details = order.getDetails(); 843 * 844 * }</pre> 845 */ 846 public R setIdIn(Object... ids) { 847 query.where().idIn(ids); 848 return root; 849 } 850 851 /** 852 * Set a label on the query. 853 * <p> 854 * This label can be used to help identify query performance metrics but we can also use 855 * profile location enhancement on Finders so for some that would be a better option. 856 * </p> 857 */ 858 public R setLabel(String label) { 859 query.setLabel(label); 860 return root; 861 } 862 863 /** 864 * Set the profile location. 865 * <p> 866 * This is typically set automatically via enhancement when profile location enhancement 867 * is turned on. It is generally not set by application code. 868 * </p> 869 */ 870 public R setProfileLocation(ProfileLocation profileLocation) { 871 query.setProfileLocation(profileLocation); 872 return root; 873 } 874 875 /** 876 * Set the default lazy loading batch size to use. 877 * <p> 878 * When lazy loading is invoked on beans loaded by this query then this sets the 879 * batch size used to load those beans. 880 * 881 * @param lazyLoadBatchSize the number of beans to lazy load in a single batch 882 */ 883 public R setLazyLoadBatchSize(int lazyLoadBatchSize) { 884 query.setLazyLoadBatchSize(lazyLoadBatchSize); 885 return root; 886 } 887 888 /** 889 * When set to true all the beans from this query are loaded into the bean 890 * cache. 891 */ 892 public R setLoadBeanCache(boolean loadBeanCache) { 893 query.setLoadBeanCache(loadBeanCache); 894 return root; 895 } 896 897 /** 898 * Set the property to use as keys for a map. 899 * <p> 900 * If no property is set then the id property is used. 901 * </p> 902 * <p> 903 * <pre>{@code 904 * 905 * // Assuming sku is unique for products... 906 * 907 * Map<String,Product> productMap = 908 * new QProduct() 909 * // use sku for keys... 910 * .setMapKey("sku") 911 * .findMap(); 912 * 913 * }</pre> 914 * 915 * @param mapKey the property to use as keys for a map. 916 */ 917 public R setMapKey(String mapKey) { 918 query.setMapKey(mapKey); 919 return root; 920 } 921 922 /** 923 * Specify the PersistenceContextScope to use for this query. 924 * <p> 925 * When this is not set the 'default' configured on {@link io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)} 926 * is used - this value defaults to {@link io.ebean.PersistenceContextScope#TRANSACTION}. 927 * <p> 928 * Note that the same persistence Context is used for subsequent lazy loading and query join queries. 929 * <p> 930 * Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for 931 * queries executed as #findIterate, #findEach, #findEachWhile. 932 * 933 * @param scope The scope to use for this query and subsequent lazy loading. 934 */ 935 public R setPersistenceContextScope(PersistenceContextScope scope) { 936 query.setPersistenceContextScope(scope); 937 return root; 938 } 939 940 /** 941 * Set RawSql to use for this query. 942 */ 943 public R setRawSql(RawSql rawSql) { 944 query.setRawSql(rawSql); 945 return root; 946 } 947 948 /** 949 * When set to true when you want the returned beans to be read only. 950 */ 951 public R setReadOnly(boolean readOnly) { 952 query.setReadOnly(readOnly); 953 return root; 954 } 955 956 /** 957 * Set this to true to use the bean cache. 958 * <p> 959 * If the query result is in cache then by default this same instance is 960 * returned. In this sense it should be treated as a read only object graph. 961 * </p> 962 */ 963 public R setUseCache(boolean useCache) { 964 query.setUseCache(useCache); 965 return root; 966 } 967 968 969 /** 970 * Set the mode to use the bean cache when executing this query. 971 * <p> 972 * By default "find by id" and "find by natural key" will use the bean cache 973 * when bean caching is enabled. Setting this to false means that the query 974 * will not use the bean cache and instead hit the database. 975 * </p> 976 * <p> 977 * By default findList() with natural keys will not use the bean cache. In that 978 * case we need to explicitly use the bean cache. 979 * </p> 980 */ 981 public R setBeanCacheMode(CacheMode beanCacheMode) { 982 query.setBeanCacheMode(beanCacheMode); 983 return root; 984 } 985 986 /** 987 * Set to true if this query should execute against the doc store. 988 * <p> 989 * When setting this you may also consider disabling lazy loading. 990 * </p> 991 */ 992 public R setUseDocStore(boolean useDocStore) { 993 query.setUseDocStore(useDocStore); 994 return root; 995 } 996 997 /** 998 * Set true if you want to disable lazy loading. 999 * <p> 1000 * That is, once the object graph is returned further lazy loading is disabled. 1001 * </p> 1002 */ 1003 public R setDisableLazyLoading(boolean disableLazyLoading) { 1004 query.setDisableLazyLoading(disableLazyLoading); 1005 return root; 1006 } 1007 1008 /** 1009 * Disable read auditing for this query. 1010 * <p> 1011 * This is intended to be used when the query is not a user initiated query and instead 1012 * part of the internal processing in an application to load a cache or document store etc. 1013 * In these cases we don't want the query to be part of read auditing. 1014 * </p> 1015 */ 1016 public R setDisableReadAuditing() { 1017 query.setDisableReadAuditing(); 1018 return root; 1019 } 1020 1021 /** 1022 * Set this to true to use the query cache. 1023 */ 1024 public R setUseQueryCache(boolean useCache) { 1025 query.setUseQueryCache(useCache); 1026 return root; 1027 } 1028 1029 /** 1030 * Set the {@link CacheMode} to use the query for executing this query. 1031 */ 1032 public R setUseQueryCache(CacheMode cacheMode) { 1033 query.setUseQueryCache(cacheMode); 1034 return root; 1035 } 1036 1037 /** 1038 * Set a timeout on this query. 1039 * <p> 1040 * This will typically result in a call to setQueryTimeout() on a 1041 * preparedStatement. If the timeout occurs an exception will be thrown - this 1042 * will be a SQLException wrapped up in a PersistenceException. 1043 * </p> 1044 * 1045 * @param secs the query timeout limit in seconds. Zero means there is no limit. 1046 */ 1047 public R setTimeout(int secs) { 1048 query.setTimeout(secs); 1049 return root; 1050 } 1051 1052 /** 1053 * Returns the set of properties or paths that are unknown (do not map to known properties or paths). 1054 * <p> 1055 * Validate the query checking the where and orderBy expression paths to confirm if 1056 * they represent valid properties or paths for the given bean type. 1057 * </p> 1058 */ 1059 public Set<String> validate() { 1060 return query.validate(); 1061 } 1062 1063 /** 1064 * Add raw expression with no parameters. 1065 * <p> 1066 * When properties in the clause are fully qualified as table-column names 1067 * then they are not translated. logical property name names (not fully 1068 * qualified) will still be translated to their physical name. 1069 * </p> 1070 * <p> 1071 * <pre>{@code 1072 * 1073 * raw("orderQty < shipQty") 1074 * 1075 * }</pre> 1076 * 1077 * <h4>Subquery example:</h4> 1078 * <pre>{@code 1079 * 1080 * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds) 1081 * 1082 * }</pre> 1083 */ 1084 public R raw(String rawExpression) { 1085 peekExprList().raw(rawExpression); 1086 return root; 1087 } 1088 1089 /** 1090 * Add raw expression with an array of parameters. 1091 * <p> 1092 * The raw expression should contain the same number of ? as there are 1093 * parameters. 1094 * </p> 1095 * <p> 1096 * When properties in the clause are fully qualified as table-column names 1097 * then they are not translated. logical property name names (not fully 1098 * qualified) will still be translated to their physical name. 1099 * </p> 1100 */ 1101 public R raw(String rawExpression, Object... bindValues) { 1102 peekExprList().raw(rawExpression, bindValues); 1103 return root; 1104 } 1105 1106 /** 1107 * Only add the raw expression if the values is not null or empty. 1108 * <p> 1109 * This is a pure convenience expression to make it nicer to deal with the pattern where we use 1110 * raw() expression with a subquery and only want to add the subquery predicate when the collection 1111 * of values is not empty. 1112 * </p> 1113 * <h3>Without inOrEmpty()</h3> 1114 * <pre>{@code 1115 * 1116 * QCustomer query = new QCustomer() // add some predicates 1117 * .status.equalTo(Status.NEW); 1118 * 1119 * // common pattern - we can use rawOrEmpty() instead 1120 * if (orderIds != null && !orderIds.isEmpty()) { 1121 * query.raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds); 1122 * } 1123 * 1124 * query.findList(); 1125 * 1126 * }</pre> 1127 * 1128 * <h3>Using rawOrEmpty()</h3> 1129 * Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion" 1130 * for each element in the collection. 1131 * 1132 * <pre>{@code 1133 * 1134 * new QCustomer() 1135 * .status.equalTo(Status.NEW) 1136 * // only add the expression if orderIds is not empty 1137 * .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds); 1138 * .findList(); 1139 * 1140 * }</pre> 1141 * 1142 * <h3>Postgres ANY</h3> 1143 * With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding 1144 * rather than <code>IN</code>. 1145 * 1146 * <pre>{@code 1147 * 1148 * new QCustomer() 1149 * .status.equalTo(Status.NEW) 1150 * .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds); 1151 * .findList(); 1152 * 1153 * }</pre> 1154 * <p> 1155 * Note that we need to cast the Postgres array for UUID types like: 1156 * </p> 1157 * <pre>{@code 1158 * 1159 * " ... = any(?::uuid[])" 1160 * 1161 * }</pre> 1162 * 1163 * @param raw The raw expression that is typically a subquery 1164 * @param values The values which is typically a list or set of id values. 1165 */ 1166 public R rawOrEmpty(String raw, Collection<?> values) { 1167 peekExprList().rawOrEmpty(raw, values); 1168 return root; 1169 } 1170 1171 /** 1172 * Add raw expression with a single parameter. 1173 * <p> 1174 * The raw expression should contain a single ? at the location of the 1175 * parameter. 1176 * </p> 1177 * <p> 1178 * When properties in the clause are fully qualified as table-column names 1179 * then they are not translated. logical property name names (not fully 1180 * qualified) will still be translated to their physical name. 1181 * </p> 1182 * <p> 1183 * <h4>Example:</h4> 1184 * <pre>{@code 1185 * 1186 * // use a database function 1187 * raw("add_days(orderDate, 10) < ?", someDate) 1188 * 1189 * }</pre> 1190 * 1191 * <h4>Subquery example:</h4> 1192 * <pre>{@code 1193 * 1194 * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds) 1195 * 1196 * }</pre> 1197 */ 1198 public R raw(String rawExpression, Object bindValue) { 1199 peekExprList().raw(rawExpression, bindValue); 1200 return root; 1201 } 1202 1203 /** 1204 * Marker that can be used to indicate that the order by clause is defined after this. 1205 * <p> 1206 * <h2>Example: order by customer name, order date</h2> 1207 * <pre>{@code 1208 * List<Order> orders = 1209 * new QOrder() 1210 * .customer.name.ilike("rob") 1211 * .orderBy() 1212 * .customer.name.asc() 1213 * .orderDate.asc() 1214 * .findList(); 1215 * 1216 * }</pre> 1217 */ 1218 public R orderBy() { 1219 // Yes this does not actually do anything! We include it because style wise it makes 1220 // the query nicer to read and suggests that order by definitions are added after this 1221 return root; 1222 } 1223 1224 /** 1225 * Marker that can be used to indicate that the order by clause is defined after this. 1226 * <p> 1227 * <h2>Example: order by customer name, order date</h2> 1228 * <pre>{@code 1229 * List<Order> orders = 1230 * new QOrder() 1231 * .customer.name.ilike("rob") 1232 * .orderBy() 1233 * .customer.name.asc() 1234 * .orderDate.asc() 1235 * .findList(); 1236 * 1237 * }</pre> 1238 */ 1239 public R order() { 1240 // Yes this does not actually do anything! We include it because style wise it makes 1241 // the query nicer to read and suggests that order by definitions are added after this 1242 return root; 1243 } 1244 1245 /** 1246 * Set the full raw order by clause replacing the existing order by clause if there is one. 1247 * <p> 1248 * This follows SQL syntax using commas between each property with the 1249 * optional asc and desc keywords representing ascending and descending order 1250 * respectively. 1251 */ 1252 public R orderBy(String orderByClause) { 1253 query.orderBy(orderByClause); 1254 return root; 1255 } 1256 1257 /** 1258 * Set the full raw order by clause replacing the existing order by clause if there is one. 1259 * <p> 1260 * This follows SQL syntax using commas between each property with the 1261 * optional asc and desc keywords representing ascending and descending order 1262 * respectively. 1263 */ 1264 public R order(String orderByClause) { 1265 query.order(orderByClause); 1266 return root; 1267 } 1268 1269 /** 1270 * Begin a list of expressions added by 'OR'. 1271 * <p> 1272 * Use endOr() or endJunction() to stop added to OR and 'pop' to the parent expression list. 1273 * </p> 1274 * <p> 1275 * <h2>Example</h2> 1276 * <p> 1277 * This example uses an 'OR' expression list with an inner 'AND' expression list. 1278 * </p> 1279 * <pre>{@code 1280 * 1281 * List<Customer> customers = 1282 * new QCustomer() 1283 * .status.equalTo(Customer.Status.GOOD) 1284 * .or() 1285 * .id.greaterThan(1000) 1286 * .and() 1287 * .name.startsWith("super") 1288 * .registered.after(fiveDaysAgo) 1289 * .endAnd() 1290 * .endOr() 1291 * .orderBy().id.desc() 1292 * .findList(); 1293 * 1294 * }</pre> 1295 * <h2>Resulting SQL where clause</h2> 1296 * <pre>{@code sql 1297 * 1298 * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) 1299 * order by t0.id desc; 1300 * 1301 * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015) 1302 * 1303 * }</pre> 1304 */ 1305 public R or() { 1306 pushExprList(peekExprList().or()); 1307 return root; 1308 } 1309 1310 /** 1311 * Begin a list of expressions added by 'AND'. 1312 * <p> 1313 * Use endAnd() or endJunction() to stop added to AND and 'pop' to the parent expression list. 1314 * </p> 1315 * <p> 1316 * Note that typically the AND expression is only used inside an outer 'OR' expression. 1317 * This is because the top level expression list defaults to an 'AND' expression list. 1318 * </p> 1319 * <h2>Example</h2> 1320 * <p> 1321 * This example uses an 'OR' expression list with an inner 'AND' expression list. 1322 * </p> 1323 * <pre>{@code 1324 * 1325 * List<Customer> customers = 1326 * new QCustomer() 1327 * .status.equalTo(Customer.Status.GOOD) 1328 * .or() // OUTER 'OR' 1329 * .id.greaterThan(1000) 1330 * .and() // NESTED 'AND' expression list 1331 * .name.startsWith("super") 1332 * .registered.after(fiveDaysAgo) 1333 * .endAnd() 1334 * .endOr() 1335 * .orderBy().id.desc() 1336 * .findList(); 1337 * 1338 * }</pre> 1339 * <h2>Resulting SQL where clause</h2> 1340 * <pre>{@code sql 1341 * 1342 * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) 1343 * order by t0.id desc; 1344 * 1345 * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015) 1346 * 1347 * }</pre> 1348 */ 1349 public R and() { 1350 pushExprList(peekExprList().and()); 1351 return root; 1352 } 1353 1354 /** 1355 * Begin a list of expressions added by NOT. 1356 * <p> 1357 * Use endNot() or endJunction() to stop added to NOT and 'pop' to the parent expression list. 1358 * </p> 1359 */ 1360 public R not() { 1361 pushExprList(peekExprList().not()); 1362 return root; 1363 } 1364 1365 /** 1366 * Begin a list of expressions added by MUST. 1367 * <p> 1368 * This automatically makes this query a document store query. 1369 * </p> 1370 * <p> 1371 * Use endJunction() to stop added to MUST and 'pop' to the parent expression list. 1372 * </p> 1373 */ 1374 public R must() { 1375 pushExprList(peekExprList().must()); 1376 return root; 1377 } 1378 1379 /** 1380 * Begin a list of expressions added by MUST NOT. 1381 * <p> 1382 * This automatically makes this query a document store query. 1383 * </p> 1384 * <p> 1385 * Use endJunction() to stop added to MUST NOT and 'pop' to the parent expression list. 1386 * </p> 1387 */ 1388 public R mustNot() { 1389 return pushExprList(peekExprList().mustNot()); 1390 } 1391 1392 /** 1393 * Begin a list of expressions added by SHOULD. 1394 * <p> 1395 * This automatically makes this query a document store query. 1396 * </p> 1397 * <p> 1398 * Use endJunction() to stop added to SHOULD and 'pop' to the parent expression list. 1399 * </p> 1400 */ 1401 public R should() { 1402 return pushExprList(peekExprList().should()); 1403 } 1404 1405 /** 1406 * End a list of expressions added by 'OR'. 1407 */ 1408 public R endJunction() { 1409 if (textMode) { 1410 textStack.pop(); 1411 } else { 1412 whereStack.pop(); 1413 } 1414 return root; 1415 } 1416 1417 /** 1418 * End OR junction - synonym for endJunction(). 1419 */ 1420 public R endOr() { 1421 return endJunction(); 1422 } 1423 1424 /** 1425 * End AND junction - synonym for endJunction(). 1426 */ 1427 public R endAnd() { 1428 return endJunction(); 1429 } 1430 1431 /** 1432 * End NOT junction - synonym for endJunction(). 1433 */ 1434 public R endNot() { 1435 return endJunction(); 1436 } 1437 1438 /** 1439 * Push the expression list onto the appropriate stack. 1440 */ 1441 private R pushExprList(ExpressionList<T> list) { 1442 if (textMode) { 1443 textStack.push(list); 1444 } else { 1445 whereStack.push(list); 1446 } 1447 return root; 1448 } 1449 1450 /** 1451 * Add expression after this to the WHERE expression list. 1452 * <p> 1453 * For queries against the normal database (not the doc store) this has no effect. 1454 * </p> 1455 * <p> 1456 * This is intended for use with Document Store / ElasticSearch where expressions can be put into either 1457 * the "query" section or the "filter" section of the query. Full text expressions like MATCH are in the 1458 * "query" section but many expression can be in either - expressions after the where() are put into the 1459 * "filter" section which means that they don't add to the relevance and are also cache-able. 1460 * </p> 1461 */ 1462 public R where() { 1463 textMode = false; 1464 return root; 1465 } 1466 1467 /** 1468 * Begin added expressions to the 'Text' expression list. 1469 * <p> 1470 * This automatically makes the query a document store query. 1471 * </p> 1472 * <p> 1473 * For ElasticSearch expressions added to 'text' go into the ElasticSearch 'query context' 1474 * and expressions added to 'where' go into the ElasticSearch 'filter context'. 1475 * </p> 1476 */ 1477 public R text() { 1478 textMode = true; 1479 return root; 1480 } 1481 1482 /** 1483 * Add a Text Multi-match expression (document store only). 1484 * <p> 1485 * This automatically makes the query a document store query. 1486 * </p> 1487 */ 1488 public R multiMatch(String query, MultiMatch multiMatch) { 1489 peekExprList().multiMatch(query, multiMatch); 1490 return root; 1491 } 1492 1493 /** 1494 * Add a Text Multi-match expression (document store only). 1495 * <p> 1496 * This automatically makes the query a document store query. 1497 * </p> 1498 */ 1499 public R multiMatch(String query, String... properties) { 1500 peekExprList().multiMatch(query, properties); 1501 return root; 1502 } 1503 1504 /** 1505 * Add a Text common terms expression (document store only). 1506 * <p> 1507 * This automatically makes the query a document store query. 1508 * </p> 1509 */ 1510 public R textCommonTerms(String query, TextCommonTerms options) { 1511 peekExprList().textCommonTerms(query, options); 1512 return root; 1513 } 1514 1515 /** 1516 * Add a Text simple expression (document store only). 1517 * <p> 1518 * This automatically makes the query a document store query. 1519 * </p> 1520 */ 1521 public R textSimple(String query, TextSimple options) { 1522 peekExprList().textSimple(query, options); 1523 return root; 1524 } 1525 1526 /** 1527 * Add a Text query string expression (document store only). 1528 * <p> 1529 * This automatically makes the query a document store query. 1530 * </p> 1531 */ 1532 public R textQueryString(String query, TextQueryString options) { 1533 peekExprList().textQueryString(query, options); 1534 return root; 1535 } 1536 1537 /** 1538 * Execute the query using the given transaction. 1539 */ 1540 public R usingTransaction(Transaction transaction) { 1541 query.usingTransaction(transaction); 1542 return root; 1543 } 1544 1545 /** 1546 * Execute the query using the given connection. 1547 */ 1548 public R usingConnection(Connection connection) { 1549 query.usingConnection(connection); 1550 return root; 1551 } 1552 1553 /** 1554 * Execute the query returning true if a row is found. 1555 * <p> 1556 * The query is executed using max rows of 1 and will only select the id property. 1557 * This method is really just a convenient way to optimise a query to perform a 1558 * 'does a row exist in the db' check. 1559 * </p> 1560 * 1561 * <h2>Example using a query bean:</h2> 1562 * <pre>{@code 1563 * 1564 * boolean userExists = 1565 * new QContact() 1566 * .email.equalTo("rob@foo.com") 1567 * .exists(); 1568 * 1569 * }</pre> 1570 * 1571 * <h2>Example:</h2> 1572 * <pre>{@code 1573 * 1574 * boolean userExists = query() 1575 * .where().eq("email", "rob@foo.com") 1576 * .exists(); 1577 * 1578 * }</pre> 1579 * 1580 * @return True if the query finds a matching row in the database 1581 */ 1582 public boolean exists() { 1583 return query.exists(); 1584 } 1585 1586 /** 1587 * Execute the query returning either a single bean or null (if no matching 1588 * bean is found). 1589 * <p> 1590 * If more than 1 row is found for this query then a PersistenceException is 1591 * thrown. 1592 * </p> 1593 * <p> 1594 * This is useful when your predicates dictate that your query should only 1595 * return 0 or 1 results. 1596 * </p> 1597 * <p> 1598 * <pre>{@code 1599 * 1600 * // assuming the sku of products is unique... 1601 * Product product = 1602 * new QProduct() 1603 * .sku.equalTo("aa113") 1604 * .findOne(); 1605 * ... 1606 * }</pre> 1607 * <p> 1608 * <p> 1609 * It is also useful with finding objects by their id when you want to specify 1610 * further join information to optimise the query. 1611 * </p> 1612 * <p> 1613 * <pre>{@code 1614 * 1615 * // Fetch order 42 and additionally fetch join its order details... 1616 * Order order = 1617 * new QOrder() 1618 * .fetch("details") // eagerly load the order details 1619 * .id.equalTo(42) 1620 * .findOne(); 1621 * 1622 * // the order details were eagerly loaded 1623 * List<OrderDetail> details = order.getDetails(); 1624 * ... 1625 * }</pre> 1626 */ 1627 @Nullable 1628 public T findOne() { 1629 return query.findOne(); 1630 } 1631 1632 /** 1633 * Execute the query returning an optional bean. 1634 */ 1635 @Nonnull 1636 public Optional<T> findOneOrEmpty() { 1637 return query.findOneOrEmpty(); 1638 } 1639 1640 /** 1641 * Execute the query returning the list of objects. 1642 * <p> 1643 * This query will execute against the EbeanServer that was used to create it. 1644 * </p> 1645 * <p> 1646 * <pre>{@code 1647 * 1648 * List<Customer> customers = 1649 * new QCustomer() 1650 * .name.ilike("rob%") 1651 * .findList(); 1652 * 1653 * }</pre> 1654 * 1655 * @see Query#findList() 1656 */ 1657 @Nonnull 1658 public List<T> findList() { 1659 return query.findList(); 1660 } 1661 1662 /** 1663 * Execute the query returning the result as a Stream. 1664 * <p> 1665 * Note that this can support very large queries iterating 1666 * any number of results. To do so internally it can use 1667 * multiple persistence contexts. 1668 * </p> 1669 * <pre>{@code 1670 * 1671 * // use try with resources to ensure Stream is closed 1672 * 1673 * try (Stream<Customer> stream = query.findStream()) { 1674 * stream 1675 * .map(...) 1676 * .collect(...); 1677 * } 1678 * 1679 * }</pre> 1680 */ 1681 @Nonnull 1682 public Stream<T> findStream() { 1683 return query.findStream(); 1684 } 1685 1686 /** 1687 * Deprecated - migrate to findStream(). 1688 */ 1689 @Deprecated 1690 public Stream<T> findLargeStream() { 1691 return query.findLargeStream(); 1692 } 1693 1694 /** 1695 * Execute the query returning the set of objects. 1696 * <p> 1697 * This query will execute against the EbeanServer that was used to create it. 1698 * </p> 1699 * <p> 1700 * <pre>{@code 1701 * 1702 * Set<Customer> customers = 1703 * new QCustomer() 1704 * .name.ilike("rob%") 1705 * .findSet(); 1706 * 1707 * }</pre> 1708 * 1709 * @see Query#findSet() 1710 */ 1711 @Nonnull 1712 public Set<T> findSet() { 1713 return query.findSet(); 1714 } 1715 1716 /** 1717 * Execute the query returning the list of Id's. 1718 * <p> 1719 * This query will execute against the EbeanServer that was used to create it. 1720 * </p> 1721 * 1722 * @see Query#findIds() 1723 */ 1724 @Nonnull 1725 public <A> List<A> findIds() { 1726 return query.findIds(); 1727 } 1728 1729 /** 1730 * Execute the query returning a map of the objects. 1731 * <p> 1732 * This query will execute against the EbeanServer that was used to create it. 1733 * </p> 1734 * <p> 1735 * You can use setMapKey() or asMapKey() to specify the property to be used as keys 1736 * on the map. If one is not specified then the id property is used. 1737 * </p> 1738 * <p> 1739 * <pre>{@code 1740 * 1741 * Map<String, Product> map = 1742 * new QProduct() 1743 * .sku.asMapKey() 1744 * .findMap(); 1745 * 1746 * }</pre> 1747 * 1748 * @see Query#findMap() 1749 */ 1750 @Nonnull 1751 public <K> Map<K, T> findMap() { 1752 return query.findMap(); 1753 } 1754 1755 /** 1756 * Execute the query iterating over the results. 1757 * <p> 1758 * Note that findIterate (and findEach and findEachWhile) uses a "per graph" 1759 * persistence context scope and adjusts jdbc fetch buffer size for large 1760 * queries. As such it is better to use findList for small queries. 1761 * </p> 1762 * <p> 1763 * Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()} 1764 * when you have finished iterating the results (typically in a finally block). 1765 * </p> 1766 * <p> 1767 * findEach() and findEachWhile() are preferred to findIterate() as they ensure 1768 * the jdbc statement and resultSet are closed at the end of the iteration. 1769 * </p> 1770 * <p> 1771 * This query will execute against the EbeanServer that was used to create it. 1772 * </p> 1773 * <pre>{@code 1774 * 1775 * Query<Customer> query = 1776 * new QCustomer() 1777 * .status.equalTo(Customer.Status.NEW) 1778 * .orderBy() 1779 * id.asc() 1780 * .query(); 1781 * 1782 * try (QueryIterator<Customer> it = query.findIterate()) { 1783 * while (it.hasNext()) { 1784 * Customer customer = it.next(); 1785 * // do something with customer ... 1786 * } 1787 * } 1788 * 1789 * }</pre> 1790 */ 1791 @Nonnull 1792 public QueryIterator<T> findIterate() { 1793 return query.findIterate(); 1794 } 1795 1796 /** 1797 * Execute the query returning a list of values for a single property. 1798 * <p> 1799 * <h3>Example</h3> 1800 * <pre>{@code 1801 * 1802 * List<String> names = 1803 * new QCustomer() 1804 * .setDistinct(true) 1805 * .select(name) 1806 * .findSingleAttributeList(); 1807 * 1808 * }</pre> 1809 * 1810 * @return the list of values for the selected property 1811 */ 1812 @Nonnull 1813 public <A> List<A> findSingleAttributeList() { 1814 return query.findSingleAttributeList(); 1815 } 1816 1817 /** 1818 * Execute the query returning a single value for a single property. 1819 * <p> 1820 * <h3>Example</h3> 1821 * <pre>{@code 1822 * 1823 * LocalDate maxDate = 1824 * new QCustomer() 1825 * .select("max(startDate)") 1826 * .findSingleAttribute(); 1827 * 1828 * }</pre> 1829 * 1830 * @return the list of values for the selected property 1831 */ 1832 public <A> A findSingleAttribute() { 1833 return query.findSingleAttribute(); 1834 } 1835 1836 /** 1837 * Execute the query processing the beans one at a time. 1838 * <p> 1839 * This method is appropriate to process very large query results as the 1840 * beans are consumed one at a time and do not need to be held in memory 1841 * (unlike #findList #findSet etc) 1842 * </p> 1843 * <p> 1844 * Note that internally Ebean can inform the JDBC driver that it is expecting larger 1845 * resultSet and specifically for MySQL this hint is required to stop it's JDBC driver 1846 * from buffering the entire resultSet. As such, for smaller resultSets findList() is 1847 * generally preferable. 1848 * </p> 1849 * <p> 1850 * Compared with #findEachWhile this will always process all the beans where as 1851 * #findEachWhile provides a way to stop processing the query result early before 1852 * all the beans have been read. 1853 * </p> 1854 * <p> 1855 * This method is functionally equivalent to findIterate() but instead of using an 1856 * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use 1857 * with Java8 closures. 1858 * </p> 1859 * <p> 1860 * <pre>{@code 1861 * 1862 * new QCustomer() 1863 * .status.equalTo(Status.NEW) 1864 * .orderBy().id.asc() 1865 * .findEach((Customer customer) -> { 1866 * 1867 * // do something with customer 1868 * System.out.println("-- visit " + customer); 1869 * }); 1870 * 1871 * }</pre> 1872 * 1873 * @param consumer the consumer used to process the queried beans. 1874 */ 1875 public void findEach(Consumer<T> consumer) { 1876 query.findEach(consumer); 1877 } 1878 1879 /** 1880 * Execute the query using callbacks to a visitor to process the resulting 1881 * beans one at a time. 1882 * <p> 1883 * This method is functionally equivalent to findIterate() but instead of using an 1884 * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use 1885 * with Java8 closures. 1886 * </p> 1887 * <p> 1888 * <p> 1889 * <pre>{@code 1890 * 1891 * new QCustomer() 1892 * .status.equalTo(Status.NEW) 1893 * .orderBy().id.asc() 1894 * .findEachWhile((Customer customer) -> { 1895 * 1896 * // do something with customer 1897 * System.out.println("-- visit " + customer); 1898 * 1899 * // return true to continue processing or false to stop 1900 * return (customer.getId() < 40); 1901 * }); 1902 * 1903 * }</pre> 1904 * 1905 * @param consumer the consumer used to process the queried beans. 1906 */ 1907 public void findEachWhile(Predicate<T> consumer) { 1908 query.findEachWhile(consumer); 1909 } 1910 1911 /** 1912 * Return versions of a @History entity bean. 1913 * <p> 1914 * Generally this query is expected to be a find by id or unique predicates query. 1915 * It will execute the query against the history returning the versions of the bean. 1916 * </p> 1917 */ 1918 @Nonnull 1919 public List<Version<T>> findVersions() { 1920 return query.findVersions(); 1921 } 1922 1923 /** 1924 * Return versions of a @History entity bean between a start and end timestamp. 1925 * <p> 1926 * Generally this query is expected to be a find by id or unique predicates query. 1927 * It will execute the query against the history returning the versions of the bean. 1928 * </p> 1929 */ 1930 @Nonnull 1931 public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) { 1932 return query.findVersionsBetween(start, end); 1933 } 1934 1935 /** 1936 * Return the count of entities this query should return. 1937 * <p> 1938 * This is the number of 'top level' or 'root level' entities. 1939 * </p> 1940 */ 1941 @Nonnull 1942 public int findCount() { 1943 return query.findCount(); 1944 } 1945 1946 /** 1947 * Execute find row count query in a background thread. 1948 * <p> 1949 * This returns a Future object which can be used to cancel, check the 1950 * execution status (isDone etc) and get the value (with or without a 1951 * timeout). 1952 * </p> 1953 * 1954 * @return a Future object for the row count query 1955 */ 1956 @Nonnull 1957 public FutureRowCount<T> findFutureCount() { 1958 return query.findFutureCount(); 1959 } 1960 1961 /** 1962 * Execute find Id's query in a background thread. 1963 * <p> 1964 * This returns a Future object which can be used to cancel, check the 1965 * execution status (isDone etc) and get the value (with or without a 1966 * timeout). 1967 * </p> 1968 * 1969 * @return a Future object for the list of Id's 1970 */ 1971 @Nonnull 1972 public FutureIds<T> findFutureIds() { 1973 return query.findFutureIds(); 1974 } 1975 1976 /** 1977 * Execute find list query in a background thread. 1978 * <p> 1979 * This query will execute in it's own PersistenceContext and using its own transaction. 1980 * What that means is that it will not share any bean instances with other queries. 1981 * </p> 1982 * 1983 * @return a Future object for the list result of the query 1984 */ 1985 @Nonnull 1986 public FutureList<T> findFutureList() { 1987 return query.findFutureList(); 1988 } 1989 1990 /** 1991 * Return a PagedList for this query using firstRow and maxRows. 1992 * <p> 1993 * The benefit of using this over findList() is that it provides functionality to get the 1994 * total row count etc. 1995 * </p> 1996 * <p> 1997 * If maxRows is not set on the query prior to calling findPagedList() then a 1998 * PersistenceException is thrown. 1999 * </p> 2000 * <p> 2001 * <pre>{@code 2002 * 2003 * PagedList<Order> pagedList = 2004 * new QOrder() 2005 * .setFirstRow(50) 2006 * .setMaxRows(20) 2007 * .findPagedList(); 2008 * 2009 * // fetch the total row count in the background 2010 * pagedList.loadRowCount(); 2011 * 2012 * List<Order> orders = pagedList.getList(); 2013 * int totalRowCount = pagedList.getTotalRowCount(); 2014 * 2015 * }</pre> 2016 * 2017 * @return The PagedList 2018 */ 2019 @Nonnull 2020 public PagedList<T> findPagedList() { 2021 return query.findPagedList(); 2022 } 2023 2024 /** 2025 * Execute as a delete query deleting the 'root level' beans that match the predicates 2026 * in the query. 2027 * <p> 2028 * Note that if the query includes joins then the generated delete statement may not be 2029 * optimal depending on the database platform. 2030 * </p> 2031 * 2032 * @return the number of beans/rows that were deleted. 2033 */ 2034 public int delete() { 2035 return query.delete(); 2036 } 2037 2038 /** 2039 * Return the sql that was generated for executing this query. 2040 * <p> 2041 * This is only available after the query has been executed and provided only 2042 * for informational purposes. 2043 * </p> 2044 */ 2045 public String getGeneratedSql() { 2046 return query.getGeneratedSql(); 2047 } 2048 2049 /** 2050 * Return the type of beans being queried. 2051 */ 2052 @Nonnull 2053 public Class<T> getBeanType() { 2054 return query.getBeanType(); 2055 } 2056 2057 /** 2058 * Return the expression list that has been built for this query. 2059 */ 2060 @Nonnull 2061 public ExpressionList<T> getExpressionList() { 2062 return query.where(); 2063 } 2064 2065 /** 2066 * Start adding expressions to the having clause when using @Aggregation properties. 2067 * 2068 * <pre>{@code 2069 * 2070 * new QMachineUse() 2071 * // where ... 2072 * .date.inRange(fromDate, toDate) 2073 * 2074 * .having() 2075 * .sumHours.greaterThan(1) 2076 * .findList() 2077 * 2078 * // The sumHours property uses @Aggregation 2079 * // e.g. @Aggregation("sum(hours)") 2080 * 2081 * }</pre> 2082 */ 2083 public R having() { 2084 if (whereStack == null) { 2085 whereStack = new ArrayStack<>(); 2086 } 2087 // effectively putting having expression list onto stack 2088 // such that expression now add to the having clause 2089 whereStack.push(query.having()); 2090 return root; 2091 } 2092 2093 /** 2094 * Return the underlying having clause to typically when using dynamic aggregation formula. 2095 * <p> 2096 * Note that after this we no longer have the query bean so typically we use this right 2097 * at the end of the query. 2098 * </p> 2099 * 2100 * <pre>{@code 2101 * 2102 * // sum(distanceKms) ... is a "dynamic formula" 2103 * // so we use havingClause() for it like: 2104 * 2105 * List<MachineUse> machineUse = 2106 * 2107 * new QMachineUse() 2108 * .select("machine, sum(fuelUsed), sum(distanceKms)") 2109 * 2110 * // where ... 2111 * .date.greaterThan(LocalDate.now().minusDays(7)) 2112 * 2113 * .havingClause() 2114 * .gt("sum(distanceKms)", 2) 2115 * .findList(); 2116 * 2117 * }</pre> 2118 */ 2119 public ExpressionList<T> havingClause() { 2120 return query.having(); 2121 } 2122 2123 /** 2124 * Return the current expression list that expressions should be added to. 2125 */ 2126 protected ExpressionList<T> peekExprList() { 2127 2128 if (textMode) { 2129 // return the current text expression list 2130 return _peekText(); 2131 } 2132 2133 if (whereStack == null) { 2134 whereStack = new ArrayStack<>(); 2135 whereStack.push(query.where()); 2136 } 2137 // return the current expression list 2138 return whereStack.peek(); 2139 } 2140 2141 protected ExpressionList<T> _peekText() { 2142 if (textStack == null) { 2143 textStack = new ArrayStack<>(); 2144 // empty so push on the queries base expression list 2145 textStack.push(query.text()); 2146 } 2147 // return the current expression list 2148 return textStack.peek(); 2149 } 2150}