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}