001package com.avaje.ebean.annotation;
002
003import java.lang.annotation.ElementType;
004import java.lang.annotation.Retention;
005import java.lang.annotation.RetentionPolicy;
006import java.lang.annotation.Target;
007
008import com.avaje.ebean.Query;
009
010/**
011 * Specify an explicit sql select statement to use for querying an entity bean.
012 * <p>
013 * The reason for using explicit sql is that you want better control over the
014 * exact sql or sql that Ebean does not generate for you (such as group by,
015 * union, intersection, window functions, recursive queries).
016 * </p>
017 * <p>
018 * An example of two sql select queries deployed on the ReportTopic entity bean.
019 * The first one has no name specified so it becomes the default query. The
020 * second query extends the first adding a where clause with a named parameter.
021 * </p>
022 * 
023 * <pre class="code">
024 * ...
025 * &#064;Entity
026 *   &#064;Sql(select = {
027 *     &#064;SqlSelect(query = 
028 *       &quot;select t.id, t.title, count(p.id) as score &quot;+
029 *       &quot;from f_topic t &quot;+
030 *       &quot;join f_topic_post p on p.topic_id = t.id &quot;+
031 *       &quot;group by t.id, t.title&quot;),
032 *     &#064;SqlSelect(
033 *       name = &quot;with.title&quot;,
034 *       extend = &quot;default&quot;,
035 *       debug = true,
036 *       where = &quot;title like :likeTitle&quot;)
037 *  })
038 *  public class ReportTopic
039 *    &#064;Id Integer id;
040 *    String title;
041 *    Double score;
042 *    ...
043 * </pre>
044 * 
045 * <p>
046 * An example using the first "default" query.
047 * </p>
048 * 
049 * <pre class="code">
050 * 
051 * List&lt;ReportTopic&gt; list =
052 *     Ebean.find(ReportTopic.class)
053 *         .having().gt(&quot;score&quot;, 0)
054 *         .findList();
055 * 
056 * </pre>
057 * 
058 * <p>
059 * The resulting sql, note the having clause has been added.
060 * </p>
061 * 
062 * <pre class="code">
063 * select t.id, t.title, count(p.id) as score 
064 * from f_topic t join f_topic_post p on p.topic_id = t.id 
065 * group by t.id, t.title  
066 * having count(p.id) &gt; ?
067 * </pre>
068 * 
069 * <p>
070 * An example using the second query. Note the named parameter "likeTitle" must
071 * be set.
072 * </p>
073 * 
074 * <pre class="code">
075 * List&lt;ReportTopic&gt; list =
076 *     Ebean.find(ReportTopic.class, &quot;with.title&quot;)
077 *         .set(&quot;likeTitle&quot;, &quot;a%&quot;)
078 *         .findList();
079 * </pre>
080 * 
081 * <p>
082 * Ebean tries to parse the sql in the query to determine 4 things
083 * <li>Location for inserting WHERE expressions (if required)</li>
084 * <li>Location for inserting HAVING expressions (if required)</li>
085 * <li>Mapping of columns to bean properties</li>
086 * <li>The order by clause</li>
087 * </p>
088 * <p>
089 * If Ebean is unable to parse out this information (perhaps because the sql
090 * contains multiple select from keywords etc) then you need to manually specify
091 * it.
092 * </p>
093 * <p>
094 * Insert ${where} or ${andWhere} into the location where Ebean can insert any
095 * expressions added to the where clause. Use ${andWhere} if the sql already has
096 * the WHERE keyword and Ebean will instead start with a AND keyword.
097 * </p>
098 * <p>
099 * Insert ${having} or ${andHaving} into the location where Ebean can insert any
100 * expressions added to the having clause. Use ${andHaving} if the sql already
101 * has a HAVING keyword and Ebean will instead start with a AND keyword.
102 * </p>
103 * <p>
104 * Use the columnMapping property if Ebean is unable to determine the columns
105 * and map them to bean properties.
106 * </p>
107 * <p>
108 * Example with ${andWhere} & ${having}.
109 * </p>
110 * 
111 * <pre class="code">
112 *    &#064;SqlSelect(
113 *          name = &quot;explicit.where&quot;,
114 *          query = 
115 *              &quot;select t.id, t.title, count(p.id) as score &quot;+
116 *              &quot;from f_topic t, f_topic_post p &quot;+
117 *              &quot;where p.topic_id = t.id ${andWhere} &quot;+
118 *              &quot;group by t.id, t.title ${having}&quot;),
119 * </pre>
120 */
121@Target({ ElementType.TYPE })
122@Retention(RetentionPolicy.RUNTIME)
123@Deprecated
124public @interface SqlSelect {
125
126  /**
127   * The name of the query. If left blank this is assumed to be the default
128   * query for this bean type.
129   * <p>
130   * This will default to "default" and in that case becomes the default query
131   * used for the bean.
132   * </p>
133   */
134  String name() default "default";
135
136  /**
137   * The tableAlias used when adding where expressions to the query.
138   */
139  String tableAlias() default "";
140
141  /**
142   * The sql select statement.
143   * <p>
144   * If this query <em>extends</em> another then this string is appended to the
145   * parent query string. Often when using <em>extend</em> you will leave the
146   * query part blank and just specify a where and/or having clauses.
147   * </p>
148   * <p>
149   * This sql <em>CAN NOT</em> contain named parameters. You have to put these
150   * in the separate where and/or having sections.
151   * </p>
152   * <p>
153   * Ebean automatically tries to determine the location in the sql string for
154   * putting in additional where or having clauses. If Ebean is unable to
155   * successfully determine this then you have to explicitly specify these
156   * locations by including
157   * <em>${where} or ${andWhere} and  ${having} or ${andHaving}</em> in the sql.
158   * </p>
159   * <p>
160   * <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
161   * Use this when there is no where clause in the sql. If expressions are added
162   * to the where clause Ebean will put them in at this location starting with
163   * the WHERE keyword.
164   * <p>
165   * <p>
166   * <b>${andWhere}</b> <br/>
167   * Use this instead of ${where} if there IS an existing where clause in the
168   * sql. Ebean will add the expressions starting with the AND keyword.
169   * <p>
170   * <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
171   * </p>
172   * <p>
173   * <b>${andHaving}</b> <br/>
174   * Use this instead of ${having} when there IS an existing HAVING clause.
175   * Ebean will add the expressions starting with the AND keyword.
176   * </p>
177   * <p>
178   * You can include one of ${where} OR ${andWhere} but not both.
179   * </p>
180   * <p>
181   * You can include one of ${having} OR ${andHaving} but not both.
182   * </p>
183   */
184  String query() default "";
185
186  /**
187   * Specify the name of a sql-select query that this one 'extends'.
188   * <p>
189   * When a query is extended the sql query contents are appended together. The
190   * where and having clauses are NOT appended but overridden.
191   * </p>
192   */
193  String extend() default "";
194
195  /**
196   * Specify a where clause typically containing named parameters.
197   * <p>
198   * If a where clause is specified with named parameters then they will need to
199   * be set on the query via {@link Query#setParameter(String, Object)}.
200   * </p>
201   * <p>
202   * In the example below the query specifies a where clause that includes a
203   * named parameter "likeTitle".
204   * </p>
205   * 
206   * <pre class="code">
207   * ...
208   * &#064;Entity
209   * &#064;Sql(select = {
210   *  ...
211   *  &#064;SqlSelect(
212   *  name = &quot;with.title&quot;,
213   *  extend = &quot;default&quot;,
214   *  debug = true,
215   *  where = &quot;title like :likeTitle&quot;)
216   *  })
217   *  public class ReportTopic
218   *  ...
219   * </pre>
220   * 
221   * <p>
222   * Example use of the above named query.
223   * </p>
224   * 
225   * <pre class="code">
226   * 
227   * Query&lt;ReportTopic&gt; query0 = Ebean.createQuery(ReportTopic.class, &quot;with.title&quot;);
228   * 
229   * query0.set(&quot;likeTitle&quot;, &quot;Bana%&quot;);
230   * 
231   * List&lt;ReportTopic&gt; list0 = query0.findList();
232   * </pre>
233   * 
234   */
235  String where() default "";
236
237  /**
238   * Specify a having clause typically containing named parameters.
239   * <p>
240   * If a having clause is specified with named parameters then they will need
241   * to be set on the query via {@link Query#setParameter(String, Object)}.
242   * </p>
243   */
244  String having() default "";
245
246  /**
247   * (Optional) Explicitly specify column to property mapping.
248   * <p>
249   * This is required when Ebean is unable to parse the sql. This could occur if
250   * the sql contains multiple select keywords etc.
251   * </p>
252   * <p>
253   * Specify the columns and property names they map to in the format.
254   * </p>
255   * 
256   * <pre class="code">
257   *  column1 propertyName1, column2 propertyName2, ...
258   * </pre>
259   * 
260   * <p>
261   * Optionally put a AS keyword between the column and property.
262   * </p>
263   * 
264   * <pre class="code">
265   *   // the AS keyword is optional
266   *  column1 AS propertyName1, column2 propertyName2, ...
267   * </pre>
268   * 
269   * <p>
270   * <b>column</b> should contain the table alias if there is one
271   * </p>
272   * <p>
273   * <b>propertyName</b> should match the property name.
274   * </p>
275   * 
276   * <p>
277   * Example mapping 5 columns to properties.
278   * </p>
279   * 
280   * <pre class="code">
281   * columnMapping=&quot;t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue&quot;,
282   * </pre>
283   * 
284   * <p>
285   * Without this set Ebean will parse the sql looking for the select clause and
286   * try to map the columns to property names. It is expected that Ebean will
287   * not be able to successfully parse some sql and for those cases you should
288   * specify the column to property mapping explicitly.
289   * </p>
290   * 
291   */
292  String columnMapping() default "";
293
294  /**
295   * Set this to true to have debug output when Ebean parses the sql-select.
296   */
297  boolean debug() default false;
298}