/*
* Copyright 2009-2011 Collaborative Research Centre SFB 632
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package annis.sqlgen;
import annis.model.QueryAnnotation;
import annis.model.QueryNode;
import annis.ql.parser.QueryData;
import static annis.test.TestUtils.uniqueInt;
import static annis.test.TestUtils.uniqueLong;
import static annis.test.TestUtils.uniqueString;
import com.google.common.collect.Lists;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.Bag;
import org.apache.commons.collections.bag.HashBag;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.BDDMockito.given;
import static org.mockito.MockitoAnnotations.initMocks;
import org.mockito.Spy;
public class TestAbstractFromClauseGenerator {
private AbstractFromClauseGenerator generator;
@Spy private TableAccessStrategy tableAccessStrategy = new TableAccessStrategy();
@Before
public void setup() {
initMocks(this);
generator = new AbstractFromClauseGenerator() {
@Override
public String fromClause(QueryData queryData, List<QueryNode> alternative,
String indent) {
throw new UnsupportedOperationException("This AbstractFromClauseGenerator is only used for testing purposes");
}
@Override
protected TableAccessStrategy createTableAccessStrategy() {
return tableAccessStrategy;
}
};
}
/**
* Create a table alias definition for a table that is only used once.
*/
@Test
public void shouldCreateTableAliasWithoutCount() {
// given
long id = uniqueLong();
QueryNode node = new QueryNode(id);
String table = uniqueString();
String tableAlias = uniqueString();
int count = 1;
Map<String, String> tableAliases = setupTableAliases(node, table, tableAlias, count);
TableAccessStrategy tas = new TableAccessStrategy(node);
tas.setTableAliases(tableAliases);
// when
String alias = AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, new LinkedList<Long>());
// then
String expected = tableAlias + " AS " + tableAlias + id;
assertThat(alias, is(expected));
}
/**
* Create a table alias definition for a table that is used multiple times.
*/
@Test
public void shouldCreateTableAliasWithCount() {
// given
long id = uniqueLong();
QueryNode node = new QueryNode(id);
String table = uniqueString();
String tableAlias = uniqueString();
int count = uniqueInt(2, 100);
Map<String, String> tableAliases = setupTableAliases(node, table, tableAlias, count);
TableAccessStrategy tas = new TableAccessStrategy(node);
tas.setTableAliases(tableAliases);
// when
String alias = AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, new LinkedList<Long>());
// then
String expected = tableAlias + " AS " + tableAlias + id + "_" + count;
assertThat(alias, is(expected));
}
@Test
public void shouldUsePartitions()
{
// given
long id = uniqueLong();
QueryNode node = new QueryNode(id);
String table = uniqueString();
String tableAlias = uniqueString();
int count = 1;
long corpusID = uniqueInt(0, Integer.MAX_VALUE);
List<Long> corpora = Lists.newArrayList(corpusID);
Map<String, String> tableAliases = setupTableAliases(node, table, tableAlias, count);
Map<String, Boolean> tablePartioned = new HashMap<>();
tablePartioned.put(table, Boolean.TRUE);
TableAccessStrategy tas = new TableAccessStrategy(node);
tas.setTableAliases(tableAliases);
tas.setTablePartitioned(tablePartioned);
// when
String alias = AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corpora);
// then
String expected = tableAlias + "_" + corpusID + " AS " + tableAlias + id;
assertThat(alias, is(expected));
}
@Test
public void shouldNotUsePartitions()
{
// given
long id = uniqueLong();
QueryNode node = new QueryNode(id);
String table = uniqueString();
String tableAlias = uniqueString();
int count = 1;
long corpusID = uniqueInt(0, Integer.MAX_VALUE);
List<Long> corporaNonEmpty = Lists.newArrayList(corpusID);
List<Long> multipleCorpora = Lists.newArrayList(uniqueLong(), corpusID, uniqueLong());
List<Long> corpusEmpty = new LinkedList<>();
Map<String, String> tableAliases = setupTableAliases(node, table, tableAlias, count);
Map<String, Boolean> tablePartioned = new HashMap<>();
tablePartioned.put(table, Boolean.TRUE);
TableAccessStrategy tas = new TableAccessStrategy(node);
tas.setTableAliases(tableAliases);
String expected = tableAlias + " AS " + tableAlias + id;
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corpusEmpty), is(expected));
// update the partion map to actually dis-allow partitions
tablePartioned.put(table, Boolean.FALSE);
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corporaNonEmpty),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corpusEmpty),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, multipleCorpora),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, null),
is(expected));
// remove the entry
tablePartioned.remove(table);
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corporaNonEmpty),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corpusEmpty),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, multipleCorpora),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, null),
is(expected));
// remove the whole object
tas.setTablePartitioned(null);
tablePartioned.remove(table);
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corporaNonEmpty),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, corpusEmpty),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, multipleCorpora),
is(expected));
assertThat(AbstractFromClauseGenerator.tableAliasDefinition(tas, node,
table, count, null),
is(expected));
}
// set up table access strategy to return the requested table alias
// simulate that count copies of the table (alias) are required
private Map<String, String> setupTableAliases(QueryNode node, String table, String tableAlias, int count)
{
HashMap<String, String> tableAliases = new HashMap<>();
tableAliases.put(table, tableAlias);
if(count > 0)
{
tableAliases.put(TableAccessStrategy.NODE_ANNOTATION_TABLE, tableAlias);
}
for(int i=0; i < count; i++)
{
// this will add new entries for the source tables
node.addNodeAnnotation(new QueryAnnotation("dummy", "dummy" + i));
}
tableAccessStrategy.setTableAliases(tableAliases);
tableAccessStrategy.setNode(node);
Bag tables = new HashBag();
tables.add(tableAlias, count);
given(tableAccessStrategy.computeSourceTables())
.willReturn(tables);
return tableAliases;
}
}