001package io.ebean;
002
003import javax.annotation.Nonnull;
004import javax.annotation.Nullable;
005import java.util.List;
006
007/**
008 * Intended to be used as a base class for 'Finder' implementations that can then
009 * be injected or used as public static fields on the associated entity bean.
010 * <p>
011 * These 'finders' are a place to organise all the finder methods for that bean type
012 * and specific finder methods are expected to be added (find by unique properties etc).
013 * </p>
014 * <h3>Testing</h3>
015 * <p>
016 * For testing the mocki-ebean project has the ability to replace the finder implementation.
017 * </p>
018 * <pre>{@code
019 *
020 * public class CustomerFinder extends Finder<Long,Customer> {
021 *
022 *   public CustomerFinder() {
023 *     super(Customer.class);
024 *   }
025 *
026 *   // Add finder methods ...
027 *
028 *   public Customer byName(String name) {
029 *     return query().eq("name", name).findOne();
030 *   }
031 *
032 *   public List<Customer> findNew() {
033 *     return query().where()
034 *       .eq("status", Customer.Status.NEW)
035 *       .order("name")
036 *       .findList()
037 *   }
038 * }
039 *
040 * @Entity
041 * public class Customer extends BaseModel {
042 *
043 *   public static final CustomerFinder find = new CustomerFinder();
044 *   ...
045 *
046 * }
047 * }</pre>
048 * <p>
049 *  When the Finder is registered as a field on Customer it can then be used like:
050 * </p>
051 * <pre>{@code
052 *
053 *   Customer rob = Customer.find.byName("Rob");
054 *
055 * }</pre>
056 *
057 */
058public class Finder<I, T> {
059
060  /**
061   * The entity bean type.
062   */
063  private final Class<T> type;
064
065  /**
066   * The name of the database this finder will use, null for the default database.
067   */
068  private final String _$dbName;
069
070  /**
071   * Create with the type of the entity bean.
072   * <pre>{@code
073   *
074   * public class CustomerFinder extends Finder<Customer> {
075   *
076   *   public CustomerFinder() {
077   *     super(Customer.class);
078   *   }
079   *
080   *   // ... add extra customer specific finder methods
081   * }
082   *
083   * @Entity
084   * public class Customer extends BaseModel {
085   *
086   *   public static final CustomerFinder find = new CustomerFinder();
087   *   ...
088   *
089   * }
090   * }</pre>
091   */
092  public Finder(Class<T> type) {
093    this.type = type;
094    this._$dbName = null;
095  }
096
097  /**
098   * Create with the type of the entity bean and specific database name.
099   */
100  public Finder(Class<T> type, String databaseName) {
101    this.type = type;
102    this._$dbName = databaseName;
103  }
104
105  /**
106   * Return the current transaction.
107   */
108  public Transaction currentTransaction() {
109    return db().currentTransaction();
110  }
111
112  /**
113   * Flush the JDBC batch on the current transaction.
114   */
115  public void flush() {
116    db().flush();
117  }
118
119  /**
120   * Return the Database this finder will use.
121   */
122  public Database db() {
123    return DB.byName(_$dbName);
124  }
125
126  /**
127   * Return typically a different Database to the default.
128   * <p>
129   * This is equivalent to {@link DB#byName(String)}
130   *
131   * @param databaseName The name of the Database. If this is null then the default database is returned.
132   */
133  public Database db(String databaseName) {
134    return DB.byName(databaseName);
135  }
136
137  /**
138   * Creates an entity reference for this ID.
139   * <p>
140   * Equivalent to {@link Database#getReference(Class, Object)}
141   */
142  @Nonnull
143  public T ref(I id) {
144    return db().getReference(type, id);
145  }
146
147  /**
148   * Retrieves an entity by ID.
149   * <p>
150   * Equivalent to {@link Database#find(Class, Object)}
151   */
152  @Nullable
153  public T byId(I id) {
154    return db().find(type, id);
155  }
156
157  /**
158   * Delete a bean by Id.
159   * <p>
160   * Equivalent to {@link Database#delete(Class, Object)}
161   */
162  public void deleteById(I id) {
163    db().delete(type, id);
164  }
165
166  /**
167   * Retrieves all entities of the given type.
168   */
169  @Nonnull
170  public List<T> all() {
171    return query().findList();
172  }
173
174  /**
175   * Creates an update query.
176   *
177   * <pre>{@code
178   *
179   *  int rows =
180   *      finder.update()
181   *      .set("status", Customer.Status.ACTIVE)
182   *      .set("updtime", new Timestamp(System.currentTimeMillis()))
183   *      .where()
184   *        .gt("id", 1000)
185   *        .update();
186   *
187   * }</pre>
188   *
189   * <p>
190   * Equivalent to {@link Database#update(Class)}
191   */
192  public UpdateQuery<T> update() {
193    return db().update(type);
194  }
195
196  /**
197   * Creates a query.
198   * <p>
199   * Equivalent to {@link Database#find(Class)}
200   */
201  public Query<T> query() {
202    return db().find(type);
203  }
204
205  /**
206   * Creates a native sql query.
207   */
208  public Query<T> nativeSql(String nativeSql) {
209    return db().findNative(type, nativeSql);
210  }
211
212  /**
213   * Creates a query using the ORM query language.
214   */
215  public Query<T> query(String ormQuery) {
216    return db().createQuery(type, ormQuery);
217  }
218
219}