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