Package com.scooterframework.orm.activerecord

Source Code of com.scooterframework.orm.activerecord.QueryBuilder

/*
*   This software is distributed under the terms of the FSF
*   Gnu Lesser General Public License (see lgpl.txt).
*
*   This program is distributed WITHOUT ANY WARRANTY. See the
*   GNU General Public License for more details.
*/
package com.scooterframework.orm.activerecord;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.scooterframework.orm.misc.JdbcPageListSource;
import com.scooterframework.orm.misc.Paginator;
import com.scooterframework.orm.sqldataexpress.util.SqlConstants;

/**
* <p>QueryBuilder class provides flexible methods for building a query.</p>
*
* @author (Fei) John Chen
*/
public class QueryBuilder {
  private TableGateway tg;
    private String conditionsSQL;
    private Map<String, Object> conditionsSQLDataMap;
    private Map<String, String> options = new HashMap<String, String>();
   
    private boolean usedWhere;
    private boolean usedIncludes;
    private boolean usedGroupBy;
    private boolean usedHaving;
    private boolean usedOrderBy;
    private boolean usedLimit;
    private boolean usedOffset;
    private boolean usedPage;
 
  QueryBuilder(TableGateway tg) {
        this.tg = tg;
  }

    /**
     * <p>Returns all the records that satisfy the query built by
     * the <tt>QueryBuilder</tt>.</p>
     *
     * @return a list of ActiveRecord objects
     */
  public List<ActiveRecord> getRecords() {
    validateBuild();
    return tg.findAll(conditionsSQL, conditionsSQLDataMap, options);
  }

    /**
     * <p>Returns the record that satisfies the query built by
     * the <tt>QueryBuilder</tt>.</p>
     *
     * @return the ActiveRecord object
     */
  public ActiveRecord getRecord() {
    validateBuild();
    return tg.findFirst(conditionsSQL, conditionsSQLDataMap, options);
  }

    /**
     * <p>Returns a Paginator that satisfy the query built by
     * the <tt>QueryBuilder</tt>. Total number of records and paged list of
     * records can be obtained from the returned Paginator instance.</p>
     *
     * @return a Paginator instance
     */
  public Paginator getPaginator() {
    validateBuild();
    Class<? extends ActiveRecord> modelClass = tg.getModelClass();
   
    Map<String, String> inputOptions = new HashMap<String, String>();
    for (Map.Entry<String, String> entry : options.entrySet()) {
      String key = entry.getKey();
      if (Paginator.key_limit.equals(key) ||
          Paginator.key_offset.equals(key) ||
          Paginator.key_npage.equals(key)) continue;
      inputOptions.put(key, entry.getValue());
    }
   
    Map<String, String> pagingControl = new HashMap<String, String>();
   
    if (options.containsKey(ActiveRecordConstants.key_limit))
      pagingControl.put(Paginator.key_limit, options.get(ActiveRecordConstants.key_limit));
   
    if (options.containsKey(ActiveRecordConstants.key_offset))
      pagingControl.put(Paginator.key_offset, options.get(ActiveRecordConstants.key_offset));
   
    if (options.containsKey(ActiveRecordConstants.key_page))
      pagingControl.put(Paginator.key_npage, options.get(ActiveRecordConstants.key_page));
   
    return new Paginator(new JdbcPageListSource(modelClass, inputOptions), pagingControl);
  }
 
  private void validateBuild() {
    if (usedHaving && !usedGroupBy) {
      throw new RuntimeException("Group-by clause must be used with having clause.");
    }

    if (usedOffset && usedPage) {
      throw new RuntimeException("Page and offset cannot be set both at the same time.");
    }
  }
   
