001package io.ebean.typequery;
002
003import io.ebean.ExpressionList;
004import io.ebean.FetchConfig;
005import io.ebeaninternal.api.SpiQueryFetch;
006
007import java.util.LinkedHashSet;
008import java.util.Set;
009
010/**
011 * Base type for associated beans.
012 *
013 * @param <T> the entity bean type (normal entity bean type e.g. Customer)
014 * @param <R> the specific root query bean type (e.g. QCustomer)
015 */
016@SuppressWarnings("rawtypes")
017public abstract class TQAssocBean<T, R> extends TQProperty<R> {
018
019  private static final FetchConfig FETCH_DEFAULT = FetchConfig.ofDefault();
020  private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
021  private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
022  private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
023
024  /**
025   * Construct with a property name and root instance.
026   *
027   * @param name the name of the property
028   * @param root the root query bean instance
029   */
030  public TQAssocBean(String name, R root) {
031    this(name, root, null);
032  }
033
034  /**
035   * Construct with additional path prefix.
036   */
037  public TQAssocBean(String name, R root, String prefix) {
038    super(name, root, prefix);
039  }
040
041  /**
042   * Eagerly fetch this association fetching all the properties.
043   */
044  public R fetch() {
045    ((TQRootBean) _root).query().fetch(_name);
046    return _root;
047  }
048
049  /**
050   * Eagerly fetch this association using a "query join".
051   */
052  public R fetchQuery() {
053    ((TQRootBean) _root).query().fetchQuery(_name);
054    return _root;
055  }
056
057  /**
058   * Eagerly fetch this association using L2 bean cache.
059   * Cache misses are populated via fetchQuery().
060   */
061  public R fetchCache() {
062    ((TQRootBean) _root).query().fetchCache(_name);
063    return _root;
064  }
065
066  /**
067   * Use lazy loading for fetching this association.
068   */
069  public R fetchLazy() {
070    ((TQRootBean) _root).query().fetchLazy(_name);
071    return _root;
072  }
073
074  /**
075   * Eagerly fetch this association with the properties specified.
076   */
077  public R fetch(String properties) {
078    ((TQRootBean) _root).query().fetch(_name, properties);
079    return _root;
080  }
081
082  /**
083   * Eagerly fetch this association using a "query join" with the properties specified.
084   */
085  public R fetchQuery(String properties) {
086    ((TQRootBean) _root).query().fetchQuery(_name, properties);
087    return _root;
088  }
089
090  /**
091   * Eagerly fetch this association using L2 cache with the properties specified.
092   * Cache misses are populated via  fetchQuery().
093   */
094  public R fetchCache(String properties) {
095    ((TQRootBean) _root).query().fetchCache(_name, properties);
096    return _root;
097  }
098
099  /**
100   * Deprecated in favor of fetch().
101   */
102  @Deprecated
103  public R fetchAll() {
104    return fetch();
105  }
106
107  /**
108   * Eagerly fetch this association fetching some of the properties.
109   */
110  @SafeVarargs
111  protected final R fetchProperties(TQProperty<?>... props) {
112    return fetchWithProperties(FETCH_DEFAULT, props);
113  }
114
115  /**
116   * Eagerly fetch query this association fetching some of the properties.
117   */
118  @SafeVarargs
119  protected final R fetchQueryProperties(TQProperty<?>... props) {
120    return fetchWithProperties(FETCH_QUERY, props);
121  }
122
123  /**
124   * Eagerly fetch this association using L2 bean cache.
125   */
126  @SafeVarargs
127  protected final R fetchCacheProperties(TQProperty<?>... props) {
128    return fetchWithProperties(FETCH_CACHE, props);
129  }
130
131  /**
132   * Eagerly fetch query this association fetching some of the properties.
133   */
134  @SafeVarargs
135  protected final R fetchLazyProperties(TQProperty<?>... props) {
136    return fetchWithProperties(FETCH_LAZY, props);
137  }
138
139  @SafeVarargs
140  private final R fetchWithProperties(FetchConfig config, TQProperty<?>... props) {
141    spiQuery().fetchProperties(_name, properties(props), config);
142    return _root;
143  }
144
145  private final SpiQueryFetch spiQuery() {
146    return (SpiQueryFetch)((TQRootBean) _root).query();
147  }
148
149  @SafeVarargs
150  private final Set<String> properties(TQProperty<?>... props) {
151    Set<String> set = new LinkedHashSet<>();
152    for (TQProperty<?> prop : props) {
153      set.add(prop.propertyName());
154    }
155    return set;
156  }
157
158  /**
159   * Is equal to by ID property.
160   */
161  public R eq(T other) {
162    expr().eq(_name, other);
163    return _root;
164  }
165
166  /**
167   * Is equal to by ID property.
168   */
169  public R equalTo(T other) {
170    return eq(other);
171  }
172
173  /**
174   * Is not equal to by ID property.
175   */
176  public R ne(T other) {
177    expr().ne(_name, other);
178    return _root;
179  }
180
181  /**
182   * Is not equal to by ID property.
183   */
184  public R notEqualTo(T other) {
185    return ne(other);
186  }
187
188  /**
189   * Apply a filter when fetching these beans.
190   */
191  public R filterMany(ExpressionList<T> filter) {
192
193    @SuppressWarnings("unchecked")
194    ExpressionList<T> expressionList = (ExpressionList<T>) expr().filterMany(_name);
195    expressionList.addAll(filter);
196    return _root;
197  }
198
199  /**
200   * Apply a filter when fetching these beans.
201   * <p>
202   * The expressions can use any valid Ebean expression and contain
203   * placeholders for bind values using <code>?</code> or <code>?1</code> style.
204   * </p>
205   *
206   * <pre>{@code
207   *
208   *     new QCustomer()
209   *       .name.startsWith("Postgres")
210   *       .contacts.filterMany("firstName istartsWith ?", "Rob")
211   *       .findList();
212   *
213   * }</pre>
214   *
215   * <pre>{@code
216   *
217   *     new QCustomer()
218   *       .name.startsWith("Postgres")
219   *       .contacts.filterMany("whenCreated inRange ? to ?", startDate, endDate)
220   *       .findList();
221   *
222   * }</pre>
223   *
224   * @param expressions The expressions including and, or, not etc with ? and ?1 bind params.
225   * @param params      The bind parameter values
226   */
227  public R filterMany(String expressions, Object... params) {
228    expr().filterMany(_name, expressions, params);
229    return _root;
230  }
231
232  /**
233   * Is empty for a collection property.
234   * <p>
235   * This effectively adds a not exists sub-query on the collection property.
236   * </p>
237   * <p>
238   * This expression only works on OneToMany and ManyToMany properties.
239   * </p>
240   */
241  public R isEmpty() {
242    expr().isEmpty(_name);
243    return _root;
244  }
245
246  /**
247   * Is not empty for a collection property.
248   * <p>
249   * This effectively adds an exists sub-query on the collection property.
250   * </p>
251   * <p>
252   * This expression only works on OneToMany and ManyToMany properties.
253   * </p>
254   */
255  public R isNotEmpty() {
256    expr().isNotEmpty(_name);
257    return _root;
258  }
259
260}