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 * Marker that can be used to indicate that the order by clause is defined after this. 1148 * <p> 1149 * <h2>Example: order by customer name, order date</h2> 1150 * <pre>{@code 1151 * List<Order> orders = 1152 * new QOrder() 1153 * .customer.name.ilike("rob") 1154 * .orderBy() 1155 * .customer.name.asc() 1156 * .orderDate.asc() 1157 * .findList(); 1158 * 1159 * }</pre> 1160 */ 1161 public R orderBy() { 1162 // Yes this does not actually do anything! We include it because style wise it makes 1163 // the query nicer to read and suggests that order by definitions are added after this 1164 return root; 1165 } 1166 1167 /** 1168 * Marker that can be used to indicate that the order by clause is defined after this. 1169 * <p> 1170 * <h2>Example: order by customer name, order date</h2> 1171 * <pre>{@code 1172 * List<Order> orders = 1173 * new QOrder() 1174 * .customer.name.ilike("rob") 1175 * .orderBy() 1176 * .customer.name.asc() 1177 * .orderDate.asc() 1178 * .findList(); 1179 * 1180 * }</pre> 1181 */ 1182 public R order() { 1183 // Yes this does not actually do anything! We include it because style wise it makes 1184 // the query nicer to read and suggests that order by definitions are added after this 1185 return root; 1186 } 1187 1188 /** 1189 * Set the full raw order by clause replacing the existing order by clause if there is one. 1190 * <p> 1191 * This follows SQL syntax using commas between each property with the 1192 * optional asc and desc keywords representing ascending and descending order 1193 * respectively. 1194 */ 1195 public R orderBy(String orderByClause) { 1196 query.orderBy(orderByClause); 1197 return root; 1198 } 1199 1200 /** 1201 * Set the full raw order by clause replacing the existing order by clause if there is one. 1202 * <p> 1203 * This follows SQL syntax using commas between each property with the 1204 * optional asc and desc keywords representing ascending and descending order 1205 * respectively. 1206 */ 1207 public R order(String orderByClause) { 1208 query.order(orderByClause); 1209 return root; 1210 } 1211 1212 /** 1213 * Begin a list of expressions added by 'OR'. 1214 * <p> 1215 * Use endOr() or endJunction() to stop added to OR and 'pop' to the parent expression list. 1216 * </p> 1217 * <p> 1218 * <h2>Example</h2> 1219 * <p> 1220 * This example uses an 'OR' expression list with an inner 'AND' expression list. 1221 * </p> 1222 * <pre>{@code 1223 * 1224 * List<Customer> customers = 1225 * new QCustomer() 1226 * .status.equalTo(Customer.Status.GOOD) 1227 * .or() 1228 * .id.greaterThan(1000) 1229 * .and() 1230 * .name.startsWith("super") 1231 * .registered.after(fiveDaysAgo) 1232 * .endAnd() 1233 * .endOr() 1234 * .orderBy().id.desc() 1235 * .findList(); 1236 * 1237 * }</pre> 1238 * <h2>Resulting SQL where clause</h2> 1239 * <pre>{@code sql 1240 * 1241 * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) 1242 * order by t0.id desc; 1243 * 1244 * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015) 1245 * 1246 * }</pre> 1247 */ 1248 public R or() { 1249 pushExprList(peekExprList().or()); 1250 return root; 1251 } 1252 1253 /** 1254 * Begin a list of expressions added by 'AND'. 1255 * <p> 1256 * Use endAnd() or endJunction() to stop added to AND and 'pop' to the parent expression list. 1257 * </p> 1258 * <p> 1259 * Note that typically the AND expression is only used inside an outer 'OR' expression. 1260 * This is because the top level expression list defaults to an 'AND' expression list. 1261 * </p> 1262 * <h2>Example</h2> 1263 * <p> 1264 * This example uses an 'OR' expression list with an inner 'AND' expression list. 1265 * </p> 1266 * <pre>{@code 1267 * 1268 * List<Customer> customers = 1269 * new QCustomer() 1270 * .status.equalTo(Customer.Status.GOOD) 1271 * .or() // OUTER 'OR' 1272 * .id.greaterThan(1000) 1273 * .and() // NESTED 'AND' expression list 1274 * .name.startsWith("super") 1275 * .registered.after(fiveDaysAgo) 1276 * .endAnd() 1277 * .endOr() 1278 * .orderBy().id.desc() 1279 * .findList(); 1280 * 1281 * }</pre> 1282 * <h2>Resulting SQL where clause</h2> 1283 * <pre>{@code sql 1284 * 1285 * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) 1286 * order by t0.id desc; 1287 * 1288 * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015) 1289 * 1290 * }</pre> 1291 */ 1292 public R and() { 1293 pushExprList(peekExprList().and()); 1294 return root; 1295 } 1296 1297 /** 1298 * Begin a list of expressions added by NOT. 1299 * <p> 1300 * Use endNot() or endJunction() to stop added to NOT and 'pop' to the parent expression list. 1301 * </p> 1302 */ 1303 public R not() { 1304 pushExprList(peekExprList().not()); 1305 return root; 1306 } 1307 1308 /** 1309 * Begin a list of expressions added by MUST. 1310 * <p> 1311 * This automatically makes this query a document store query. 1312 * </p> 1313 * <p> 1314 * Use endJunction() to stop added to MUST and 'pop' to the parent expression list. 1315 * </p> 1316 */ 1317 public R must() { 1318 pushExprList(peekExprList().must()); 1319 return root; 1320 } 1321 1322 /** 1323 * Begin a list of expressions added by MUST NOT. 1324 * <p> 1325 * This automatically makes this query a document store query. 1326 * </p> 1327 * <p> 1328 * Use endJunction() to stop added to MUST NOT and 'pop' to the parent expression list. 1329 * </p> 1330 */ 1331 public R mustNot() { 1332 return pushExprList(peekExprList().mustNot()); 1333 } 1334 1335 /** 1336 * Begin a list of expressions added by SHOULD. 1337 * <p> 1338 * This automatically makes this query a document store query. 1339 * </p> 1340 * <p> 1341 * Use endJunction() to stop added to SHOULD and 'pop' to the parent expression list. 1342 * </p> 1343 */ 1344 public R should() { 1345 return pushExprList(peekExprList().should()); 1346 } 1347 1348 /** 1349 * End a list of expressions added by 'OR'. 1350 */ 1351 public R endJunction() { 1352 if (textMode) { 1353 textStack.pop(); 1354 } else { 1355 whereStack.pop(); 1356 } 1357 return root; 1358 } 1359 1360 /** 1361 * End OR junction - synonym for endJunction(). 1362 */ 1363 public R endOr() { 1364 return endJunction(); 1365 } 1366 1367 /** 1368 * End AND junction - synonym for endJunction(). 1369 */ 1370 public R endAnd() { 1371 return endJunction(); 1372 } 1373 1374 /** 1375 * End NOT junction - synonym for endJunction(). 1376 */ 1377 public R endNot() { 1378 return endJunction(); 1379 } 1380 1381 /** 1382 * Push the expression list onto the appropriate stack. 1383 */ 1384 private R pushExprList(ExpressionList<T> list) { 1385 if (textMode) { 1386 textStack.push(list); 1387 } else { 1388 whereStack.push(list); 1389 } 1390 return root; 1391 } 1392 1393 /** 1394 * Add expression after this to the WHERE expression list. 1395 * <p> 1396 * For queries against the normal database (not the doc store) this has no effect. 1397 * </p> 1398 * <p> 1399 * This is intended for use with Document Store / ElasticSearch where expressions can be put into either 1400 * the "query" section or the "filter" section of the query. Full text expressions like MATCH are in the 1401 * "query" section but many expression can be in either - expressions after the where() are put into the 1402 * "filter" section which means that they don't add to the relevance and are also cache-able. 1403 * </p> 1404 */ 1405 public R where() { 1406 textMode = false; 1407 return root; 1408 } 1409 1410 /** 1411 * Begin added expressions to the 'Text' expression list. 1412 * <p> 1413 * This automatically makes the query a document store query. 1414 * </p> 1415 * <p> 1416 * For ElasticSearch expressions added to 'text' go into the ElasticSearch 'query context' 1417 * and expressions added to 'where' go into the ElasticSearch 'filter context'. 1418 * </p> 1419 */ 1420 public R text() { 1421 textMode = true; 1422 return root; 1423 } 1424 1425 /** 1426 * Add a Text Multi-match expression (document store only). 1427 * <p> 1428 * This automatically makes the query a document store query. 1429 * </p> 1430 */ 1431 public R multiMatch(String query, MultiMatch multiMatch) { 1432 peekExprList().multiMatch(query, multiMatch); 1433 return root; 1434 } 1435 1436 /** 1437 * Add a Text Multi-match expression (document store only). 1438 * <p> 1439 * This automatically makes the query a document store query. 1440 * </p> 1441 */ 1442 public R multiMatch(String query, String... properties) { 1443 peekExprList().multiMatch(query, properties); 1444 return root; 1445 } 1446 1447 /** 1448 * Add a Text common terms expression (document store only). 1449 * <p> 1450 * This automatically makes the query a document store query. 1451 * </p> 1452 */ 1453 public R textCommonTerms(String query, TextCommonTerms options) { 1454 peekExprList().textCommonTerms(query, options); 1455 return root; 1456 } 1457 1458 /** 1459 * Add a Text simple expression (document store only). 1460 * <p> 1461 * This automatically makes the query a document store query. 1462 * </p> 1463 */ 1464 public R textSimple(String query, TextSimple options) { 1465 peekExprList().textSimple(query, options); 1466 return root; 1467 } 1468 1469 /** 1470 * Add a Text query string expression (document store only). 1471 * <p> 1472 * This automatically makes the query a document store query. 1473 * </p> 1474 */ 1475 public R textQueryString(String query, TextQueryString options) { 1476 peekExprList().textQueryString(query, options); 1477 return root; 1478 } 1479 1480 /** 1481 * Execute the query using the given transaction. 1482 */ 1483 public R usingTransaction(Transaction transaction) { 1484 query.usingTransaction(transaction); 1485 return root; 1486 } 1487 1488 /** 1489 * Execute the query using the given connection. 1490 */ 1491 public R usingConnection(Connection connection) { 1492 query.usingConnection(connection); 1493 return root; 1494 } 1495 1496 /** 1497 * Execute the query returning true if a row is found. 1498 * <p> 1499 * The query is executed using max rows of 1 and will only select the id property. 1500 * This method is really just a convenient way to optimise a query to perform a 1501 * 'does a row exist in the db' check. 1502 * </p> 1503 * 1504 * <h2>Example using a query bean:</h2> 1505 * <pre>{@code 1506 * 1507 * boolean userExists = 1508 * new QContact() 1509 * .email.equalTo("rob@foo.com") 1510 * .exists(); 1511 * 1512 * }</pre> 1513 * 1514 * <h2>Example:</h2> 1515 * <pre>{@code 1516 * 1517 * boolean userExists = query() 1518 * .where().eq("email", "rob@foo.com") 1519 * .exists(); 1520 * 1521 * }</pre> 1522 * 1523 * @return True if the query finds a matching row in the database 1524 */ 1525 public boolean exists() { 1526 return query.exists(); 1527 } 1528 1529 /** 1530 * Execute the query returning either a single bean or null (if no matching 1531 * bean is found). 1532 * <p> 1533 * If more than 1 row is found for this query then a PersistenceException is 1534 * thrown. 1535 * </p> 1536 * <p> 1537 * This is useful when your predicates dictate that your query should only 1538 * return 0 or 1 results. 1539 * </p> 1540 * <p> 1541 * <pre>{@code 1542 * 1543 * // assuming the sku of products is unique... 1544 * Product product = 1545 * new QProduct() 1546 * .sku.equalTo("aa113") 1547 * .findOne(); 1548 * ... 1549 * }</pre> 1550 * <p> 1551 * <p> 1552 * It is also useful with finding objects by their id when you want to specify 1553 * further join information to optimise the query. 1554 * </p> 1555 * <p> 1556 * <pre>{@code 1557 * 1558 * // Fetch order 42 and additionally fetch join its order details... 1559 * Order order = 1560 * new QOrder() 1561 * .fetch("details") // eagerly load the order details 1562 * .id.equalTo(42) 1563 * .findOne(); 1564 * 1565 * // the order details were eagerly loaded 1566 * List<OrderDetail> details = order.getDetails(); 1567 * ... 1568 * }</pre> 1569 */ 1570 @Nullable 1571 public T findOne() { 1572 return query.findOne(); 1573 } 1574 1575 /** 1576 * Execute the query returning an optional bean. 1577 */ 1578 @Nonnull 1579 public Optional<T> findOneOrEmpty() { 1580 return query.findOneOrEmpty(); 1581 } 1582 1583 /** 1584 * Execute the query returning the list of objects. 1585 * <p> 1586 * This query will execute against the EbeanServer that was used to create it. 1587 * </p> 1588 * <p> 1589 * <pre>{@code 1590 * 1591 * List<Customer> customers = 1592 * new QCustomer() 1593 * .name.ilike("rob%") 1594 * .findList(); 1595 * 1596 * }</pre> 1597 * 1598 * @see Query#findList() 1599 */ 1600 @Nonnull 1601 public List<T> findList() { 1602 return query.findList(); 1603 } 1604 1605 /** 1606 * Execute the query returning the result as a Stream. 1607 * <p> 1608 * Note that this can support very large queries iterating 1609 * any number of results. To do so internally it can use 1610 * multiple persistence contexts. 1611 * </p> 1612 * <pre>{@code 1613 * 1614 * // use try with resources to ensure Stream is closed 1615 * 1616 * try (Stream<Customer> stream = query.findStream()) { 1617 * stream 1618 * .map(...) 1619 * .collect(...); 1620 * } 1621 * 1622 * }</pre> 1623 */ 1624 @Nonnull 1625 public Stream<T> findStream() { 1626 return query.findStream(); 1627 } 1628 1629 /** 1630 * Deprecated - migrate to findStream(). 1631 */ 1632 @Deprecated 1633 public Stream<T> findLargeStream() { 1634 return query.findLargeStream(); 1635 } 1636 1637 /** 1638 * Execute the query returning the set of objects. 1639 * <p> 1640 * This query will execute against the EbeanServer that was used to create it. 1641 * </p> 1642 * <p> 1643 * <pre>{@code 1644 * 1645 * Set<Customer> customers = 1646 * new QCustomer() 1647 * .name.ilike("rob%") 1648 * .findSet(); 1649 * 1650 * }</pre> 1651 * 1652 * @see Query#findSet() 1653 */ 1654 @Nonnull 1655 public Set<T> findSet() { 1656 return query.findSet(); 1657 } 1658 1659 /** 1660 * Execute the query returning the list of Id's. 1661 * <p> 1662 * This query will execute against the EbeanServer that was used to create it. 1663 * </p> 1664 * 1665 * @see Query#findIds() 1666 */ 1667 @Nonnull 1668 public <A> List<A> findIds() { 1669 return query.findIds(); 1670 } 1671 1672 /** 1673 * Execute the query returning a map of the objects. 1674 * <p> 1675 * This query will execute against the EbeanServer that was used to create it. 1676 * </p> 1677 * <p> 1678 * You can use setMapKey() or asMapKey() to specify the property to be used as keys 1679 * on the map. If one is not specified then the id property is used. 1680 * </p> 1681 * <p> 1682 * <pre>{@code 1683 * 1684 * Map<String, Product> map = 1685 * new QProduct() 1686 * .sku.asMapKey() 1687 * .findMap(); 1688 * 1689 * }</pre> 1690 * 1691 * @see Query#findMap() 1692 */ 1693 @Nonnull 1694 public <K> Map<K, T> findMap() { 1695 return query.findMap(); 1696 } 1697 1698 /** 1699 * Execute the query iterating over the results. 1700 * <p> 1701 * Note that findIterate (and findEach and findEachWhile) uses a "per graph" 1702 * persistence context scope and adjusts jdbc fetch buffer size for large 1703 * queries. As such it is better to use findList for small queries. 1704 * </p> 1705 * <p> 1706 * Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()} 1707 * when you have finished iterating the results (typically in a finally block). 1708 * </p> 1709 * <p> 1710 * findEach() and findEachWhile() are preferred to findIterate() as they ensure 1711 * the jdbc statement and resultSet are closed at the end of the iteration. 1712 * </p> 1713 * <p> 1714 * This query will execute against the EbeanServer that was used to create it. 1715 * </p> 1716 * <pre>{@code 1717 * 1718 * Query<Customer> query = 1719 * new QCustomer() 1720 * .status.equalTo(Customer.Status.NEW) 1721 * .orderBy() 1722 * id.asc() 1723 * .query(); 1724 * 1725 * try (QueryIterator<Customer> it = query.findIterate()) { 1726 * while (it.hasNext()) { 1727 * Customer customer = it.next(); 1728 * // do something with customer ... 1729 * } 1730 * } 1731 * 1732 * }</pre> 1733 */ 1734 @Nonnull 1735 public QueryIterator<T> findIterate() { 1736 return query.findIterate(); 1737 } 1738 1739 /** 1740 * Execute the query returning a list of values for a single property. 1741 * <p> 1742 * <h3>Example</h3> 1743 * <pre>{@code 1744 * 1745 * List<String> names = 1746 * new QCustomer() 1747 * .setDistinct(true) 1748 * .select(name) 1749 * .findSingleAttributeList(); 1750 * 1751 * }</pre> 1752 * 1753 * @return the list of values for the selected property 1754 */ 1755 @Nonnull 1756 public <A> List<A> findSingleAttributeList() { 1757 return query.findSingleAttributeList(); 1758 } 1759 1760 /** 1761 * Execute the query returning a single value for a single property. 1762 * <p> 1763 * <h3>Example</h3> 1764 * <pre>{@code 1765 * 1766 * LocalDate maxDate = 1767 * new QCustomer() 1768 * .select("max(startDate)") 1769 * .findSingleAttribute(); 1770 * 1771 * }</pre> 1772 * 1773 * @return the list of values for the selected property 1774 */ 1775 public <A> A findSingleAttribute() { 1776 return query.findSingleAttribute(); 1777 } 1778 1779 /** 1780 * Execute the query processing the beans one at a time. 1781 * <p> 1782 * This method is appropriate to process very large query results as the 1783 * beans are consumed one at a time and do not need to be held in memory 1784 * (unlike #findList #findSet etc) 1785 * </p> 1786 * <p> 1787 * Note that internally Ebean can inform the JDBC driver that it is expecting larger 1788 * resultSet and specifically for MySQL this hint is required to stop it's JDBC driver 1789 * from buffering the entire resultSet. As such, for smaller resultSets findList() is 1790 * generally preferable. 1791 * </p> 1792 * <p> 1793 * Compared with #findEachWhile this will always process all the beans where as 1794 * #findEachWhile provides a way to stop processing the query result early before 1795 * all the beans have been read. 1796 * </p> 1797 * <p> 1798 * This method is functionally equivalent to findIterate() but instead of using an 1799 * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use 1800 * with Java8 closures. 1801 * </p> 1802 * <p> 1803 * <pre>{@code 1804 * 1805 * new QCustomer() 1806 * .status.equalTo(Status.NEW) 1807 * .orderBy().id.asc() 1808 * .findEach((Customer customer) -> { 1809 * 1810 * // do something with customer 1811 * System.out.println("-- visit " + customer); 1812 * }); 1813 * 1814 * }</pre> 1815 * 1816 * @param consumer the consumer used to process the queried beans. 1817 */ 1818 public void findEach(Consumer<T> consumer) { 1819 query.findEach(consumer); 1820 } 1821 1822 /** 1823 * Execute the query using callbacks to a visitor to process the resulting 1824 * beans one at a time. 1825 * <p> 1826 * This method is functionally equivalent to findIterate() but instead of using an 1827 * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use 1828 * with Java8 closures. 1829 * </p> 1830 * <p> 1831 * <p> 1832 * <pre>{@code 1833 * 1834 * new QCustomer() 1835 * .status.equalTo(Status.NEW) 1836 * .orderBy().id.asc() 1837 * .findEachWhile((Customer customer) -> { 1838 * 1839 * // do something with customer 1840 * System.out.println("-- visit " + customer); 1841 * 1842 * // return true to continue processing or false to stop 1843 * return (customer.getId() < 40); 1844 * }); 1845 * 1846 * }</pre> 1847 * 1848 * @param consumer the consumer used to process the queried beans. 1849 */ 1850 public void findEachWhile(Predicate<T> consumer) { 1851 query.findEachWhile(consumer); 1852 } 1853 1854 /** 1855 * Return versions of a @History entity bean. 1856 * <p> 1857 * Generally this query is expected to be a find by id or unique predicates query. 1858 * It will execute the query against the history returning the versions of the bean. 1859 * </p> 1860 */ 1861 @Nonnull 1862 public List<Version<T>> findVersions() { 1863 return query.findVersions(); 1864 } 1865 1866 /** 1867 * Return versions of a @History entity bean between a start and end timestamp. 1868 * <p> 1869 * Generally this query is expected to be a find by id or unique predicates query. 1870 * It will execute the query against the history returning the versions of the bean. 1871 * </p> 1872 */ 1873 @Nonnull 1874 public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) { 1875 return query.findVersionsBetween(start, end); 1876 } 1877 1878 /** 1879 * Return the count of entities this query should return. 1880 * <p> 1881 * This is the number of 'top level' or 'root level' entities. 1882 * </p> 1883 */ 1884 @Nonnull 1885 public int findCount() { 1886 return query.findCount(); 1887 } 1888 1889 /** 1890 * Execute find row count query in a background thread. 1891 * <p> 1892 * This returns a Future object which can be used to cancel, check the 1893 * execution status (isDone etc) and get the value (with or without a 1894 * timeout). 1895 * </p> 1896 * 1897 * @return a Future object for the row count query 1898 */ 1899 @Nonnull 1900 public FutureRowCount<T> findFutureCount() { 1901 return query.findFutureCount(); 1902 } 1903 1904 /** 1905 * Execute find Id's query in a background thread. 1906 * <p> 1907 * This returns a Future object which can be used to cancel, check the 1908 * execution status (isDone etc) and get the value (with or without a 1909 * timeout). 1910 * </p> 1911 * 1912 * @return a Future object for the list of Id's 1913 */ 1914 @Nonnull 1915 public FutureIds<T> findFutureIds() { 1916 return query.findFutureIds(); 1917 } 1918 1919 /** 1920 * Execute find list query in a background thread. 1921 * <p> 1922 * This query will execute in it's own PersistenceContext and using its own transaction. 1923 * What that means is that it will not share any bean instances with other queries. 1924 * </p> 1925 * 1926 * @return a Future object for the list result of the query 1927 */ 1928 @Nonnull 1929 public FutureList<T> findFutureList() { 1930 return query.findFutureList(); 1931 } 1932 1933 /** 1934 * Return a PagedList for this query using firstRow and maxRows. 1935 * <p> 1936 * The benefit of using this over findList() is that it provides functionality to get the 1937 * total row count etc. 1938 * </p> 1939 * <p> 1940 * If maxRows is not set on the query prior to calling findPagedList() then a 1941 * PersistenceException is thrown. 1942 * </p> 1943 * <p> 1944 * <pre>{@code 1945 * 1946 * PagedList<Order> pagedList = 1947 * new QOrder() 1948 * .setFirstRow(50) 1949 * .setMaxRows(20) 1950 * .findPagedList(); 1951 * 1952 * // fetch the total row count in the background 1953 * pagedList.loadRowCount(); 1954 * 1955 * List<Order> orders = pagedList.getList(); 1956 * int totalRowCount = pagedList.getTotalRowCount(); 1957 * 1958 * }</pre> 1959 * 1960 * @return The PagedList 1961 */ 1962 @Nonnull 1963 public PagedList<T> findPagedList() { 1964 return query.findPagedList(); 1965 } 1966 1967 /** 1968 * Execute as a delete query deleting the 'root level' beans that match the predicates 1969 * in the query. 1970 * <p> 1971 * Note that if the query includes joins then the generated delete statement may not be 1972 * optimal depending on the database platform. 1973 * </p> 1974 * 1975 * @return the number of beans/rows that were deleted. 1976 */ 1977 public int delete() { 1978 return query.delete(); 1979 } 1980 1981 /** 1982 * Return the sql that was generated for executing this query. 1983 * <p> 1984 * This is only available after the query has been executed and provided only 1985 * for informational purposes. 1986 * </p> 1987 */ 1988 public String getGeneratedSql() { 1989 return query.getGeneratedSql(); 1990 } 1991 1992 /** 1993 * Return the type of beans being queried. 1994 */ 1995 @Nonnull 1996 public Class<T> getBeanType() { 1997 return query.getBeanType(); 1998 } 1999 2000 /** 2001 * Return the expression list that has been built for this query. 2002 */ 2003 @Nonnull 2004 public ExpressionList<T> getExpressionList() { 2005 return query.where(); 2006 } 2007 2008 /** 2009 * Start adding expressions to the having clause when using @Aggregation properties. 2010 * 2011 * <pre>{@code 2012 * 2013 * new QMachineUse() 2014 * // where ... 2015 * .date.inRange(fromDate, toDate) 2016 * 2017 * .having() 2018 * .sumHours.greaterThan(1) 2019 * .findList() 2020 * 2021 * // The sumHours property uses @Aggregation 2022 * // e.g. @Aggregation("sum(hours)") 2023 * 2024 * }</pre> 2025 */ 2026 public R having() { 2027 if (whereStack == null) { 2028 whereStack = new ArrayStack<>(); 2029 } 2030 // effectively putting having expression list onto stack 2031 // such that expression now add to the having clause 2032 whereStack.push(query.having()); 2033 return root; 2034 } 2035 2036 /** 2037 * Return the underlying having clause to typically when using dynamic aggregation formula. 2038 * <p> 2039 * Note that after this we no longer have the query bean so typically we use this right 2040 * at the end of the query. 2041 * </p> 2042 * 2043 * <pre>{@code 2044 * 2045 * // sum(distanceKms) ... is a "dynamic formula" 2046 * // so we use havingClause() for it like: 2047 * 2048 * List<MachineUse> machineUse = 2049 * 2050 * new QMachineUse() 2051 * .select("machine, sum(fuelUsed), sum(distanceKms)") 2052 * 2053 * // where ... 2054 * .date.greaterThan(LocalDate.now().minusDays(7)) 2055 * 2056 * .havingClause() 2057 * .gt("sum(distanceKms)", 2) 2058 * .findList(); 2059 * 2060 * }</pre> 2061 */ 2062 public ExpressionList<T> havingClause() { 2063 return query.having(); 2064 } 2065 2066 /** 2067 * Return the current expression list that expressions should be added to. 2068 */ 2069 protected ExpressionList<T> peekExprList() { 2070 2071 if (textMode) { 2072 // return the current text expression list 2073 return _peekText(); 2074 } 2075 2076 if (whereStack == null) { 2077 whereStack = new ArrayStack<>(); 2078 whereStack.push(query.where()); 2079 } 2080 // return the current expression list 2081 return whereStack.peek(); 2082 } 2083 2084 protected ExpressionList<T> _peekText() { 2085 if (textStack == null) { 2086 textStack = new ArrayStack<>(); 2087 // empty so push on the queries base expression list 2088 textStack.push(query.text()); 2089 } 2090 // return the current expression list 2091 return textStack.peek(); 2092 } 2093}