001package com.avaje.ebean;
002
003import java.sql.ResultSet;
004
005import com.avaje.ebean.RawSql.ColumnMapping;
006import com.avaje.ebean.RawSql.Sql;
007
008/**
009 * Builds RawSql instances from a SQL string and column mappings.
010 * <p>
011 * Note that RawSql can also be defined in ebean-orm.xml files and be used as a
012 * named query.
013 * </p>
014 * 
015 * @see RawSql
016 */
017public class RawSqlBuilder {
018
019  /**
020   * Special property name assigned to a DB column that should be ignored.
021   */
022  public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
023
024  private final ResultSet resultSet;
025  
026  private final Sql sql;
027
028  private final ColumnMapping columnMapping;
029
030  /**
031   * Create and return a RawSql object based on the resultSet and list of properties the columns in
032   * the resultSet map to.
033   * <p>
034   * The properties listed in the propertyNames must be in the same order as the columns in the
035   * resultSet.
036   */
037  public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
038    return new RawSql(resultSet, propertyNames);
039  }
040  
041  /**
042   * Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
043   * modified - so no additional WHERE or HAVING expressions can be added to
044   * this query.
045   */
046  public static RawSqlBuilder unparsed(String sql) {
047
048    Sql s = new Sql(sql);
049    return new RawSqlBuilder(s, new ColumnMapping());
050  }
051
052  /**
053   * Return a RawSqlBuilder parsing the sql.
054   * <p>
055   * The sql statement will be parsed so that Ebean can determine where it can
056   * insert additional WHERE or HAVING expressions.
057   * </p>
058   * <p>
059   * Additionally the selected columns are parsed to determine the column
060   * ordering. This also means additional checks can be made with the column
061   * mapping - specifically we can check that all columns are mapped and that
062   * correct column names are entered into the mapping.
063   * </p>
064   */
065  public static RawSqlBuilder parse(String sql) {
066
067    Sql sql2 = DRawSqlParser.parse(sql);
068    String select = sql2.getPreFrom();
069
070    ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
071    return new RawSqlBuilder(sql2, mapping);
072  }
073  
074  private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
075    this.sql = sql;
076    this.columnMapping = columnMapping;
077    this.resultSet = null;
078  }
079
080  /**
081   * Set the mapping of a DB Column to a bean property.
082   * <p>
083   * For Unparsed SQL the columnMapping MUST be defined in the same order that
084   * the columns appear in the SQL statement.
085   * </p>
086   * 
087   * @param dbColumn
088   *          the DB column that we are mapping to a bean property
089   * @param propertyName
090   *          the bean property that we are mapping the DB column to.
091   */
092  public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
093    columnMapping.columnMapping(dbColumn, propertyName);
094    return this;
095  }
096
097  /**
098   * Ignore this DB column. It is not mapped to any bean property.
099   */
100  public RawSqlBuilder columnMappingIgnore(String dbColumn) {
101    return columnMapping(dbColumn, IGNORE_COLUMN);
102  }
103
104  /**
105   * Modify any column mappings with the given table alias to have the path prefix.
106   * <p>
107   * For example modify all mappings with table alias "c" to have the path prefix "customer".
108   * </p>
109   * <p>
110   * For the "Root type" you don't need to specify a tableAliasMapping.
111   * </p>
112   */
113  public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
114    columnMapping.tableAliasMapping(tableAlias, path);
115    return this;
116  }
117
118  /**
119   * Create the immutable RawSql object. Do this after all the column mapping
120   * has been defined.
121   */
122  public RawSql create() {
123    return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
124  }
125
126  /**
127   * Return the internal parsed Sql object (for testing).
128   */
129  protected Sql getSql() {
130    return sql;
131  }
132
133
134
135}