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 * Assign to a property to be based on a SQL formula. 012 * <p> 013 * This is typically a SQL Literal value, SQL case statement, SQL function or 014 * similar. 015 * </p> 016 * <p> 017 * Any property based on a formula becomes a read only property. 018 * </p> 019 * <p> 020 * You may also put use the Transient annotation with the Formula annotation. 021 * The effect of the Transient annotation in this case is that the formula will 022 * <b>NOT</b> be included in queries by default - you have to explicitly include 023 * it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}. 024 * You may want to do this if the Formula is relatively expensive and only want 025 * it included in the query when you explicitly state it. 026 * </p> 027 * 028 * <pre class="code"> 029 * // On the Order "master" bean 030 * // ... a formula using the Order details 031 * // ... sum(order_qty*unit_price) 032 * @Transient 033 * @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id") 034 * Double totalAmount; 035 * 036 * </pre> 037 * <p> 038 * As the totalAmount formula is also Transient it is not included by default in 039 * queries - it needs to be explicitly included. 040 * </p> 041 * 042 * <pre>{@code 043 * 044 * // find by Id 045 * Order o1 = Ebean.find(Order.class) 046 * .select("id, totalAmount") 047 * .setId(1).findUnique(); 048 * 049 * // find list ... using totalAmount in the where clause 050 * List<Order> list = Ebean.find(Order.class) 051 * .select("id, totalAmount") 052 * .where() 053 * .eq("status", Order.Status.NEW) 054 * .gt("totalAmount", 10) 055 * .findList(); 056 * 057 * // as a join from customer 058 * List<Customer> l0 = Ebean.find(Customer.class) 059 * .select("id, name") 060 * .fetch("orders", "status, totalAmount") 061 * .where() 062 * .gt("id", 0) 063 * .gt("orders.totalAmount", 10) 064 * .findList(); 065 * 066 * }</pre> 067 */ 068@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE }) 069@Retention(RetentionPolicy.RUNTIME) 070public @interface Formula { 071 072 /** 073 * The SQL to be used in the SELECT part of the SQL to populate a property. 074 */ 075 String select(); 076 077 /** 078 * OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the 079 * formula. 080 * <p> 081 * This is commonly used to join a 'dynamic view' to support aggregation such 082 * as count, sum etc. 083 * </p> 084 * <p> 085 * The join string should start with either "left outer join" or "join". 086 * </p> 087 * 088 * <p> 089 * You will almost certainly use the "${ta}" as a place holder for the table 090 * alias of the table you are joining back to (the "base table" of the entity 091 * bean). 092 * </p> 093 * <p> 094 * The example below is used to support a total count of topics created by a 095 * user. 096 * </p> 097 * 098 * <pre>{@code 099 * 100 * join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id 101 * 102 * }</pre> 103 */ 104 String join() default ""; 105 106}