private void appendJoinsAndWheres(StringBuilder builder, String tablePrefixOrNull) {
   values.clear();
   for (Join<T, ?> join : joins) {
     builder.append(" JOIN ").append(join.daoDestination.getTablename()).append(' ');
     builder.append(join.tablePrefix).append(" ON ");
     SqlUtils.appendProperty(builder, join.sourceTablePrefix, join.joinPropertySource).append('=');
     SqlUtils.appendProperty(builder, join.tablePrefix, join.joinPropertyDestination);
   }
   boolean whereAppended = !whereCollector.isEmpty();
   if (whereAppended) {
     builder.append(" WHERE ");
     whereCollector.appendWhereClause(builder, tablePrefixOrNull, values);
   }
   for (Join<T, ?> join : joins) {
     if (!join.whereCollector.isEmpty()) {
       if (!whereAppended) {
         builder.append(" WHERE ");
         whereAppended = true;
       } else {
         builder.append(" AND ");
       }
       join.whereCollector.appendWhereClause(builder, join.tablePrefix, values);
     }
   }
 }
  /**
   * Builds a reusable query object for counting rows (Query objects can be executed more
   * efficiently than creating a QueryBuilder for each execution.
   */
  public CountQuery<T> buildCount() {
    String tablename = dao.getTablename();
    String baseSql = SqlUtils.createSqlSelectCountStar(tablename, tablePrefix);
    StringBuilder builder = new StringBuilder(baseSql);
    appendJoinsAndWheres(builder, tablePrefix);

    String sql = builder.toString();
    checkLog(sql);

    return CountQuery.create(dao, sql, values.toArray());
  }
  private StringBuilder createSelectBuilder() {
    String select =
        SqlUtils.createSqlSelect(dao.getTablename(), tablePrefix, dao.getAllColumns(), distinct);
    StringBuilder builder = new StringBuilder(select);

    appendJoinsAndWheres(builder, tablePrefix);

    if (orderBuilder != null && orderBuilder.length() > 0) {
      builder.append(" ORDER BY ").append(orderBuilder);
    }
    return builder;
  }
  /**
   * Builds a reusable query object for deletion (Query objects can be executed more efficiently
   * than creating a QueryBuilder for each execution.
   */
  public DeleteQuery<T> buildDelete() {
    if (!joins.isEmpty()) {
      throw new DaoException("JOINs are not supported for DELETE queries");
    }
    String tablename = dao.getTablename();
    String baseSql = SqlUtils.createSqlDelete(tablename, null);
    StringBuilder builder = new StringBuilder(baseSql);

    // tablePrefix gets replaced by table name below. Don't use tableName here because it causes
    // trouble when
    // table name ends with tablePrefix.
    appendJoinsAndWheres(builder, tablePrefix);

    String sql = builder.toString();
    // Remove table aliases, not supported for DELETE queries.
    // TODO(?): don't create table aliases in the first place.
    sql = sql.replace(tablePrefix + ".\"", '"' + tablename + "\".\"");
    checkLog(sql);

    return DeleteQuery.create(dao, sql, values.toArray());
  }