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 *       .orderBy("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 * }</pre>
047 * <p>
048 *  When the Finder is registered as a field on Customer it can then be used like:
049 * </p>
050 * <pre>{@code
051 *
052 *   Customer rob = Customer.find.byName("Rob");
053 *
054 * }</pre>
055 *
056 */
057public class Finder<I, T> {
058
059  /**
060   * The entity bean type.
061   */
062  private final Class<T> type;
063
064  /**
065   * The name of the database this finder will use, null for the default database.
066   */
067  private final String _$dbName;
068
069  /**
070   * Create with the type of the entity bean.
071   * <pre>{@code
072   *
073   * public class CustomerFinder extends Finder<Customer> {
074   *
075   *   public CustomerFinder() {
076   *     super(Customer.class);
077   *   }
078   *
079   *   // ... add extra customer specific finder methods
080   * }
081   *
082   * @Entity
083   * public class Customer extends BaseModel {
084   *
085   *   public static final CustomerFinder find = new CustomerFinder();
086   *   ...
087   *
088   * }</pre>
089   */
090  public Finder(Class<T> type) {
091    this.type = type;
092    this._$dbName = null;
093  }
094
095  /**
096   * Create with the type of the entity bean and specific database name.
097   */
098  public Finder(Class<T> type, String databaseName) {
099    this.type = type;
100    this._$dbName = databaseName;
101  }
102
103  /**
104   * Return the current transaction.
105   */
106  public Transaction currentTransaction() {
107    return db().currentTransaction();
108  }
109
110  /**
111   * Flush the JDBC batch on the current transaction.
112   */
113  public void flush() {
114    db().flush();
115  }
116
117  /**
118   * Return the Database this finder will use.
119   */
120  public Database db() {
121    return DB.byName(_$dbName);
122  }
123
124  /**
125   * Return typically a different Database to the default.
126   * <p>
127   * This is equivalent to {@link DB#byName(String)}
128   *
129   * @param databaseName The name of the Database. If this is null then the default database is returned.
130   */
131  public Database db(String databaseName) {
132    return DB.byName(databaseName);
133  }
134
135  /**
136   * Creates an entity reference for this ID.
137   * <p>
138   * Equivalent to {@link Database#getReference(Class, Object)}
139   */
140  @Nonnull
141  public T ref(I id) {
142    return db().getReference(type, id);
143  }
144
145  /**
146   * Retrieves an entity by ID.
147   * <p>
148   * Equivalent to {@link Database#find(Class, Object)}
149   */
150  @Nullable
151  public T byId(I id) {
152    return db().find(type, id);
153  }
154
155  /**
156   * Delete a bean by Id.
157   * <p>
158   * Equivalent to {@link Database#delete(Class, Object)}
159   */
160  public void deleteById(I id) {
161    db().delete(type, id);
162  }
163
164  /**
165   * Retrieves all entities of the given type.
166   */
167  @Nonnull
168  public List<T> all() {
169    return query().findList();
170  }
171
172  /**
173   * Creates an update query.
174   *
175   * <pre>{@code
176   *
177   *  int rows =
178   *      finder.update()
179   *      .set("status", Customer.Status.ACTIVE)
180   *      .set("updtime", new Timestamp(System.currentTimeMillis()))
181   *      .where()
182   *        .gt("id", 1000)
183   *        .update();
184   *
185   * }</pre>
186   *
187   * <p>
188   * Equivalent to {@link Database#update(Class)}
189   */
190  public UpdateQuery<T> update() {
191    return db().update(type);
192  }
193
194  /**
195   * Creates a query.
196   * <p>
197   * Equivalent to {@link Database#find(Class)}
198   */
199  public Query<T> query() {
200    return db().find(type);
201  }
202
203  /**
204   * Creates a native sql query.
205   */
206  public Query<T> nativeSql(String nativeSql) {
207    return db().findNative(type, nativeSql);
208  }
209
210  /**
211   * Creates a query using the ORM query language.
212   */
213  public Query<T> query(String ormQuery) {
214    return db().createQuery(type, ormQuery);
215  }
216
217}