Finished draft implementation with some TODO's left
This commit is contained in:
parent
063f94e382
commit
5e2a797b17
|
@ -19,25 +19,26 @@ public class CompiledStatement {
|
||||||
// the decision tree as defined in the WHERE clause
|
// the decision tree as defined in the WHERE clause
|
||||||
WhereExpression whereExpression;
|
WhereExpression whereExpression;
|
||||||
|
|
||||||
// the expression evaluating to the selected objects according to the SELECT
|
// the expression evaluating to the selected objects according to the SELECT clause
|
||||||
// clause
|
|
||||||
public SelectClause selectClause;
|
public SelectClause selectClause;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
* @param inputObjects
|
||||||
|
* @param queryParameter
|
||||||
*
|
*
|
||||||
* @return List of objects resulting from running the compiled code
|
* @return List of objects resulting from running the compiled code
|
||||||
*/
|
*/
|
||||||
public List<Object> evaluate(Map<String, Object> inputObjects, Map<String, Object> injectedObjects) {
|
public List<Object> evaluate(final Map<String, Object> inputObjects, final Map<String, Object> queryParameter) {
|
||||||
|
|
||||||
boolean evaluateWhereExpression = true;
|
boolean evaluateWhereExpression = true;
|
||||||
if (whereExpression != null) {
|
if (whereExpression != null)
|
||||||
evaluateWhereExpression = whereExpression.evaluate(inputObjects, injectedObjects);
|
evaluateWhereExpression = whereExpression.evaluate(inputObjects, queryParameter);
|
||||||
}
|
|
||||||
|
|
||||||
if (evaluateWhereExpression) {
|
if (evaluateWhereExpression)
|
||||||
return selectClause.evaluate(inputObjects, injectedObjects);
|
return selectClause.evaluate(inputObjects, queryParameter);
|
||||||
}
|
|
||||||
|
|
||||||
|
// else return empty list
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterator used to build the cartesian product defined in the FROM clause
|
||||||
|
*/
|
||||||
|
public class IndexPointer implements Iterator {
|
||||||
|
|
||||||
|
final int[] numberOfEntities;
|
||||||
|
final int[] pointer;
|
||||||
|
|
||||||
|
public IndexPointer(int[] numberOfEntities) {
|
||||||
|
this.numberOfEntities = numberOfEntities;
|
||||||
|
this.pointer = new int[numberOfEntities.length];
|
||||||
|
this.pointer[pointer.length-1]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] next() {
|
||||||
|
pointer[pointer.length - 1]++;
|
||||||
|
normalize();
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
for (int i = 0; i < pointer.length; i++) {
|
||||||
|
if (pointer[i] < numberOfEntities[i] - 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalize() {
|
||||||
|
for (int i = pointer.length - 1; i >= 0; i--) {
|
||||||
|
if (pointer[i] == numberOfEntities[i]) {
|
||||||
|
pointer[i] = 0;
|
||||||
|
pointer[i - 1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
|
import li.strolch.model.StrolchRootElement;
|
||||||
|
import li.strolch.model.query.ActivityQuery;
|
||||||
|
import li.strolch.model.query.OrderQuery;
|
||||||
|
import li.strolch.model.query.ResourceQuery;
|
||||||
|
import li.strolch.model.query.StrolchElementQuery;
|
||||||
|
import li.strolch.soql.antlr4.generated.SOQLLexer;
|
||||||
|
import li.strolch.soql.antlr4.generated.SOQLParser;
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main class to process a SOQL query. It performs the queries to retrieve the
|
||||||
|
* input objects as defined in the FROM clause and evaluates the compiled
|
||||||
|
* statement on any cartesian product, returning the objects defined in the
|
||||||
|
* SELECT clause.
|
||||||
|
*
|
||||||
|
* @author msmock
|
||||||
|
*/
|
||||||
|
public class QueryProcessor {
|
||||||
|
|
||||||
|
// Map of queries to retrieve the input objects
|
||||||
|
protected Map<String, StrolchElementQuery> queries;
|
||||||
|
|
||||||
|
// Map of entities the input objects are taken from
|
||||||
|
protected Map<String, List<StrolchRootElement>> inputCollections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* empty constructor
|
||||||
|
*/
|
||||||
|
public QueryProcessor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the input map of collections to take the input objects from. For testing
|
||||||
|
* purposes only.
|
||||||
|
*
|
||||||
|
* @param inputCollections
|
||||||
|
*/
|
||||||
|
void setInputCollections(Map<String, List<StrolchRootElement>> inputCollections) {
|
||||||
|
this.inputCollections = inputCollections;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param request
|
||||||
|
* @return the query response object covering the result set
|
||||||
|
*/
|
||||||
|
public QueryResponse process(QueryRequest request) {
|
||||||
|
|
||||||
|
String statement = request.getStatement();
|
||||||
|
|
||||||
|
CompiledStatement compiledStatement = null;
|
||||||
|
try {
|
||||||
|
ParseTree tree = parseStatement(statement);
|
||||||
|
compiledStatement = compile(tree);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO add error handling
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new SOQLParseException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the input collections, if not set already
|
||||||
|
if (inputCollections == null) {
|
||||||
|
queries = entity2Query(compiledStatement.entities);
|
||||||
|
// TODO perform the queries
|
||||||
|
}
|
||||||
|
|
||||||
|
// build cartesian product
|
||||||
|
Object[] keys = inputCollections.keySet().toArray();
|
||||||
|
List<List<StrolchRootElement>> cartesianProduct = buildCartesianProduct(inputCollections, keys);
|
||||||
|
|
||||||
|
ResultSet resultSet = new ResultSet();
|
||||||
|
|
||||||
|
// apply the compiled statement to any row of the cartesian product
|
||||||
|
for (List<StrolchRootElement> row : cartesianProduct) {
|
||||||
|
Map<String, Object> inputObjects = new HashMap<>();
|
||||||
|
for (int i = 0; i < row.size(); i++) {
|
||||||
|
inputObjects.put((String) keys[i], row.get(i));
|
||||||
|
}
|
||||||
|
List<Object> resultRow = compiledStatement.evaluate(inputObjects, request.getParameter());
|
||||||
|
|
||||||
|
if (!resultRow.isEmpty())
|
||||||
|
resultSet.add(resultRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResponse response = new QueryResponse();
|
||||||
|
response.setStatement(statement);
|
||||||
|
response.setParameter(request.getParameter());
|
||||||
|
response.setResultSet(resultSet);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param inputCollections
|
||||||
|
* @param keys
|
||||||
|
* @return List of Lists of the elements to be taken as input for the compiled statement
|
||||||
|
*/
|
||||||
|
private List<List<StrolchRootElement>> buildCartesianProduct(Map<String, List<StrolchRootElement>> inputCollections, Object[] keys) {
|
||||||
|
|
||||||
|
int numberOfKeys = keys.length;
|
||||||
|
|
||||||
|
// get an overview of how many elements we have to take into account
|
||||||
|
int[] numberOfEntities = new int[numberOfKeys];
|
||||||
|
for (int keyIndex = 0; keyIndex < numberOfKeys; keyIndex++) {
|
||||||
|
numberOfEntities[keyIndex] = inputCollections.get(keys[keyIndex]).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// build cartesian product
|
||||||
|
List<List<StrolchRootElement>> cartesianProduct = new ArrayList<>();
|
||||||
|
IndexPointer indexPointer = new IndexPointer(numberOfEntities);
|
||||||
|
while (indexPointer.hasNext()) {
|
||||||
|
|
||||||
|
List<StrolchRootElement> row = new ArrayList<>();
|
||||||
|
cartesianProduct.add(row);
|
||||||
|
|
||||||
|
int[] pointer = indexPointer.next();
|
||||||
|
|
||||||
|
// fasten your seat belts, here we go
|
||||||
|
for (int keyIndex = 0; keyIndex < numberOfKeys; keyIndex++) {
|
||||||
|
Object key = keys[keyIndex];
|
||||||
|
List<StrolchRootElement> elements = inputCollections.get(key);
|
||||||
|
StrolchRootElement element = elements.get(pointer[keyIndex]);
|
||||||
|
row.add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cartesianProduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse the string and return the antlr tree
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
ParseTree parseStatement(String s) throws Exception {
|
||||||
|
|
||||||
|
// build a buffer of tokens pulled from the lexer
|
||||||
|
CharStream input = CharStreams.fromString(s);
|
||||||
|
SOQLLexer lexer = new SOQLLexer(input);
|
||||||
|
|
||||||
|
// build a parser that feeds off the tokens buffer
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
|
SOQLParser parser = new SOQLParser(tokens);
|
||||||
|
parser.addErrorListener(new VerboseListener());
|
||||||
|
|
||||||
|
return parser.select_statement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compile the antlr tree to executeable code
|
||||||
|
*
|
||||||
|
* @param tree
|
||||||
|
* @return CompiledSOQLStatement
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
CompiledStatement compile(ParseTree tree) throws Exception {
|
||||||
|
|
||||||
|
ParseTreeWalker walker = new ParseTreeWalker();
|
||||||
|
SOQLListener listener = new SOQLListener();
|
||||||
|
walker.walk(listener, tree);
|
||||||
|
|
||||||
|
CompiledStatement soqlStatement = new CompiledStatement();
|
||||||
|
soqlStatement.entities = listener.getEntities();
|
||||||
|
soqlStatement.whereExpression = listener.getWhereExpression();
|
||||||
|
soqlStatement.selectClause = listener.getSelectClause();
|
||||||
|
|
||||||
|
return soqlStatement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the entities extracted from the FROM clause to the
|
||||||
|
* StrolchElementQuery to be performed to retrieve the input objects.
|
||||||
|
*
|
||||||
|
* @param entities
|
||||||
|
* @return Map of queries for the entities defining the objects returned
|
||||||
|
*/
|
||||||
|
Map<String, StrolchElementQuery> entity2Query(Map<String, String> entities) {
|
||||||
|
|
||||||
|
Map<String, StrolchElementQuery> result = new HashMap<>();
|
||||||
|
|
||||||
|
Set<String> keys = entities.keySet();
|
||||||
|
for (String key : keys) {
|
||||||
|
String clazzKey = entities.get(key);
|
||||||
|
|
||||||
|
switch (clazzKey) {
|
||||||
|
case "Resource":
|
||||||
|
result.put(key, new ResourceQuery());
|
||||||
|
break;
|
||||||
|
case "Order":
|
||||||
|
result.put(key, new OrderQuery());
|
||||||
|
break;
|
||||||
|
case "Activity":
|
||||||
|
result.put(key, new ActivityQuery());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
String s = "Unable to resolve " + clazzKey + " to strolch entity query.";
|
||||||
|
throw new SOQLParseException(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,13 +15,13 @@ import java.util.Set;
|
||||||
public class QueryRequest {
|
public class QueryRequest {
|
||||||
|
|
||||||
public static final String STATEMENT = "statement";
|
public static final String STATEMENT = "statement";
|
||||||
public static final String PARAMETER = "parameter";
|
public static final String PARAMETER = "queryParameter";
|
||||||
|
|
||||||
// the SOQL query string
|
// the SOQL query string
|
||||||
private String statement;
|
String statement;
|
||||||
|
|
||||||
// the parameter of the SOQL query
|
// the parameter of the SOQL query
|
||||||
private Map<String, String> parameter = new HashMap<>();
|
Map<String, Object> parameter = new HashMap<>();
|
||||||
|
|
||||||
public String getStatement() {
|
public String getStatement() {
|
||||||
return statement;
|
return statement;
|
||||||
|
@ -31,26 +31,30 @@ public class QueryRequest {
|
||||||
this.statement = statement;
|
this.statement = statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getParameter() {
|
public Map<String, Object> getParameter() {
|
||||||
return parameter;
|
return parameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setParameter(Map<String, Object> parameter) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the query as JsonObject
|
* @return the query as JsonObject
|
||||||
*/
|
*/
|
||||||
public JsonObject asJson() {
|
public JsonObject asJson() {
|
||||||
|
|
||||||
final JsonObject rootJ = new JsonObject();
|
JsonObject rootJ = new JsonObject();
|
||||||
rootJ.addProperty(Tags.Json.OBJECT_TYPE, "QueryRequest");
|
rootJ.addProperty(Tags.Json.OBJECT_TYPE, "QueryRequest");
|
||||||
rootJ.addProperty(STATEMENT, statement);
|
rootJ.addProperty(STATEMENT, statement);
|
||||||
|
|
||||||
final JsonObject parameterJ = new JsonObject();
|
JsonObject parameterJ = new JsonObject();
|
||||||
rootJ.add(PARAMETER, parameterJ);
|
rootJ.add(PARAMETER, parameterJ);
|
||||||
|
|
||||||
final Set<String> keys = parameter.keySet();
|
Set<String> keys = parameter.keySet();
|
||||||
for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
|
for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
|
||||||
final String key = iterator.next();
|
String key = iterator.next();
|
||||||
final Object param = parameter.get(key);
|
Object param = parameter.get(key);
|
||||||
parameterJ.addProperty(key, param.toString());
|
parameterJ.addProperty(key, param.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,12 +68,12 @@ public class QueryRequest {
|
||||||
*/
|
*/
|
||||||
public QueryRequest fromJson(JsonObject jsonObject) {
|
public QueryRequest fromJson(JsonObject jsonObject) {
|
||||||
|
|
||||||
final String statement = jsonObject.get(STATEMENT).getAsString();
|
String statement = jsonObject.get(STATEMENT).getAsString();
|
||||||
setStatement(statement);
|
setStatement(statement);
|
||||||
|
|
||||||
final JsonObject params = jsonObject.getAsJsonObject(PARAMETER);
|
JsonObject params = jsonObject.getAsJsonObject(PARAMETER);
|
||||||
final Set<Map.Entry<String, JsonElement>> entrySet = params.entrySet();
|
Set<Map.Entry<String, JsonElement>> entrySet = params.entrySet();
|
||||||
for (final Map.Entry<String, JsonElement> entry : entrySet) {
|
for (Map.Entry<String, JsonElement> entry : entrySet) {
|
||||||
parameter.put(entry.getKey(), entry.getValue().getAsString());
|
parameter.put(entry.getKey(), entry.getValue().getAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,33 +2,48 @@ package li.strolch.soql.core;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import li.strolch.model.Tags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author msmock
|
* @author msmock
|
||||||
*/
|
*/
|
||||||
public class QueryResponse extends QueryRequest {
|
public class QueryResponse extends QueryRequest {
|
||||||
|
|
||||||
// the returned objects
|
|
||||||
static final String RESULT_SET = "resultSet";
|
static final String RESULT_SET = "resultSet";
|
||||||
|
|
||||||
// an exception or error message in case of error
|
// an exception or error message in case of error
|
||||||
public String message;
|
public String message;
|
||||||
|
|
||||||
//
|
// the returned objects
|
||||||
public final ResultSet resultSet = new ResultSet();
|
public ResultSet resultSet = new ResultSet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resultSet the resultSet to set
|
||||||
|
*/
|
||||||
|
public void setResultSet(ResultSet resultSet) {
|
||||||
|
this.resultSet = resultSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the resultSet
|
||||||
|
*/
|
||||||
|
public ResultSet getResultSet() {
|
||||||
|
return resultSet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the query as JsonObject
|
* @return the query as JsonObject
|
||||||
*/
|
*/
|
||||||
public JsonObject asJson() {
|
public JsonObject asJson() {
|
||||||
|
|
||||||
final JsonObject rootJ = super.asJson();
|
JsonObject rootJ = super.asJson();
|
||||||
|
rootJ.addProperty(Tags.Json.OBJECT_TYPE, "QueryResponse");
|
||||||
|
|
||||||
if (message != null && !message.isEmpty()) {
|
if (message != null && !message.isEmpty()) {
|
||||||
rootJ.addProperty("Message", message);
|
rootJ.addProperty("Message", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
rootJ.add(RESULT_SET, resultSet.asJson());
|
rootJ.add(RESULT_SET, resultSet.asJson());
|
||||||
|
|
||||||
return rootJ;
|
return rootJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
package li.strolch.soql.core;
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import li.strolch.model.StrolchRootElement;
|
|
||||||
import li.strolch.model.json.StrolchElementToJsonVisitor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
|
||||||
|
import li.strolch.model.StrolchRootElement;
|
||||||
|
import li.strolch.model.json.StrolchElementToJsonVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The query result set as List of Lists
|
* The query result set as List of Lists
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* TODO: the result set should carry arbitrary objects, not only StrolchRootElements
|
* TODO: the result set should carry arbitrary objects, not only
|
||||||
|
* StrolchRootElements
|
||||||
*
|
*
|
||||||
* @author msmock
|
* @author msmock
|
||||||
*/
|
*/
|
||||||
|
@ -23,10 +26,22 @@ public class ResultSet {
|
||||||
public final List<List<StrolchRootElement>> rows = new ArrayList<>();
|
public final List<List<StrolchRootElement>> rows = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param row the result of the execution of a single statement
|
* @param row
|
||||||
|
* the result of the execution of a single statement
|
||||||
*/
|
*/
|
||||||
public void add(final List<StrolchRootElement> row) {
|
public void add(final List<Object> row) {
|
||||||
rows.add(row);
|
|
||||||
|
List<StrolchRootElement> toBeAdded = new LinkedList<>();
|
||||||
|
for (Object object : row) {
|
||||||
|
if (object instanceof StrolchRootElement) {
|
||||||
|
toBeAdded.add((StrolchRootElement) object);
|
||||||
|
} else {
|
||||||
|
System.out.println("Could not add object " + object + " of class " + object.getClass()
|
||||||
|
+ " to result set. Only StrolchRootElements are supported yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.add(toBeAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,7 +49,7 @@ public class ResultSet {
|
||||||
*/
|
*/
|
||||||
public JsonArray asJson() {
|
public JsonArray asJson() {
|
||||||
|
|
||||||
final JsonArray rowsAsJson = new JsonArray();
|
JsonArray rowsAsJson = new JsonArray();
|
||||||
|
|
||||||
for (Iterator<List<StrolchRootElement>> rowsIter = rows.iterator(); rowsIter.hasNext();)
|
for (Iterator<List<StrolchRootElement>> rowsIter = rows.iterator(); rowsIter.hasNext();)
|
||||||
rowsAsJson.add(row2Json(rowsIter.next()));
|
rowsAsJson.add(row2Json(rowsIter.next()));
|
||||||
|
@ -46,7 +61,7 @@ public class ResultSet {
|
||||||
* @return a single row as JSON Array
|
* @return a single row as JSON Array
|
||||||
*/
|
*/
|
||||||
private JsonArray row2Json(final List<StrolchRootElement> evalResult) {
|
private JsonArray row2Json(final List<StrolchRootElement> evalResult) {
|
||||||
final JsonArray rowAsJson = new JsonArray();
|
JsonArray rowAsJson = new JsonArray();
|
||||||
for (Iterator<StrolchRootElement> iterator = evalResult.iterator(); iterator.hasNext();) {
|
for (Iterator<StrolchRootElement> iterator = evalResult.iterator(); iterator.hasNext();) {
|
||||||
rowAsJson.add(iterator.next().accept(visitor));
|
rowAsJson.add(iterator.next().accept(visitor));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
package li.strolch.soql.core;
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
import li.strolch.model.*;
|
import java.util.ArrayList;
|
||||||
import li.strolch.model.parameter.FloatParameter;
|
import java.util.Date;
|
||||||
import li.strolch.model.parameter.Parameter;
|
import java.util.List;
|
||||||
import li.strolch.model.query.ActivityQuery;
|
|
||||||
import li.strolch.model.query.OrderQuery;
|
|
||||||
import li.strolch.model.query.ResourceQuery;
|
|
||||||
import li.strolch.model.query.StrolchElementQuery;
|
|
||||||
import li.strolch.soql.antlr4.generated.SOQLLexer;
|
|
||||||
import li.strolch.soql.antlr4.generated.SOQLParser;
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
import org.antlr.v4.runtime.CharStream;
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.*;
|
import li.strolch.model.Order;
|
||||||
|
import li.strolch.model.ParameterBag;
|
||||||
import static org.junit.Assert.assertEquals;
|
import li.strolch.model.Resource;
|
||||||
import static org.junit.Assert.assertTrue;
|
import li.strolch.model.State;
|
||||||
|
import li.strolch.model.StrolchRootElement;
|
||||||
|
import li.strolch.model.activity.Activity;
|
||||||
|
import li.strolch.model.parameter.FloatParameter;
|
||||||
|
import li.strolch.model.parameter.Parameter;
|
||||||
|
import li.strolch.soql.antlr4.generated.SOQLLexer;
|
||||||
|
import li.strolch.soql.antlr4.generated.SOQLParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author msmock
|
* @author msmock
|
||||||
|
@ -36,7 +36,8 @@ public abstract class BaseTest {
|
||||||
final CharStream input = CharStreams.fromString(s);
|
final CharStream input = CharStreams.fromString(s);
|
||||||
final SOQLLexer lexer = new SOQLLexer(input); // create a buffer of tokens pulled from the lexer
|
final SOQLLexer lexer = new SOQLLexer(input); // create a buffer of tokens pulled from the lexer
|
||||||
|
|
||||||
final CommonTokenStream tokens = new CommonTokenStream(lexer); // create a parser that feeds off the tokens buffer
|
final CommonTokenStream tokens = new CommonTokenStream(lexer); // create a parser that feeds off the tokens
|
||||||
|
// buffer
|
||||||
final SOQLParser parser = new SOQLParser(tokens);
|
final SOQLParser parser = new SOQLParser(tokens);
|
||||||
parser.addErrorListener(new VerboseListener());
|
parser.addErrorListener(new VerboseListener());
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ public abstract class BaseTest {
|
||||||
bag.setId("testBag");
|
bag.setId("testBag");
|
||||||
resource.addParameterBag(bag);
|
resource.addParameterBag(bag);
|
||||||
|
|
||||||
final Parameter parameter = new FloatParameter();
|
final Parameter<Double> parameter = new FloatParameter();
|
||||||
parameter.setId("testId");
|
parameter.setId("testId");
|
||||||
parameter.setValue(100d);
|
parameter.setValue(100d);
|
||||||
|
|
||||||
|
@ -90,15 +91,18 @@ public abstract class BaseTest {
|
||||||
/**
|
/**
|
||||||
* @return a test order
|
* @return a test order
|
||||||
*/
|
*/
|
||||||
StrolchRootElement getTestOrder(final String id) {
|
StrolchRootElement getTestOrder(String id) {
|
||||||
final Order order = new Order();
|
Order order = new Order();
|
||||||
order.setId("testId");
|
order.setId(id);
|
||||||
|
order.setState(State.CREATED);
|
||||||
|
|
||||||
final ParameterBag bag = new ParameterBag();
|
order.setDate(new Date());
|
||||||
|
|
||||||
|
ParameterBag bag = new ParameterBag();
|
||||||
bag.setId("testBag");
|
bag.setId("testBag");
|
||||||
order.addParameterBag(bag);
|
order.addParameterBag(bag);
|
||||||
|
|
||||||
final Parameter parameter = new FloatParameter();
|
Parameter<Double> parameter = new FloatParameter();
|
||||||
parameter.setId("testId");
|
parameter.setId("testId");
|
||||||
parameter.setValue(100d);
|
parameter.setValue(100d);
|
||||||
|
|
||||||
|
@ -106,10 +110,29 @@ public abstract class BaseTest {
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a test order
|
||||||
|
*/
|
||||||
|
StrolchRootElement getTestActivity(final String id) {
|
||||||
|
final Activity activity = new Activity();
|
||||||
|
activity.setId(id);
|
||||||
|
|
||||||
|
final ParameterBag bag = new ParameterBag();
|
||||||
|
bag.setId("testBag");
|
||||||
|
activity.addParameterBag(bag);
|
||||||
|
|
||||||
|
final Parameter<Double> parameter = new FloatParameter();
|
||||||
|
parameter.setId("testId");
|
||||||
|
parameter.setValue(100d);
|
||||||
|
|
||||||
|
activity.addParameter("testBag", parameter);
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
|
||||||
List<StrolchRootElement> getTestRessources(int n) {
|
List<StrolchRootElement> getTestRessources(int n) {
|
||||||
final List<StrolchRootElement> result = new ArrayList<>(n);
|
final List<StrolchRootElement> result = new ArrayList<>(n);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
result.add(getTestResource(String.valueOf(n)));
|
result.add(getTestResource(String.valueOf(i)));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +140,15 @@ public abstract class BaseTest {
|
||||||
List<StrolchRootElement> getTestOrders(int n) {
|
List<StrolchRootElement> getTestOrders(int n) {
|
||||||
final List<StrolchRootElement> result = new ArrayList<>(n);
|
final List<StrolchRootElement> result = new ArrayList<>(n);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
result.add(getTestOrder(String.valueOf(n)));
|
result.add(getTestOrder(String.valueOf(i)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StrolchRootElement> getTestActivities(int n) {
|
||||||
|
final List<StrolchRootElement> result = new ArrayList<>(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
result.add(getTestActivity(String.valueOf(i)));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
|
import li.strolch.model.StrolchRootElement;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DataStructureTest extends BaseTest {
|
||||||
|
|
||||||
|
Map<String, List<StrolchRootElement>> structure;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
structure = new LinkedHashMap<>();
|
||||||
|
structure.put("r", getTestRessources(6));
|
||||||
|
structure.put("o", getTestOrders(3));
|
||||||
|
structure.put("a", getTestActivities(4));
|
||||||
|
// System.out.println(structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildProduct() {
|
||||||
|
|
||||||
|
// it's ugly indexing stuff, so here we go
|
||||||
|
final Object[] keys = structure.keySet().toArray(); // TODO the nickname of the entities
|
||||||
|
final int numberOfKeys = keys.length;
|
||||||
|
|
||||||
|
// get an overview of how many elements we have to take into account
|
||||||
|
final int[] numberOfEntities = new int[numberOfKeys];
|
||||||
|
for (int keyIndex = 0; keyIndex < numberOfKeys; keyIndex++) {
|
||||||
|
numberOfEntities[keyIndex] = structure.get(keys[keyIndex]).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// build cartesian product
|
||||||
|
final List<List<StrolchRootElement>> cartesianProduct = new ArrayList<>();
|
||||||
|
final IndexPointer indexPointer = new IndexPointer(numberOfEntities);
|
||||||
|
while(indexPointer.hasNext()){
|
||||||
|
|
||||||
|
final List<StrolchRootElement> row = new ArrayList<>();
|
||||||
|
cartesianProduct.add(row);
|
||||||
|
|
||||||
|
int[] pointer = indexPointer.next();
|
||||||
|
|
||||||
|
// fasten your seat belts, here we go
|
||||||
|
for (int keyIndex = 0; keyIndex < numberOfKeys; keyIndex++) {
|
||||||
|
final Object key = keys[keyIndex];
|
||||||
|
final List<StrolchRootElement> elements = structure.get(key);
|
||||||
|
final StrolchRootElement element = elements.get(pointer[keyIndex]);
|
||||||
|
row.add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,23 +1,21 @@
|
||||||
package li.strolch.soql.core;
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import li.strolch.model.ParameterBag;
|
import li.strolch.model.ParameterBag;
|
||||||
import li.strolch.model.Resource;
|
import li.strolch.model.Resource;
|
||||||
import li.strolch.model.StrolchElement;
|
|
||||||
import li.strolch.model.StrolchRootElement;
|
import li.strolch.model.StrolchRootElement;
|
||||||
import li.strolch.model.json.StrolchElementToJsonVisitor;
|
|
||||||
import li.strolch.model.parameter.Parameter;
|
import li.strolch.model.parameter.Parameter;
|
||||||
import li.strolch.model.parameter.StringParameter;
|
import li.strolch.model.parameter.StringParameter;
|
||||||
import li.strolch.soql.core.expresssion.ChainedMethodExpression;
|
import li.strolch.soql.core.expresssion.ChainedMethodExpression;
|
||||||
import li.strolch.soql.core.expresssion.MethodArgumentDeclaration;
|
import li.strolch.soql.core.expresssion.MethodArgumentDeclaration;
|
||||||
import li.strolch.soql.core.expresssion.MethodExpression;
|
import li.strolch.soql.core.expresssion.MethodExpression;
|
||||||
import li.strolch.soql.core.expresssion.ParameterReference;
|
import li.strolch.soql.core.expresssion.ParameterReference;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author msmock
|
* @author msmock
|
||||||
|
@ -32,7 +30,7 @@ public class MethodExpressionTest {
|
||||||
bag.setId("testBag");
|
bag.setId("testBag");
|
||||||
resource.addParameterBag(bag);
|
resource.addParameterBag(bag);
|
||||||
|
|
||||||
final Parameter parameter = new StringParameter();
|
final Parameter<String> parameter = new StringParameter();
|
||||||
parameter.setId("testId");
|
parameter.setId("testId");
|
||||||
parameter.setValue("testValue");
|
parameter.setValue("testValue");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import li.strolch.model.StrolchRootElement;
|
||||||
|
|
||||||
|
public class QueryProcessorTest extends BaseTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProcess() {
|
||||||
|
|
||||||
|
List<StrolchRootElement> resources = getTestRessources(10);
|
||||||
|
List<StrolchRootElement> orders = getTestOrders(10);
|
||||||
|
|
||||||
|
Map<String, List<StrolchRootElement>> inputCollections = new HashMap<>();
|
||||||
|
inputCollections.put("r", resources);
|
||||||
|
inputCollections.put("o", orders);
|
||||||
|
|
||||||
|
QueryProcessor processor = new QueryProcessor();
|
||||||
|
processor.setInputCollections(inputCollections);
|
||||||
|
|
||||||
|
QueryRequest request = new QueryRequest();
|
||||||
|
request.getParameter().put("id", "0");
|
||||||
|
request.setStatement("SELECT r,o FROM Resource r, Order o WHERE r.getId() = :id AND o.getId() = :id");
|
||||||
|
|
||||||
|
QueryResponse response = processor.process(request);
|
||||||
|
|
||||||
|
System.out.println(response.asJson());
|
||||||
|
|
||||||
|
// TBD what to assert
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,28 +1,19 @@
|
||||||
package li.strolch.soql.core;
|
package li.strolch.soql.core;
|
||||||
|
|
||||||
import li.strolch.model.Order;
|
import static org.junit.Assert.assertEquals;
|
||||||
import li.strolch.model.ParameterBag;
|
|
||||||
import li.strolch.model.Resource;
|
import java.util.HashMap;
|
||||||
import li.strolch.model.StrolchElement;
|
import java.util.Iterator;
|
||||||
import li.strolch.model.parameter.FloatParameter;
|
import java.util.Map;
|
||||||
import li.strolch.model.parameter.Parameter;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import li.strolch.model.query.ActivityQuery;
|
import li.strolch.model.query.ActivityQuery;
|
||||||
import li.strolch.model.query.OrderQuery;
|
import li.strolch.model.query.OrderQuery;
|
||||||
import li.strolch.model.query.ResourceQuery;
|
import li.strolch.model.query.ResourceQuery;
|
||||||
import li.strolch.model.query.StrolchElementQuery;
|
import li.strolch.model.query.StrolchElementQuery;
|
||||||
import li.strolch.soql.antlr4.generated.SOQLLexer;
|
|
||||||
import li.strolch.soql.antlr4.generated.SOQLParser;
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author msmock
|
* @author msmock
|
||||||
|
@ -31,7 +22,7 @@ public class QueryTest extends BaseTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param entities
|
* @param entities
|
||||||
* @return Map<String , StrolchElementQuery> of queries for the entities
|
* @return Map of queries for the entities defining the objects returned
|
||||||
*/
|
*/
|
||||||
public Map<String, StrolchElementQuery> resolveEntities(final Map<String, String> entities) {
|
public Map<String, StrolchElementQuery> resolveEntities(final Map<String, String> entities) {
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,13 @@ public class SerialisationTest extends BaseTest {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuery2JSON() {
|
public void testQuery2JSON() {
|
||||||
final QueryRequest request = buildTestRequest();
|
final QueryRequest request = buildTestRequest();
|
||||||
JsonObject jsonObject = request.asJson();
|
JsonObject jsonObject = request.asJson();
|
||||||
|
|
||||||
String expected = "{\"objectType\":\"QueryRequest\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() " +
|
String expected = "{\"objectType\":\"QueryRequest\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() "
|
||||||
"= :p\",\"parameter\":{\"r\":\"Just a string!\"}}";
|
+ "= :p\",\"queryParameter\":{\"r\":\"Just a string!\"}}";
|
||||||
assertEquals(expected.trim(), jsonObject.toString());
|
assertEquals(expected.trim(), jsonObject.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,19 +59,15 @@ public class SerialisationTest extends BaseTest {
|
||||||
@Test
|
@Test
|
||||||
public void testResponse2JSON() {
|
public void testResponse2JSON() {
|
||||||
final QueryResponse response = buildTestResponse();
|
final QueryResponse response = buildTestResponse();
|
||||||
final List<StrolchRootElement> evalResult = getTestRessources(2);
|
final List evalResult = getTestRessources(2);
|
||||||
response.resultSet.add(evalResult);
|
response.getResultSet().add(evalResult);
|
||||||
|
|
||||||
String expected = "{\"objectType\":\"QueryRequest\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() " +
|
String expected = "{\"objectType\":\"QueryResponse\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() = :p\",\"queryParameter\":{\"r\":\"Just a string!\"},\"resultSet\":[[{\"objectType\":\"Resource\",\"id\":\"0\",\"name\":null,\"type\":null,\"parameterBags\":{\"testBag\":{\"id\":\"testBag\",\"name\":null,\"type\":null,\"parameters\":{\"testId\":{\"id\":\"testId\",\"name\":null,\"type\":\"Float\",\"value\":\"100.0\"}}}}},{\"objectType\":\"Resource\",\"id\":\"1\",\"name\":null,\"type\":null,\"parameterBags\":{\"testBag\":{\"id\":\"testBag\",\"name\":null,\"type\":null,\"parameters\":{\"testId\":{\"id\":\"testId\",\"name\":null,\"type\":\"Float\",\"value\":\"100.0\"}}}}}]]}";
|
||||||
"= :p\",\"parameter\":{\"r\":\"Just a string!\"},\"resultSet\":[[{\"objectType\":\"Resource\"," +
|
|
||||||
"\"id\":\"2\",\"name\":null,\"type\":null,\"parameterBags\":{\"testBag\":{\"id\":\"testBag\"," +
|
|
||||||
"\"name\":null,\"type\":null,\"parameters\":{\"testId\":{\"id\":\"testId\",\"name\":null,\"type\"" +
|
|
||||||
":\"Float\",\"value\":\"100.0\"}}}}},{\"objectType\":\"Resource\",\"id\":\"2\",\"name\":null,\"type\"" +
|
|
||||||
":null,\"parameterBags\":{\"testBag\":{\"id\":\"testBag\",\"name\":null,\"type\":null,\"parameters\"" +
|
|
||||||
":{\"testId\":{\"id\":\"testId\",\"name\":null,\"type\":\"Float\",\"value\":\"100.0\"}}}}}]]}";
|
|
||||||
|
|
||||||
final JsonObject jsonObject = response.asJson();
|
final JsonObject jsonObject = response.asJson();
|
||||||
assertEquals(expected.trim(), jsonObject.toString());
|
assertEquals(expected.trim(), jsonObject.toString());
|
||||||
|
|
||||||
|
System.out.println(jsonObject.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue