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 * executed the select with "for update" which should lock the record "on read" 690 */ 691 public R forUpdate() { 692 query.forUpdate(); 693 return root; 694 } 695 696 /** 697 * Execute using "for update" clause with "no wait" option. 698 * <p> 699 * This is typically a Postgres and Oracle only option at this stage. 700 * </p> 701 */ 702 public R forUpdateNoWait() { 703 query.forUpdateNoWait(); 704 return root; 705 } 706 707 /** 708 * Execute using "for update" clause with "skip locked" option. 709 * <p> 710 * This is typically a Postgres and Oracle only option at this stage. 711 * </p> 712 */ 713 public R forUpdateSkipLocked() { 714 query.forUpdateSkipLocked(); 715 return root; 716 } 717 718 /** 719 * Return this query as an UpdateQuery. 720 * 721 * <pre>{@code 722 * 723 * int rows = 724 * new QCustomer() 725 * .name.startsWith("Rob") 726 * .organisation.id.equalTo(42) 727 * .asUpdate() 728 * .set("active", false) 729 * .update() 730 * 731 * }</pre> 732 * 733 * @return This query as an UpdateQuery 734 */ 735 public UpdateQuery<T> asUpdate() { 736 return query.asUpdate(); 737 } 738 739 /** 740 * Convert the query to a DTO bean query. 741 * <p> 742 * We effectively use the underlying ORM query to build the SQL and then execute 743 * and map it into DTO beans. 744 */ 745 public <D> DtoQuery<D> asDto(Class<D> dtoClass) { 746 return query.asDto(dtoClass); 747 } 748 749 /** 750 * Set the Id value to query. This is used with findOne(). 751 * <p> 752 * You can use this to have further control over the query. For example adding 753 * fetch joins. 754 * </p> 755 * <p> 756 * <pre>{@code 757 * 758 * Order order = 759 * new QOrder() 760 * .setId(1) 761 * .fetch("details") 762 * .findOne(); 763 * 764 * // the order details were eagerly fetched 765 * List<OrderDetail> details = order.getDetails(); 766 * 767 * }</pre> 768 */ 769 public R setId(Object id) { 770 query.setId(id); 771 return root; 772 } 773 774 /** 775 * Set a list of Id values to match. 776 * <p> 777 * <pre>{@code 778 * 779 * List<Order> orders = 780 * new QOrder() 781 * .setIdIn(42, 43, 44) 782 * .findList(); 783 * 784 * // the order details were eagerly fetched 785 * List<OrderDetail> details = order.getDetails(); 786 * 787 * }</pre> 788 */ 789 public R setIdIn(Object... ids) { 790 query.where().idIn(ids); 791 return root; 792 } 793 794 /** 795 * Set a label on the query. 796 * <p> 797 * This label can be used to help identify query performance metrics but we can also use 798 * profile location enhancement on Finders so for some that would be a better option. 799 * </p> 800 */ 801 public R setLabel(String label) { 802 query.setLabel(label); 803 return root; 804 } 805 806 /** 807 * Set the profile location. 808 * <p> 809 * This is typically set automatically via enhancement when profile location enhancement 810 * is turned on. It is generally not set by application code. 811 * </p> 812 */ 813 public R setProfileLocation(ProfileLocation profileLocation) { 814 query.setProfileLocation(profileLocation); 815 return root; 816 } 817 818 /** 819 * Set the default lazy loading batch size to use. 820 * <p> 821 * When lazy loading is invoked on beans loaded by this query then this sets the 822 * batch size used to load those beans. 823 * 824 * @param lazyLoadBatchSize the number of beans to lazy load in a single batch 825 */ 826 public R setLazyLoadBatchSize(int lazyLoadBatchSize) { 827 query.setLazyLoadBatchSize(lazyLoadBatchSize); 828 return root; 829 } 830 831 /** 832 * When set to true all the beans from this query are loaded into the bean 833 * cache. 834 */ 835 public R setLoadBeanCache(boolean loadBeanCache) { 836 query.setLoadBeanCache(loadBeanCache); 837 return root; 838 } 839 840 /** 841 * Set the property to use as keys for a map. 842 * <p> 843 * If no property is set then the id property is used. 844 * </p> 845 * <p> 846 * <pre>{@code 847 * 848 * // Assuming sku is unique for products... 849 * 850 * Map<String,Product> productMap = 851 * new QProduct() 852 * // use sku for keys... 853 * .setMapKey("sku") 854 * .findMap(); 855 * 856 * }</pre> 857 * 858 * @param mapKey the property to use as keys for a map. 859 */ 860 public R setMapKey(String mapKey) { 861 query.setMapKey(mapKey); 862 return root; 863 } 864 865 /** 866 * Specify the PersistenceContextScope to use for this query. 867 * <p> 868 * When this is not set the 'default' configured on {@link io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)} 869 * is used - this value defaults to {@link io.ebean.PersistenceContextScope#TRANSACTION}. 870 * <p> 871 * Note that the same persistence Context is used for subsequent lazy loading and query join queries. 872 * <p> 873 * Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for 874 * queries executed as #findIterate, #findEach, #findEachWhile. 875 * 876 * @param scope The scope to use for this query and subsequent lazy loading. 877 */ 878 public R setPersistenceContextScope(PersistenceContextScope scope) { 879 query.setPersistenceContextScope(scope); 880 return root; 881 } 882 883 /** 884 * Set RawSql to use for this query. 885 */ 886 public R setRawSql(RawSql rawSql) { 887 query.setRawSql(rawSql); 888 return root; 889 } 890 891 /** 892 * When set to true when you want the returned beans to be read only. 893 */ 894 public R setReadOnly(boolean readOnly) { 895 query.setReadOnly(readOnly); 896 return root; 897 } 898 899 /** 900 * Set this to true to use the bean cache. 901 * <p> 902 * If the query result is in cache then by default this same instance is 903 * returned. In this sense it should be treated as a read only object graph. 904 * </p> 905 */ 906 public R setUseCache(boolean useCache) { 907 query.setUseCache(useCache); 908 return root; 909 } 910 911 912 /** 913 * Set the mode to use the bean cache when executing this query. 914 * <p> 915 * By default "find by id" and "find by natural key" will use the bean cache 916 * when bean caching is enabled. Setting this to false means that the query 917 * will not use the bean cache and instead hit the database. 918 * </p> 919 * <p> 920 * By default findList() with natural keys will not use the bean cache. In that 921 * case we need to explicitly use the bean cache. 922 * </p> 923 */ 924 public R setBeanCacheMode(CacheMode beanCacheMode) { 925 query.setBeanCacheMode(beanCacheMode); 926 return root; 927 } 928 929 /** 930 * Set to true if this query should execute against the doc store. 931 * <p> 932 * When setting this you may also consider disabling lazy loading. 933 * </p> 934 */ 935 public R setUseDocStore(boolean useDocStore) { 936 query.setUseDocStore(useDocStore); 937 return root; 938 } 939 940 /** 941 * Set true if you want to disable lazy loading. 942 * <p> 943 * That is, once the object graph is returned further lazy loading is disabled. 944 * </p> 945 */ 946 public R setDisableLazyLoading(boolean disableLazyLoading) { 947 query.setDisableLazyLoading(disableLazyLoading); 948 return root; 949 } 950 951 /** 952 * Disable read auditing for this query. 953 * <p> 954 * This is intended to be used when the query is not a user initiated query and instead 955 * part of the internal processing in an application to load a cache or document store etc. 956 * In these cases we don't want the query to be part of read auditing. 957 * </p> 958 */ 959 public R setDisableReadAuditing() { 960 query.setDisableReadAuditing(); 961 return root; 962 } 963 964 /** 965 * Set this to true to use the query cache. 966 */ 967 public R setUseQueryCache(boolean useCache) { 968 query.setUseQueryCache(useCache); 969 return root; 970 } 971 972 /** 973 * Set the {@link CacheMode} to use the query for executing this query. 974 */ 975 public R setUseQueryCache(CacheMode cacheMode) { 976 query.setUseQueryCache(cacheMode); 977 return root; 978 } 979 980 /** 981 * Set a timeout on this query. 982 * <p> 983 * This will typically result in a call to setQueryTimeout() on a 984 * preparedStatement. If the timeout occurs an exception will be thrown - this 985 * will be a SQLException wrapped up in a PersistenceException. 986 * </p> 987 * 988 * @param secs the query timeout limit in seconds. Zero means there is no limit. 989 */ 990 public R setTimeout(int secs) { 991 query.setTimeout(secs); 992 return root; 993 } 994 995 /** 996 * Returns the set of properties or paths that are unknown (do not map to known properties or paths). 997 * <p> 998 * Validate the query checking the where and orderBy expression paths to confirm if 999 * they represent valid properties or paths for the given bean type. 1000 * </p> 1001 */ 1002 public Set<String> validate() { 1003 return query.validate(); 1004 } 1005 1006 /** 1007 * Add raw expression with no parameters. 1008 * <p> 1009 * When properties in the clause are fully qualified as table-column names 1010 * then they are not translated. logical property name names (not fully 1011 * qualified) will still be translated to their physical name. 1012 * </p> 1013 * <p> 1014 * <pre>{@code 1015 * 1016 * raw("orderQty < shipQty") 1017 * 1018 * }</pre> 1019 * 1020 * <h4>Subquery example:</h4> 1021 * <pre>{@code 1022 * 1023 * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds) 1024 * 1025 * }</pre> 1026 */ 1027 public R raw(String rawExpression) { 1028 peekExprList().raw(rawExpression); 1029 return root; 1030 } 1031 1032 /** 1033 * Add raw expression with an array of parameters. 1034 * <p> 1035 * The raw expression should contain the same number of ? as there are 1036 * parameters. 1037 * </p> 1038 * <p> 1039 * When properties in the clause are fully qualified as table-column names 1040 * then they are not translated. logical property name names (not fully 1041 * qualified) will still be translated to their physical name. 1042 * </p> 1043 */ 1044 public R raw(String rawExpression, Object... bindValues) { 1045 peekExprList().raw(rawExpression, bindValues); 1046 return root; 1047 } 1048 1049 /** 1050 * Only add the raw expression if the values is not null or empty. 1051 * <p> 1052 * This is a pure convenience expression to make it nicer to deal with the pattern where we use 1053 * raw() expression with a subquery and only want to add the subquery predicate when the collection 1054 * of values is not empty. 1055 * </p> 1056 * <h3>Without inOrEmpty()</h3> 1057 * <pre>{@code 1058 * 1059 * QCustomer query = new QCustomer() // add some predicates 1060 * .status.equalTo(Status.NEW); 1061 * 1062 * // common pattern - we can use rawOrEmpty() instead 1063 * if (orderIds != null && !orderIds.isEmpty()) { 1064 * query.raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds); 1065 * } 1066 * 1067 * query.findList(); 1068 * 1069 * }</pre> 1070 * 1071 * <h3>Using rawOrEmpty()</h3> 1072 * Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion" 1073 * for each element in the collection. 1074 * 1075 * <pre>{@code 1076 * 1077 * new QCustomer() 1078 * .status.equalTo(Status.NEW) 1079 * // only add the expression if orderIds is not empty 1080 * .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds); 1081 * .findList(); 1082 * 1083 * }</pre> 1084 * 1085 * <h3>Postgres ANY</h3> 1086 * With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding 1087 * rather than <code>IN</code>. 1088 * 1089 * <pre>{@code 1090 * 1091 * new QCustomer() 1092 * .status.equalTo(Status.NEW) 1093 * .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds); 1094 * .findList(); 1095 * 1096 * }</pre> 1097 * <p> 1098 * Note that we need to cast the Postgres array for UUID types like: 1099 * </p> 1100 * <pre>{@code 1101 * 1102 * " ... = any(?::uuid[])" 1103 * 1104 * }</pre> 1105 * 1106 * @param raw The raw expression that is typically a subquery 1107 * @param values The values which is typically a list or set of id values. 1108 */ 1109 public R rawOrEmpty(String raw, Collection<?> values) { 1110 peekExprList().rawOrEmpty(raw, values); 1111 return root; 1112 } 1113 1114 /** 1115 * Add raw expression with a single parameter. 1116 * <p> 1117 * The raw expression should contain a single ? at the location of the 1118 * parameter. 1119 * </p> 1120 * <p> 1121 * When properties in the clause are fully qualified as table-column names 1122 * then they are not translated. logical property name names (not fully 1123 * qualified) will still be translated to their physical name. 1124 * </p> 1125 * <p> 1126 * <h4>Example:</h4> 1127 * <pre>{@code 1128 * 1129 * // use a database function 1130 * raw("add_days(orderDate, 10) < ?", someDate) 1131 * 1132 * }</pre> 1133 * 1134 * <h4>Subquery example:</h4> 1135 * <pre>{@code 1136 * 1137 * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds) 1138 * 1139 * }</pre> 1140 */ 1141 public R raw(String rawExpression, Object bindValue) { 1142 peekExprList().raw(rawExpression, bindValue); 1143 return root; 1144 } 1145 1146 /** 1147 * Deprecated migrate to order(). 1148 */ 1149 @Deprecated 1150 public R orderBy() { 1151 // Yes this does not actually do anything! We include it because style wise it makes 1152 // the query nicer to read and suggests that order by definitions are added after this 1153 return root; 1154 } 1155 1156 /** 1157 * Marker that can be used to indicate that the order by clause is defined after this. 1158 * <p> 1159 * <h2>Example: order by customer name, order date</h2> 1160 * <pre>{@code 1161 * List<Order> orders = 1162 * new QOrder() 1163 * .customer.name.ilike("rob") 1164 * .order() 1165 * .customer.name.asc() 1166 * .orderDate.asc() 1167 * .findList(); 1168 * 1169 * }</pre> 1170 */ 1171 public R order() { 1172 // Yes this does not actually do anything! We include it because style wise it makes 1173 // the query nicer to read and suggests that order by definitions are added after this 1174 return root; 1175 } 1176 1177 1178 /** 1179 * Deprecated migrate to {@link #order(String)}. 1180 */ 1181 @Deprecated 1182 public R orderBy(String orderByClause) { 1183 query.orderBy(orderByClause); 1184 return root; 1185 } 1186 1187 /** 1188 * Set the full raw order by clause replacing the existing order by clause if there is one. 1189 * <p> 1190 * This follows SQL syntax using commas between each property with the 1191 * optional asc and desc keywords representing ascending and descending order 1192 * respectively. 1193 */ 1194 public R order(String orderByClause) { 1195 query.order(orderByClause); 1196 return root; 1197 } 1198 1199 /** 1200 * Begin a list of expressions added by 'OR'. 1201 * <p> 1202 * Use endOr() or endJunction() to stop added to OR and 'pop' to the parent expression list. 1203 * </p> 1204 * <p> 1205 * <h2>Example</h2> 1206 * <p> 1207 * This example uses an 'OR' expression list with an inner 'AND' expression list. 1208 * </p> 1209 * <pre>{@code 1210 * 1211 * List<Customer> customers = 1212 * new QCustomer() 1213 * .status.equalTo(Customer.Status.GOOD) 1214 * .or() 1215 * .id.greaterThan(1000) 1216 * .and() 1217 * .name.startsWith("super") 1218 * .registered.after(fiveDaysAgo) 1219 * .endAnd() 1220 * .endOr() 1221 * .orderBy().id.desc() 1222 * .findList(); 1223 * 1224 * }</pre> 1225 * <h2>Resulting SQL where clause</h2> 1226 * <pre>{@code sql 1227 * 1228 * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) 1229 * order by t0.id desc; 1230 * 1231 * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015) 1232 * 1233 * }</pre> 1234 */ 1235 public R or() { 1236 pushExprList(peekExprList().or()); 1237 return root; 1238 } 1239 1240 /** 1241 * Begin a list of expressions added by 'AND'. 1242 * <p> 1243 * Use endAnd() or endJunction() to stop added to AND and 'pop' to the parent expression list. 1244 * </p> 1245 * <p> 1246 * Note that typically the AND expression is only used inside an outer 'OR' expression. 1247 * This is because the top level expression list defaults to an 'AND' expression list. 1248 * </p> 1249 * <h2>Example</h2> 1250 * <p> 1251 * This example uses an 'OR' expression list with an inner 'AND' expression list. 1252 * </p> 1253 * <pre>{@code 1254 * 1255 * List<Customer> customers = 1256 * new QCustomer() 1257 * .status.equalTo(Customer.Status.GOOD) 1258 * .or() // OUTER 'OR' 1259 * .id.greaterThan(1000) 1260 * .and() // NESTED 'AND' expression list 1261 * .name.startsWith("super") 1262 * .registered.after(fiveDaysAgo) 1263 * .endAnd() 1264 * .endOr() 1265 * .orderBy().id.desc() 1266 * .findList(); 1267 * 1268 * }</pre> 1269 * <h2>Resulting SQL where clause</h2> 1270 * <pre>{@code sql 1271 * 1272 * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) 1273 * order by t0.id desc; 1274 * 1275 * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015) 1276 * 1277 * }</pre> 1278 */ 1279 public R and() { 1280 pushExprList(peekExprList().and()); 1281 return root; 1282 } 1283 1284 /** 1285 * Begin a list of expressions added by NOT. 1286 * <p> 1287 * Use endNot() or endJunction() to stop added to NOT and 'pop' to the parent expression list. 1288 * </p> 1289 */ 1290 public R not() { 1291 pushExprList(peekExprList().not()); 1292 return root; 1293 } 1294 1295 /** 1296 * Begin a list of expressions added by MUST. 1297 * <p> 1298 * This automatically makes this query a document store query. 1299 * </p> 1300 * <p> 1301 * Use endJunction() to stop added to MUST and 'pop' to the parent expression list. 1302 * </p> 1303 */ 1304 public R must() { 1305 pushExprList(peekExprList().must()); 1306 return root; 1307 } 1308 1309 /** 1310 * Begin a list of expressions added by MUST NOT. 1311 * <p> 1312 * This automatically makes this query a document store query. 1313 * </p> 1314 * <p> 1315 * Use endJunction() to stop added to MUST NOT and 'pop' to the parent expression list. 1316 * </p> 1317 */ 1318 public R mustNot() { 1319 return pushExprList(peekExprList().mustNot()); 1320 } 1321 1322 /** 1323 * Begin a list of expressions added by SHOULD. 1324 * <p> 1325 * This automatically makes this query a document store query. 1326 * </p> 1327 * <p> 1328 * Use endJunction() to stop added to SHOULD and 'pop' to the parent expression list. 1329 * </p> 1330 */ 1331 public R should() { 1332 return pushExprList(peekExprList().should()); 1333 } 1334 1335 /** 1336 * End a list of expressions added by 'OR'. 1337 */ 1338 public R endJunction() { 1339 if (textMode) { 1340 textStack.pop(); 1341 } else { 1342 whereStack.pop(); 1343 } 1344 return root; 1345 } 1346 1347 /** 1348 * End OR junction - synonym for endJunction(). 1349 */ 1350 public R endOr() { 1351 return endJunction(); 1352 } 1353 1354 /** 1355 * End AND junction - synonym for endJunction(). 1356 */ 1357 public R endAnd() { 1358 return endJunction(); 1359 } 1360 1361 /** 1362 * End NOT junction - synonym for endJunction(). 1363 */ 1364 public R endNot() { 1365 return endJunction(); 1366 } 1367 1368 /** 1369 * Push the expression list onto the appropriate stack. 1370 */ 1371 private R pushExprList(ExpressionList<T> list) { 1372 if (textMode) { 1373 textStack.push(list); 1374 } else { 1375 whereStack.push(list); 1376 } 1377 return root; 1378 } 1379 1380 /** 1381 * Add expression after this to the WHERE expression list. 1382 * <p> 1383 * For queries against the normal database (not the doc store) this has no effect. 1384 * </p> 1385 * <p> 1386 * This is intended for use with Document Store / ElasticSearch where expressions can be put into either 1387 * the "query" section or the "filter" section of the query. Full text expressions like MATCH are in the 1388 * "query" section but many expression can be in either - expressions after the where() are put into the 1389 * "filter" section which means that they don't add to the relevance and are also cache-able. 1390 * </p> 1391 */ 1392 public R where() { 1393 textMode = false; 1394 return root; 1395 } 1396 1397 /** 1398 * Begin added expressions to the 'Text' expression list. 1399 * <p> 1400 * This automatically makes the query a document store query. 1401 * </p> 1402 * <p> 1403 * For ElasticSearch expressions added to 'text' go into the ElasticSearch 'query context' 1404 * and expressions added to 'where' go into the ElasticSearch 'filter context'. 1405 * </p> 1406 */ 1407 public R text() { 1408 textMode = true; 1409 return root; 1410 } 1411 1412 /** 1413 * Add a Text Multi-match expression (document store only). 1414 * <p> 1415 * This automatically makes the query a document store query. 1416 * </p> 1417 */ 1418 public R multiMatch(String query, MultiMatch multiMatch) { 1419 peekExprList().multiMatch(query, multiMatch); 1420 return root; 1421 } 1422 1423 /** 1424 * Add a Text Multi-match expression (document store only). 1425 * <p> 1426 * This automatically makes the query a document store query. 1427 * </p> 1428 */ 1429 public R multiMatch(String query, String... properties) { 1430 peekExprList().multiMatch(query, properties); 1431 return root; 1432 } 1433 1434 /** 1435 * Add a Text common terms expression (document store only). 1436 * <p> 1437 * This automatically makes the query a document store query. 1438 * </p> 1439 */ 1440 public R textCommonTerms(String query, TextCommonTerms options) { 1441 peekExprList().textCommonTerms(query, options); 1442 return root; 1443 } 1444 1445 /** 1446 * Add a Text simple expression (document store only). 1447 * <p> 1448 * This automatically makes the query a document store query. 1449 * </p> 1450 */ 1451 public R textSimple(String query, TextSimple options) { 1452 peekExprList().textSimple(query, options); 1453 return root; 1454 } 1455 1456 /** 1457 * Add a Text query string expression (document store only). 1458 * <p> 1459 * This automatically makes the query a document store query. 1460 * </p> 1461 */ 1462 public R textQueryString(String query, TextQueryString options) { 1463 peekExprList().textQueryString(query, options); 1464 return root; 1465 } 1466 1467 /** 1468 * Execute the query using the given transaction. 1469 */ 1470 public R usingTransaction(Transaction transaction) { 1471 query.usingTransaction(transaction); 1472 return root; 1473 } 1474 1475 /** 1476 * Execute the query using the given connection. 1477 */ 1478 public R usingConnection(Connection connection) { 1479 query.usingConnection(connection); 1480 return root; 1481 } 1482 1483 /** 1484 * Execute the query returning true if a row is found. 1485 * <p> 1486 * The query is executed using max rows of 1 and will only select the id property. 1487 * This method is really just a convenient way to optimise a query to perform a 1488 * 'does a row exist in the db' check. 1489 * </p> 1490 * 1491 * <h2>Example using a query bean:</h2> 1492 * <pre>{@code 1493 * 1494 * boolean userExists = 1495 * new QContact() 1496 * .email.equalTo("rob@foo.com") 1497 * .exists(); 1498 * 1499 * }</pre> 1500 * 1501 * <h2>Example:</h2> 1502 * <pre>{@code 1503 * 1504 * boolean userExists = query() 1505 * .where().eq("email", "rob@foo.com") 1506 * .exists(); 1507 * 1508 * }</pre> 1509 * 1510 * @return True if the query finds a matching row in the database 1511 */ 1512 public boolean exists() { 1513 return query.exists(); 1514 } 1515 1516 /** 1517 * Execute the query returning either a single bean or null (if no matching 1518 * bean is found). 1519 * <p> 1520 * If more than 1 row is found for this query then a PersistenceException is 1521 * thrown. 1522 * </p> 1523 * <p> 1524 * This is useful when your predicates dictate that your query should only 1525 * return 0 or 1 results. 1526 * </p> 1527 * <p> 1528 * <pre>{@code 1529 * 1530 * // assuming the sku of products is unique... 1531 * Product product = 1532 * new QProduct() 1533 * .sku.equalTo("aa113") 1534 * .findOne(); 1535 * ... 1536 * }</pre> 1537 * <p> 1538 * <p> 1539 * It is also useful with finding objects by their id when you want to specify 1540 * further join information to optimise the query. 1541 * </p> 1542 * <p> 1543 * <pre>{@code 1544 * 1545 * // Fetch order 42 and additionally fetch join its order details... 1546 * Order order = 1547 * new QOrder() 1548 * .fetch("details") // eagerly load the order details 1549 * .id.equalTo(42) 1550 * .findOne(); 1551 * 1552 * // the order details were eagerly loaded 1553 * List<OrderDetail> details = order.getDetails(); 1554 * ... 1555 * }</pre> 1556 */ 1557 @Nullable 1558 public T findOne() { 1559 return query.findOne(); 1560 } 1561 1562 /** 1563 * Execute the query returning an optional bean. 1564 */ 1565 @Nonnull 1566 public Optional<T> findOneOrEmpty() { 1567 return query.findOneOrEmpty(); 1568 } 1569 1570 /** 1571 * Execute the query returning the list of objects. 1572 * <p> 1573 * This query will execute against the EbeanServer that was used to create it. 1574 * </p> 1575 * <p> 1576 * <pre>{@code 1577 * 1578 * List<Customer> customers = 1579 * new QCustomer() 1580 * .name.ilike("rob%") 1581 * .findList(); 1582 * 1583 * }</pre> 1584 * 1585 * @see Query#findList() 1586 */ 1587 @Nonnull 1588 public List<T> findList() { 1589 return query.findList(); 1590 } 1591 1592 /** 1593 * Execute the query returning the result as a Stream. 1594 * <p> 1595 * Note that this will hold all resulting beans in memory using a single 1596 * persistence context. Use findLargeStream() for queries that expect to 1597 * return a large number of results. 1598 * </p> 1599 * <pre>{@code 1600 * 1601 * // use try with resources to ensure Stream is closed 1602 * 1603 * try (Stream<Customer> stream = query.findStream()) { 1604 * stream 1605 * .map(...) 1606 * .collect(...); 1607 * } 1608 * 1609 * }</pre> 1610 */ 1611 @Nonnull 1612 public Stream<T> findSteam() { 1613 return query.findStream(); 1614 } 1615 1616 /** 1617 * Execute the query returning the result as a Stream. 1618 * <p> 1619 * Note that this uses multiple persistence contexts such that we can use 1620 * it with a large number of results. 1621 * </p> 1622 * <pre>{@code 1623 * 1624 * // use try with resources to ensure Stream is closed 1625 * 1626 * try (Stream<Customer> stream = query.findLargeStream()) { 1627 * stream 1628 * .map(...) 1629 * .collect(...); 1630 * } 1631 * 1632 * }</pre> 1633 */ 1634 public Stream<T> findLargeStream() { 1635 return query.findLargeStream(); 1636 } 1637 1638 /** 1639 * Execute the query returning the set of objects. 1640 * <p> 1641 * This query will execute against the EbeanServer that was used to create it. 1642 * </p> 1643 * <p> 1644 * <pre>{@code 1645 * 1646 * Set<Customer> customers = 1647 * new QCustomer() 1648 * .name.ilike("rob%") 1649 * .findSet(); 1650 * 1651 * }</pre> 1652 * 1653 * @see Query#findSet() 1654 */ 1655 @Nonnull 1656 public Set<T> findSet() { 1657 return query.findSet(); 1658 } 1659 1660 /** 1661 * Execute the query returning the list of Id's. 1662 * <p> 1663 * This query will execute against the EbeanServer that was used to create it. 1664 * </p> 1665 * 1666 * @see Query#findIds() 1667 */ 1668 @Nonnull 1669 public <A> List<A> findIds() { 1670 return query.findIds(); 1671 } 1672 1673 /** 1674 * Execute the query returning a map of the objects. 1675 * <p> 1676 * This query will execute against the EbeanServer that was used to create it. 1677 * </p> 1678 * <p> 1679 * You can use setMapKey() or asMapKey() to specify the property to be used as keys 1680 * on the map. If one is not specified then the id property is used. 1681 * </p> 1682 * <p> 1683 * <pre>{@code 1684 * 1685 * Map<String, Product> map = 1686 * new QProduct() 1687 * .sku.asMapKey() 1688 * .findMap(); 1689 * 1690 * }</pre> 1691 * 1692 * @see Query#findMap() 1693 */ 1694 @Nonnull 1695 public <K> Map<K, T> findMap() { 1696 return query.findMap(); 1697 } 1698 1699 /** 1700 * Execute the query iterating over the results. 1701 * <p> 1702 * Note that findIterate (and findEach and findEachWhile) uses a "per graph" 1703 * persistence context scope and adjusts jdbc fetch buffer size for large 1704 * queries. As such it is better to use findList for small queries. 1705 * </p> 1706 * <p> 1707 * Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()} 1708 * when you have finished iterating the results (typically in a finally block). 1709 * </p> 1710 * <p> 1711 * findEach() and findEachWhile() are preferred to findIterate() as they ensure 1712 * the jdbc statement and resultSet are closed at the end of the iteration. 1713 * </p> 1714 * <p> 1715 * This query will execute against the EbeanServer that was used to create it. 1716 * </p> 1717 * <pre>{@code 1718 * 1719 * Query<Customer> query = 1720 * new QCustomer() 1721 * .status.equalTo(Customer.Status.NEW) 1722 * .order() 1723 * id.asc() 1724 * .query(); 1725 * 1726 * try (QueryIterator<Customer> it = query.findIterate()) { 1727 * while (it.hasNext()) { 1728 * Customer customer = it.next(); 1729 * // do something with customer ... 1730 * } 1731 * } 1732 * 1733 * }</pre> 1734 */ 1735 @Nonnull 1736 public QueryIterator<T> findIterate() { 1737 return query.findIterate(); 1738 } 1739 1740 /** 1741 * Execute the query returning a list of values for a single property. 1742 * <p> 1743 * <h3>Example</h3> 1744 * <pre>{@code 1745 * 1746 * List<String> names = 1747 * new QCustomer() 1748 * .setDistinct(true) 1749 * .select(name) 1750 * .findSingleAttributeList(); 1751 * 1752 * }</pre> 1753 * 1754 * @return the list of values for the selected property 1755 */ 1756 @Nonnull 1757 public <A> List<A> findSingleAttributeList() { 1758 return query.findSingleAttributeList(); 1759 } 1760 1761 /** 1762 * Execute the query returning a single value for a single property. 1763 * <p> 1764 * <h3>Example</h3> 1765 * <pre>{@code 1766 * 1767 * LocalDate maxDate = 1768 * new QCustomer() 1769 * .select("max(startDate)") 1770 * .findSingleAttribute(); 1771 * 1772 * }</pre> 1773 * 1774 * @return the list of values for the selected property 1775 */ 1776 public <A> A findSingleAttribute() { 1777 return query.findSingleAttribute(); 1778 } 1779 1780 /** 1781 * Execute the query processing the beans one at a time. 1782 * <p> 1783 * This method is appropriate to process very large query results as the 1784 * beans are consumed one at a time and do not need to be held in memory 1785 * (unlike #findList #findSet etc) 1786 * </p> 1787 * <p> 1788 * Note that internally Ebean can inform the JDBC driver that it is expecting larger 1789 * resultSet and specifically for MySQL this hint is required to stop it's JDBC driver 1790 * from buffering the entire resultSet. As such, for smaller resultSets findList() is 1791 * generally preferable. 1792 * </p> 1793 * <p> 1794 * Compared with #findEachWhile this will always process all the beans where as 1795 * #findEachWhile provides a way to stop processing the query result early before 1796 * all the beans have been read. 1797 * </p> 1798 * <p> 1799 * This method is functionally equivalent to findIterate() but instead of using an 1800 * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use 1801 * with Java8 closures. 1802 * </p> 1803 * <p> 1804 * <pre>{@code 1805 * 1806 * new QCustomer() 1807 * .status.equalTo(Status.NEW) 1808 * .orderBy().id.asc() 1809 * .findEach((Customer customer) -> { 1810 * 1811 * // do something with customer 1812 * System.out.println("-- visit " + customer); 1813 * }); 1814 * 1815 * }</pre> 1816 * 1817 * @param consumer the consumer used to process the queried beans. 1818 */ 1819 public void findEach(Consumer<T> consumer) { 1820 query.findEach(consumer); 1821 } 1822 1823 /** 1824 * Execute the query using callbacks to a visitor to process the resulting 1825 * beans one at a time. 1826 * <p> 1827 * This method is functionally equivalent to findIterate() but instead of using an 1828 * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use 1829 * with Java8 closures. 1830 * </p> 1831 * <p> 1832 * <p> 1833 * <pre>{@code 1834 * 1835 * new QCustomer() 1836 * .status.equalTo(Status.NEW) 1837 * .order().id.asc() 1838 * .findEachWhile((Customer customer) -> { 1839 * 1840 * // do something with customer 1841 * System.out.println("-- visit " + customer); 1842 * 1843 * // return true to continue processing or false to stop 1844 * return (customer.getId() < 40); 1845 * }); 1846 * 1847 * }</pre> 1848 * 1849 * @param consumer the consumer used to process the queried beans. 1850 */ 1851 public void findEachWhile(Predicate<T> consumer) { 1852 query.findEachWhile(consumer); 1853 } 1854 1855 /** 1856 * Return versions of a @History entity bean. 1857 * <p> 1858 * Generally this query is expected to be a find by id or unique predicates query. 1859 * It will execute the query against the history returning the versions of the bean. 1860 * </p> 1861 */ 1862 @Nonnull 1863 public List<Version<T>> findVersions() { 1864 return query.findVersions(); 1865 } 1866 1867 /** 1868 * Return versions of a @History entity bean between a start and end timestamp. 1869 * <p> 1870 * Generally this query is expected to be a find by id or unique predicates query. 1871 * It will execute the query against the history returning the versions of the bean. 1872 * </p> 1873 */ 1874 @Nonnull 1875 public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) { 1876 return query.findVersionsBetween(start, end); 1877 } 1878 1879 /** 1880 * Return the count of entities this query should return. 1881 * <p> 1882 * This is the number of 'top level' or 'root level' entities. 1883 * </p> 1884 */ 1885 @Nonnull 1886 public int findCount() { 1887 return query.findCount(); 1888 } 1889 1890 /** 1891 * Execute find row count query in a background thread. 1892 * <p> 1893 * This returns a Future object which can be used to cancel, check the 1894 * execution status (isDone etc) and get the value (with or without a 1895 * timeout). 1896 * </p> 1897 * 1898 * @return a Future object for the row count query 1899 */ 1900 @Nonnull 1901 public FutureRowCount<T> findFutureCount() { 1902 return query.findFutureCount(); 1903 } 1904 1905 /** 1906 * Execute find Id's query in a background thread. 1907 * <p> 1908 * This returns a Future object which can be used to cancel, check the 1909 * execution status (isDone etc) and get the value (with or without a 1910 * timeout). 1911 * </p> 1912 * 1913 * @return a Future object for the list of Id's 1914 */ 1915 @Nonnull 1916 public FutureIds<T> findFutureIds() { 1917 return query.findFutureIds(); 1918 } 1919 1920 /** 1921 * Execute find list query in a background thread. 1922 * <p> 1923 * This query will execute in it's own PersistenceContext and using its own transaction. 1924 * What that means is that it will not share any bean instances with other queries. 1925 * </p> 1926 * 1927 * @return a Future object for the list result of the query 1928 */ 1929 @Nonnull 1930 public FutureList<T> findFutureList() { 1931 return query.findFutureList(); 1932 } 1933 1934 /** 1935 * Return a PagedList for this query using firstRow and maxRows. 1936 * <p> 1937 * The benefit of using this over findList() is that it provides functionality to get the 1938 * total row count etc. 1939 * </p> 1940 * <p> 1941 * If maxRows is not set on the query prior to calling findPagedList() then a 1942 * PersistenceException is thrown. 1943 * </p> 1944 * <p> 1945 * <pre>{@code 1946 * 1947 * PagedList<Order> pagedList = 1948 * new QOrder() 1949 * .setFirstRow(50) 1950 * .setMaxRows(20) 1951 * .findPagedList(); 1952 * 1953 * // fetch the total row count in the background 1954 * pagedList.loadRowCount(); 1955 * 1956 * List<Order> orders = pagedList.getList(); 1957 * int totalRowCount = pagedList.getTotalRowCount(); 1958 * 1959 * }</pre> 1960 * 1961 * @return The PagedList 1962 */ 1963 @Nonnull 1964 public PagedList<T> findPagedList() { 1965 return query.findPagedList(); 1966 } 1967 1968 /** 1969 * Execute as a delete query deleting the 'root level' beans that match the predicates 1970 * in the query. 1971 * <p> 1972 * Note that if the query includes joins then the generated delete statement may not be 1973 * optimal depending on the database platform. 1974 * </p> 1975 * 1976 * @return the number of beans/rows that were deleted. 1977 */ 1978 public int delete() { 1979 return query.delete(); 1980 } 1981 1982 /** 1983 * Return the sql that was generated for executing this query. 1984 * <p> 1985 * This is only available after the query has been executed and provided only 1986 * for informational purposes. 1987 * </p> 1988 */ 1989 public String getGeneratedSql() { 1990 return query.getGeneratedSql(); 1991 } 1992 1993 /** 1994 * Return the type of beans being queried. 1995 */ 1996 @Nonnull 1997 public Class<T> getBeanType() { 1998 return query.getBeanType(); 1999 } 2000 2001 /** 2002 * Return the expression list that has been built for this query. 2003 */ 2004 @Nonnull 2005 public ExpressionList<T> getExpressionList() { 2006 return query.where(); 2007 } 2008 2009 /** 2010 * Start adding expressions to the having clause when using @Aggregation properties. 2011 * 2012 * <pre>{@code 2013 * 2014 * new QMachineUse() 2015 * // where ... 2016 * .date.inRange(fromDate, toDate) 2017 * 2018 * .having() 2019 * .sumHours.greaterThan(1) 2020 * .findList() 2021 * 2022 * // The sumHours property uses @Aggregation 2023 * // e.g. @Aggregation("sum(hours)") 2024 * 2025 * }</pre> 2026 */ 2027 public R having() { 2028 if (whereStack == null) { 2029 whereStack = new ArrayStack<>(); 2030 } 2031 // effectively putting having expression list onto stack 2032 // such that expression now add to the having clause 2033 whereStack.push(query.having()); 2034 return root; 2035 } 2036 2037 /** 2038 * Return the underlying having clause to typically when using dynamic aggregation formula. 2039 * <p> 2040 * Note that after this we no longer have the query bean so typically we use this right 2041 * at the end of the query. 2042 * </p> 2043 * 2044 * <pre>{@code 2045 * 2046 * // sum(distanceKms) ... is a "dynamic formula" 2047 * // so we use havingClause() for it like: 2048 * 2049 * List<MachineUse> machineUse = 2050 * 2051 * new QMachineUse() 2052 * .select("machine, sum(fuelUsed), sum(distanceKms)") 2053 * 2054 * // where ... 2055 * .date.greaterThan(LocalDate.now().minusDays(7)) 2056 * 2057 * .havingClause() 2058 * .gt("sum(distanceKms)", 2) 2059 * .findList(); 2060 * 2061 * }</pre> 2062 */ 2063 public ExpressionList<T> havingClause() { 2064 return query.having(); 2065 } 2066 2067 /** 2068 * Return the current expression list that expressions should be added to. 2069 */ 2070 protected ExpressionList<T> peekExprList() { 2071 2072 if (textMode) { 2073 // return the current text expression list 2074 return _peekText(); 2075 } 2076 2077 if (whereStack == null) { 2078 whereStack = new ArrayStack<>(); 2079 whereStack.push(query.where()); 2080 } 2081 // return the current expression list 2082 return whereStack.peek(); 2083 } 2084 2085 protected ExpressionList<T> _peekText() { 2086 if (textStack == null) { 2087 textStack = new ArrayStack<>(); 2088 // empty so push on the queries base expression list 2089 textStack.push(query.text()); 2090 } 2091 // return the current expression list 2092 return textStack.peek(); 2093 } 2094}