/** Simple test to confirm containers and joins can be added successfully to a query. */
  public void testContainersAndJoinsAddToQuery() throws Exception {
    Query query = new QueryImpl(new StubDatabaseMapping());
    ItemContainer container1 = new ItemContainer("Table 1");
    StringItem item1 = new StringItem("Column 1");
    container1.addItem(item1);
    query.addTable(container1);

    ItemContainer container2 = new ItemContainer("Table 2");
    StringItem item2 = new StringItem("Column 2");
    container2.addItem(item2);
    query.addTable(container2);

    ItemContainer container3 = new ItemContainer("Table 3");
    StringItem item3 = new StringItem("Column 3");
    container3.addItem(item3);
    query.addTable(container3);

    SQLJoin join1to2 = new SQLJoin(item1, item2);
    SQLJoin join2to3 = new SQLJoin(item2, item3);
    query.addJoin(join1to2);
    query.addJoin(join2to3);

    assertEquals(3, query.getFromTableList().size());
    assertTrue(query.getFromTableList().contains(container1));
    assertTrue(query.getFromTableList().contains(container2));
    assertTrue(query.getFromTableList().contains(container3));
    assertEquals(2, query.getJoins().size());
    assertTrue(query.getJoins().contains(join1to2));
    assertTrue(query.getJoins().contains(join2to3));
  }
 /**
  * Copy contructor, clones the state of a generic Query into a DefaultQuery
  *
  * @param query
  */
 public DefaultQuery(Query query) {
   this(
       query.getTypeName(),
       query.getNamespace(),
       query.getFilter(),
       query.getMaxFeatures(),
       query.getProperties(),
       query.getHandle());
   this.sortBy = query.getSortBy();
   this.coordinateSystem = query.getCoordinateSystem();
   this.coordinateSystemReproject = query.getCoordinateSystemReproject();
   this.version = query.getVersion();
   this.hints = query.getHints();
   this.startIndex = query.getStartIndex();
   this.alias = query.getAlias();
   this.joins = query.getJoins();
 }
  /**
   * Basic reset test.
   *
   * @throws Exception
   */
  public void testResetQuery() throws Exception {
    Query q = new QueryImpl(new StubDatabaseMapping());
    String startingWhereClause = q.getGlobalWhereClause();
    q.setGlobalWhereClause("something");
    boolean startingGroupingFlag = q.isGroupingEnabled();
    q.setGroupingEnabled(true);
    int startingZoomLevel = q.getZoomLevel();
    q.setZoomLevel(75);
    Container constantsContainer = q.getConstantsContainer();
    List<Item> constantItems = constantsContainer.getItems();
    constantsContainer.removeItem(0);
    constantsContainer.addItem(new StringItem("New Constant"));

    Container container1 = new ItemContainer("Container 1");
    Item item1 = new StringItem("Item 1");
    container1.addItem(item1);
    q.addTable(container1);
    Container container2 = new ItemContainer("Container 2");
    Item item2 = new StringItem("item 2");
    container2.addItem(item2);
    q.addTable(container2);
    q.selectItem(item1);
    q.selectItem(item2);
    q.orderColumn(item1, OrderByArgument.ASC);
    q.orderColumn(item2, OrderByArgument.DESC);
    SQLJoin join = new SQLJoin(item1, item2);
    q.addJoin(join);

    q.reset();
    assertEquals(startingZoomLevel, q.getZoomLevel());
    assertEquals(startingWhereClause, q.getGlobalWhereClause());
    assertEquals(startingGroupingFlag, q.isGroupingEnabled());

    Container resetConstants = q.getConstantsContainer();
    assertEquals(constantItems.size(), resetConstants.getItems().size());
    for (int i = 0; i < constantItems.size(); i++) {
      assertEquals(constantItems.get(i).getName(), resetConstants.getItems().get(i).getName());
    }

    assertTrue(q.getFromTableList().isEmpty());
    assertTrue(q.getJoins().isEmpty());
    assertTrue(q.getOrderByList().isEmpty());
    assertTrue(q.getSelectedColumns().isEmpty());
  }
  /**
   * Selects all entities of the specified type which match the given <code>Query</code>. This
   * method creates a <code>PreparedStatement</code> using the <code>Query</code> instance specified
   * against the table represented by the given type. This query is then executed (with the
   * parameters specified in the query). The method then iterates through the result set and
   * extracts the specified field, mapping an entity of the given type to each row. This array of
   * entities is returned.
   *
   * @param type The type of the entities to retrieve.
   * @param field The field value to use in the creation of the entities. This is usually the
   *     primary key field of the corresponding table.
   * @param query The {@link Query} instance to use in determining the results.
   * @return An array of entities of the given type which match the specified query.
   */
  public <T extends RawEntity<K>, K> T[] find(Class<T> type, String field, Query query)
      throws SQLException {
    List<T> back = new ArrayList<T>();

    query.resolveFields(type, getFieldNameConverter());

    // <ian>
    Version version = type.getAnnotation(Version.class);
    if (version != null && !version.findInitial()) {
      // Add initial version check to exclude
      // objects that have only been created and not saved yet.
      if (query.getWhereClause() == null) {
        query.where(version.value() + " != ?", version.initial());
      } else {
        // Preserve existing WHERE clause and parameters
        String whereClause =
            new StringBuilder()
                .append(query.getWhereClause())
                .append(" AND ")
                .append(version.value())
                .append(" != ?")
                .toString();
        Object[] paramsOld = query.getWhereParams();
        Object[] paramsNew = new Object[paramsOld.length + 1];
        System.arraycopy(paramsOld, 0, paramsNew, 0, paramsOld.length);
        paramsNew[paramsNew.length - 1] = version.initial();
        query.setWhereClause(whereClause);
        query.setWhereParams(paramsNew);
      }
    }
    // </ian>

    Preload preloadAnnotation = type.getAnnotation(Preload.class);
    if (preloadAnnotation != null) {
      if (!query.getFields()[0].equals("*") && query.getJoins().isEmpty()) {
        String[] oldFields = query.getFields();
        List<String> newFields = new ArrayList<String>();

        for (String newField : preloadAnnotation.value()) {
          newField = newField.trim();

          int fieldLoc = -1;
          for (int i = 0; i < oldFields.length; i++) {
            if (oldFields[i].equals(newField)) {
              fieldLoc = i;
              break;
            }
          }

          if (fieldLoc < 0) {
            newFields.add(newField);
          } else {
            newFields.add(oldFields[fieldLoc]);
          }
        }

        if (!newFields.contains("*")) {
          for (String oldField : oldFields) {
            if (!newFields.contains(oldField)) {
              newFields.add(oldField);
            }
          }
        }

        query.setFields(newFields.toArray(new String[newFields.size()]));
      }
    }

    Connection conn = getProvider().getConnection();
    try {
      String sql = null;
      tableNameConverterLock.readLock().lock();
      try {
        sql = query.toSQL(type, provider, tableNameConverter, getFieldNameConverter(), false);
      } finally {
        tableNameConverterLock.readLock().unlock();
      }

      Logger.getLogger("net.java.ao").log(Level.INFO, sql);
      PreparedStatement stmt =
          conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      provider.setQueryStatementProperties(stmt, query);

      query.setParameters(this, stmt);

      ResultSet res = stmt.executeQuery();
      provider.setQueryResultSetProperties(res, query);

      while (res.next()) {
        T entity =
            peer(
                type,
                Common.getPrimaryKeyType(type)
                    .pullFromDatabase(this, res, Common.getPrimaryKeyClassType(type), field));
        CacheLayer cacheLayer = getProxyForEntity(entity).getCacheLayer(entity);

        for (String cacheField : query.getCanonicalFields(type, fieldNameConverter)) {
          cacheLayer.put(cacheField, res.getObject(cacheField));
        }

        back.add(entity);
      }
      res.close();
      stmt.close();
    } finally {
      conn.close();
    }

    return back.toArray((T[]) Array.newInstance(type, back.size()));
  }