001package io.ebean;
002
003import io.avaje.lang.NonNullApi;
004import io.avaje.lang.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 */
058@NonNullApi
059public class Finder<I, T> {
060
061  /**
062   * The entity bean type.
063   */
064  private final Class<T> type;
065
066  /**
067   * The name of the database this finder will use, null for the default database.
068   */
069  private final String _$dbName;
070
071  /**
072   * Create with the type of the entity bean.
073   * <pre>{@code
074   *
075   * public class CustomerFinder extends Finder<Customer> {
076   *
077   *   public CustomerFinder() {
078   *     super(Customer.class);
079   *   }
080   *
081   *   // ... add extra customer specific finder methods
082   * }
083   *
084   * @Entity
085   * public class Customer extends BaseModel {
086   *
087   *   public static final CustomerFinder find = new CustomerFinder();
088   *   ...
089   *
090   * }
091   * }</pre>
092   */
093  public Finder(Class<T> type) {
094    this.type = type;
095    this._$dbName = null;
096  }
097
098  /**
099   * Create with the type of the entity bean and specific database name.
100   */
101  public Finder(Class<T> type, String databaseName) {
102    this.type = type;
103    this._$dbName = databaseName;
104  }
105
106  /**
107   * Return the current transaction.
108   */
109  public Transaction currentTransaction() {
110    return db().currentTransaction();
111  }
112
113  /**
114   * Flush the JDBC batch on the current transaction.
115   */
116  public void flush() {
117    db().flush();
118  }
119
120  /**
121   * Return the Database this finder will use.
122   */
123  public Database db() {
124    return DB.byName(_$dbName);
125  }
126
127  /**
128   * Return typically a different Database to the default.
129   * <p>
130   * This is equivalent to {@link DB#byName(String)}
131   *
132   * @param databaseName The name of the Database. If this is null then the default database is returned.
133   */
134  public Database db(String databaseName) {
135    return DB.byName(databaseName);
136  }
137
138  /**
139   * Creates an entity reference for this ID.
140   * <p>
141   * Equivalent to {@link Database#reference(Class, Object)}
142   */
143  public T ref(I id) {
144    return db().reference(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  public List<T> all() {
170    return query().findList();
171  }
172
173  /**
174   * Creates an update query.
175   *
176   * <pre>{@code
177   *
178   *  int rows =
179   *      finder.update()
180   *      .set("status", Customer.Status.ACTIVE)
181   *      .set("updtime", new Timestamp(System.currentTimeMillis()))
182   *      .where()
183   *        .gt("id", 1000)
184   *        .update();
185   *
186   * }</pre>
187   *
188   * <p>
189   * Equivalent to {@link Database#update(Class)}
190   */
191  public UpdateQuery<T> update() {
192    return db().update(type);
193  }
194
195  /**
196   * Creates a query.
197   * <p>
198   * Equivalent to {@link Database#find(Class)}
199   */
200  public Query<T> query() {
201    return db().find(type);
202  }
203
204  /**
205   * Creates a native sql query.
206   */
207  public Query<T> nativeSql(String nativeSql) {
208    return db().findNative(type, nativeSql);
209  }
210
211  /**
212   * Creates a query using the ORM query language.
213   */
214  public Query<T> query(String ormQuery) {
215    return db().createQuery(type, ormQuery);
216  }
217
218}