    /**
     * <p>Setup where clause.</p>
     *
     * @param conditionsSQL  a valid SQL query where clause string
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder where(String conditionsSQL) {
        return where(conditionsSQL, (Map<String, Object>)null);
    }
   
    /**
     * <p>Setup where clause.</p>
     *
     * @param conditionsSQL      a valid SQL query where clause string
     * @param conditionsSQLData  an array of data for the <tt>conditionsSQL</tt> string
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder where(String conditionsSQL, Object[] conditionsSQLData) {
    if (conditionsSQLData == null || conditionsSQLData.length == 0) {
      return where(conditionsSQL);
    }
    Map<String, Object> map = new HashMap<String, Object>(conditionsSQLData.length);
    int index = 1;
    for(Object o : conditionsSQLData) {
      map.put("" + index, o);
      index++;
    }
        return where(conditionsSQL, map);
    }
   
    /**
     * <p>Setup where clause.</p>
     *
     * @param conditionsSQL         a valid SQL query where clause string
     * @param conditionsSQLDataMap  a map of data for the keys in the <tt>conditionsSQL</tt> string
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder where(String conditionsSQL, Map<String, Object> conditionsSQLDataMap) {
    if (usedWhere)
      throw new RuntimeException("where() can only be called once.");
    usedWhere = true;
   
    this.conditionsSQL = conditionsSQL;
    this.conditionsSQLDataMap = conditionsSQLDataMap;
        return this;
    }
   
    /**
     * <p>Setup associated models for eager loading.</p>
     *
     * @param includes  a string of associated models
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder includes(String includes) {
    if (usedIncludes)
      throw new RuntimeException("includes() can only be called once.");
    usedIncludes = true;
   
    options.put(ActiveRecordConstants.key_include, includes);
    return this;
  }
   
    /**
     * <p>Setup associated models for eager loading.</p>
     *
     * @param includes  a string of associated models
     * @param joinType  type of join
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder includes(String includes, String joinType) {
    if (usedIncludes)
      throw new RuntimeException("includes() can only be called once.");
    usedIncludes = true;
   
    options.put(ActiveRecordConstants.key_include, includes);
    options.put(ActiveRecordConstants.key_join_type, joinType);
    return this;
  }
   
    /**
     * <p>Setup associated models for eager loading.</p>
     *
     * <p>If <tt>strict</tt> is true, then child records can only be accessed
     * through their parent.</p>
     *
     * @param includes  a string of associated models
     * @param strict    true if strict
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder includes(String includes, boolean strict) {
    if (usedIncludes)
      throw new RuntimeException("includes() can only be called once.");
    usedIncludes = true;
   
    if (strict) {
      options.put(ActiveRecordConstants.key_strict_include, includes);
    }
    else {
      options.put(ActiveRecordConstants.key_include, includes);
    }
    return this;
  }
   
    /**
     * <p>Setup group-by clause.</p>
     *
     * @param groupBy  a valid SQL query group-by clause string
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder groupBy(String groupBy) {
    if (usedGroupBy)
      throw new RuntimeException("groupBy() can only be called once.");
    usedGroupBy = true;
   
    options.put(SqlConstants.key_group_by, groupBy);
    return this;
  }
   
    /**
     * <p>Setup having clause.</p>
     *
     * @param having  a valid SQL query having clause string
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder having(String having) {
    if (usedHaving)
      throw new RuntimeException("having() can only be called once.");
    usedHaving = true;
   
    options.put(SqlConstants.key_having, having);
    return this;
  }
   
    /**
     * <p>Setup group-by clause.</p>
     *
     * @param orderBy  a valid SQL query order-by clause string
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder orderBy(String orderBy) {
    if (usedOrderBy)
      throw new RuntimeException("orderBy() can only be called once.");
    usedOrderBy = true;
   
    options.put(SqlConstants.key_order_by, orderBy);
    return this;
  }
   
    /**
     * <p>Setup limit for number of records per retrieval.</p>
     *
     * @param limit  number of records for each retrieval
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder limit(int limit) {
    if (usedLimit)
      throw new RuntimeException("limit() can only be called once.");
    usedLimit = true;
   
    options.put(ActiveRecordConstants.key_limit, limit + "");
    return this;
  }
   
    /**
     * <p>Setup number of records to skip.</p>
     *
     * @param offset  number of records to skip
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder offset(int offset) {
    if (usedOffset)
      throw new RuntimeException("offset() can only be called once.");
    usedOffset = true;
   
    options.put(ActiveRecordConstants.key_offset, offset + "");
    return this;
  }
   
    /**
     * <p>Setup current page number.
     * All records in previous pages are skipped.</p>
     *
     * <p>The first page is 1, not 0.</p>
     *
     * @param page  current page number
     * @return current <tt>QueryBuilder</tt> instance
     */
  public QueryBuilder page(int page) {
    if (usedPage)
      throw new RuntimeException("page() can only be called once.");
    usedPage = true;
   
    options.put(ActiveRecordConstants.key_page, page + "");
    return this;
  }
}
TOP

Related Classes of com.scooterframework.orm.activerecord.QueryBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.