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