package org.orienteer.core.component.table.filter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.orientechnologies.orient.core.db.ODatabase;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OProperty;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.orienteer.core.component.table.filter.sql.ODefaultQueryBuilder;
import org.orienteer.junit.GuiceRule;
import org.orienteer.junit.StaticInjectorProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.ydn.wicket.wicketorientdb.filter.IQueryBuilder;
import ru.ydn.wicket.wicketorientdb.model.OPropertyModel;
import ru.ydn.wicket.wicketorientdb.utils.DBClosure;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Vitaliy Gonchar
*/
public class OrienteerDefaultQueryBuilderTest {
private static final Logger LOG = LoggerFactory.getLogger(OrienteerDefaultQueryBuilderTest.class);
private static TestOClassManager manager;
private static FilterTest filterTest;
private static final String CLASS_NAME = "____OrienteerDefaultQueryBuilderTestClass____";
private static final int DOCUMENTS_NUM = 2;
private final Map<IModel<OProperty>, IModel<?>> filteredValues = Maps.newHashMap();
private final IQueryBuilder<ODocument> queryBuilder = new ODefaultQueryBuilder<>(CLASS_NAME);
static String dateFormat;
static String dateTimeFormat;
private static final String ORIENTEER_TEST_CLASS = "OModule";
@BeforeClass
public static void initialize() {
filterTest = new FilterTest();
manager = new TestOClassManager(CLASS_NAME, DOCUMENTS_NUM);
dateFormat = getDateFormat(OType.DATE);
dateTimeFormat = getDateFormat(OType.DATETIME);
}
@AfterClass
public static void clear() {
manager.deleteOClass();
}
@Test
@SuppressWarnings("unchecked")
public void testPrimitives() {
OClass testClass = manager.createAndGetOClassWithPrimitives();
clearAndInitFilteredValues(testClass);
List<String> stringFilters = manager.getSuccessStringFilters();
List<Number> numberFilters = manager.getSuccessNumberFilters();
List<Date> dateFilters = manager.getSuccessDateFilters();
IModel<String> stringModel = Model.of();
IModel<Number> numberModel = Model.of();
IModel<Boolean> booleanModel = Model.of();
for (IModel<OProperty> propertyModel : filteredValues.keySet()) {
OProperty property = propertyModel.getObject();
IModel<?> model = filteredValues.get(propertyModel);
String name = property.getName();
switch (property.getType()) {
case BOOLEAN:
testFilters(name, (IModel<Boolean>) model, Lists.newArrayList(true, false), OType.BOOLEAN,true);
model.setObject(null);
booleanModel = (IModel<Boolean>) model;
break;
case INTEGER:
case SHORT:
case BYTE:
case LONG:
case DECIMAL:
case FLOAT:
case DOUBLE:
testFilters(name, (IModel<Number>) model, numberFilters, OType.INTEGER,true);
testFilters(name, (IModel<Number>) model,
Lists.<Number>newArrayList(-1, -2, -100, 12345), OType.INTEGER,false);
model.setObject(null);
numberModel = (IModel<Number>) model;
break;
case DATE:
testFilters(name, (IModel<Date>) model, dateFilters, OType.DATE, true);
model.setObject(null);
break;
case DATETIME:
manager.showDocuments();
testFilters(name, (IModel<Date>) model, dateFilters, OType.DATETIME, true);
model.setObject(null);
break;
case STRING:
testFilters(name, (IModel<String>) model, stringFilters, OType.STRING,true);
testFilters(name, (IModel<String>) model, Lists.newArrayList("abcd", "asbcd%;sd", "1234"), OType.STRING,false);
model.setObject(null);
stringModel = (IModel<String>) model;
break;
case BINARY:
break;
}
}
numberModel.setObject(numberFilters.get(0));
booleanModel.setObject(true);
stringModel.setObject(stringFilters.get(0));
printODocuments(queryBuilder.build(filteredValues).getObject());
}
@Test
@Ignore
public void testEmbedded() {
OClass testClass = manager.createAndGetOClassWithEmbeded(ORIENTEER_TEST_CLASS);
Map<String, String> successEmbeddedString = manager.getSuccessEmbeddedString();
Map<String, Integer> successEmbeddedInteger = manager.getSuccessEmbeddedInteger();
Map<String, Boolean> successEmbeddedBoolean = manager.getSuccessEmbeddedBoolean();
}
private <V> void testFilters(String propertyName, IModel<V> model,
List<V> filters, OType type, boolean success) {
for (V filter : filters) {
model.setObject(filter);
List<ODocument> documents = queryBuilder.build(filteredValues).getObject();
assertEquals("Size of query documents", documents.size() > 0, success);
if (LOG.isDebugEnabled()) printODocuments(documents, filter);
switch (type) {
case STRING:
Pattern pattern = getPattern((String) filter);
assertStringPropertyByPattern(propertyName, pattern, documents);
break;
case INTEGER:
case SHORT:
case BYTE:
case LONG:
case DECIMAL:
case FLOAT:
case DOUBLE:
case BOOLEAN:
case DATE:
assertValueProperty(propertyName, filter, documents);
break;
}
}
}
private void assertStringPropertyByPattern(String propertyName, Pattern pattern, List<ODocument> documents) {
for (ODocument document : documents) {
String fieldString = document.field(propertyName);
boolean matches = pattern.matcher(fieldString).matches();
assertTrue("Assert string field = " + fieldString, matches);
}
}
private <V> void assertValueProperty(String propertyName, V value, List<ODocument> documents) {
for (ODocument document : documents) {
V fieldValue = document.field(propertyName);
if (value instanceof Number) {
Number fieldNumber = (Number) fieldValue;
Number valueNumber = (Number) value;
assertEquals(fieldNumber.doubleValue() == valueNumber.doubleValue(), true);
} else if (value instanceof Date) {
String format = document.fieldType(propertyName) == OType.DATE ? dateFormat : dateTimeFormat;
String fieldDate = getDateStringByFormat(format, (Date) fieldValue);
String valueDate = getDateStringByFormat(format, (Date) value);
assertEquals("Equals values: fieldValue=" + fieldDate + " requiredValue=" + valueDate, fieldDate, valueDate);
} else assertEquals("Equals values: fieldValue=" + fieldValue + " requiredValue=" + value, fieldValue, value);
}
}
private <V> void printODocuments(List<ODocument> documents, V filter) {
LOG.debug("Executed filter {} value={}, result documents:", filter.getClass(), filter);
printODocuments(documents);
}
private void printODocuments(List<ODocument> documents) {
for (ODocument document : documents) {
LOG.debug(document.toString());
}
}
private Pattern getPattern(String filter) {
Pattern result;
if (!filter.contains("%")) {
result = Pattern.compile(filter + "[^$]*");
} else {
String query = filter.replaceAll("%", "\\[\\^\\$\\]*");
result = Pattern.compile(query);
}
return result;
}
static class FilterTest extends GuiceRule {
public FilterTest() {
super(StaticInjectorProvider.INSTANCE);
}
}
private void clearAndInitFilteredValues(OClass filteredClass) {
filteredValues.clear();
for (OProperty property : filteredClass.properties()) {
filteredValues.put(new OPropertyModel(property), Model.of());
}
}
private String getDateStringByFormat(String dateFormat, Date date) {
SimpleDateFormat df = new SimpleDateFormat(dateFormat);
return df.format(date);
}
private static String getDateFormat(final OType type) {
return new DBClosure<String>() {
@Override
protected String execute(ODatabaseDocument db) {
String format = null;
if (type == OType.DATE) {
format = (String) db.get(ODatabase.ATTRIBUTES.DATEFORMAT);
} else if (type == OType.DATETIME) {
format = (String) db.get(ODatabase.ATTRIBUTES.DATETIMEFORMAT);
}
return format;
}
}.execute();
}
}