From 5e2a797b17cfe874489122f9dd0e58ee83af7b95 Mon Sep 17 00:00:00 2001 From: msmock Date: Thu, 4 Jan 2018 14:30:51 +0100 Subject: [PATCH] Finished draft implementation with some TODO's left --- .../strolch/soql/core/CompiledStatement.java | 53 ++--- .../li/strolch/soql/core/IndexPointer.java | 43 ++++ .../li/strolch/soql/core/QueryProcessor.java | 210 +++++++++++++++++ .../li/strolch/soql/core/QueryRequest.java | 98 ++++---- .../li/strolch/soql/core/QueryResponse.java | 49 ++-- .../java/li/strolch/soql/core/ResultSet.java | 79 ++++--- .../li/strolch/soql/core/VerboseListener.java | 0 .../java/li/strolch/soql/core/BaseTest.java | 211 ++++++++++-------- .../strolch/soql/core/DataStructureTest.java | 60 +++++ .../soql/core/MethodExpressionTest.java | 18 +- .../strolch/soql/core/QueryProcessorTest.java | 49 ++++ .../java/li/strolch/soql/core/QueryTest.java | 31 +-- .../strolch/soql/core/SerialisationTest.java | 93 ++++---- 13 files changed, 703 insertions(+), 291 deletions(-) create mode 100644 li.strolch.soql/src/main/java/li/strolch/soql/core/IndexPointer.java create mode 100644 li.strolch.soql/src/main/java/li/strolch/soql/core/QueryProcessor.java rename li.strolch.soql/src/{test => main}/java/li/strolch/soql/core/VerboseListener.java (100%) create mode 100644 li.strolch.soql/src/test/java/li/strolch/soql/core/DataStructureTest.java create mode 100644 li.strolch.soql/src/test/java/li/strolch/soql/core/QueryProcessorTest.java diff --git a/li.strolch.soql/src/main/java/li/strolch/soql/core/CompiledStatement.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/CompiledStatement.java index 158ba5ece..3eaccf7fb 100644 --- a/li.strolch.soql/src/main/java/li/strolch/soql/core/CompiledStatement.java +++ b/li.strolch.soql/src/main/java/li/strolch/soql/core/CompiledStatement.java @@ -13,38 +13,39 @@ import li.strolch.soql.core.expresssion.WhereExpression; */ public class CompiledStatement { - // the map of entities declared in the FROM clause with their nicknames as keys - Map entities = new HashMap<>(); + // the map of entities declared in the FROM clause with their nicknames as keys + Map entities = new HashMap<>(); - // the decision tree as defined in the WHERE clause - WhereExpression whereExpression; + // the decision tree as defined in the WHERE clause + WhereExpression whereExpression; - // the expression evaluating to the selected objects according to the SELECT - // clause - public SelectClause selectClause; + // the expression evaluating to the selected objects according to the SELECT clause + public SelectClause selectClause; - /** - * - * @return List of objects resulting from running the compiled code - */ - public List evaluate(Map inputObjects, Map injectedObjects) { + /** + * + * @param inputObjects + * @param queryParameter + * + * @return List of objects resulting from running the compiled code + */ + public List evaluate(final Map inputObjects, final Map queryParameter) { - boolean evaluateWhereExpression = true; - if (whereExpression != null) { - evaluateWhereExpression = whereExpression.evaluate(inputObjects, injectedObjects); - } + boolean evaluateWhereExpression = true; + if (whereExpression != null) + evaluateWhereExpression = whereExpression.evaluate(inputObjects, queryParameter); - if (evaluateWhereExpression) { - return selectClause.evaluate(inputObjects, injectedObjects); - } + if (evaluateWhereExpression) + return selectClause.evaluate(inputObjects, queryParameter); - return new ArrayList<>(); - } + // else return empty list + return new ArrayList<>(); + } - @Override - public String toString() { - return "CompiledStatement [entities=" + entities + ", whereExpression=" + whereExpression + ", selectClause=" - + selectClause + "]"; - } + @Override + public String toString() { + return "CompiledStatement [entities=" + entities + ", whereExpression=" + whereExpression + ", selectClause=" + + selectClause + "]"; + } } diff --git a/li.strolch.soql/src/main/java/li/strolch/soql/core/IndexPointer.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/IndexPointer.java new file mode 100644 index 000000000..979287a9c --- /dev/null +++ b/li.strolch.soql/src/main/java/li/strolch/soql/core/IndexPointer.java @@ -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]++; + } + } + } + +} diff --git a/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryProcessor.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryProcessor.java new file mode 100644 index 000000000..b8106c1aa --- /dev/null +++ b/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryProcessor.java @@ -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 queries; + + // Map of entities the input objects are taken from + protected Map> 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> 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> cartesianProduct = buildCartesianProduct(inputCollections, keys); + + ResultSet resultSet = new ResultSet(); + + // apply the compiled statement to any row of the cartesian product + for (List row : cartesianProduct) { + Map inputObjects = new HashMap<>(); + for (int i = 0; i < row.size(); i++) { + inputObjects.put((String) keys[i], row.get(i)); + } + List 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> buildCartesianProduct(Map> 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> cartesianProduct = new ArrayList<>(); + IndexPointer indexPointer = new IndexPointer(numberOfEntities); + while (indexPointer.hasNext()) { + + List 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 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 entity2Query(Map entities) { + + Map result = new HashMap<>(); + + Set 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; + } + +} diff --git a/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryRequest.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryRequest.java index a886405bd..454355276 100644 --- a/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryRequest.java +++ b/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryRequest.java @@ -14,66 +14,70 @@ import java.util.Set; */ public class QueryRequest { - public static final String STATEMENT = "statement"; - public static final String PARAMETER = "parameter"; + public static final String STATEMENT = "statement"; + public static final String PARAMETER = "queryParameter"; - // the SOQL query string - private String statement; + // the SOQL query string + String statement; - // the parameter of the SOQL query - private Map parameter = new HashMap<>(); + // the parameter of the SOQL query + Map parameter = new HashMap<>(); - public String getStatement() { - return statement; - } + public String getStatement() { + return statement; + } - public void setStatement(String statement) { - this.statement = statement; - } + public void setStatement(String statement) { + this.statement = statement; + } - public Map getParameter() { - return parameter; - } + public Map getParameter() { + return parameter; + } - /** - * @return the query as JsonObject - */ - public JsonObject asJson() { + public void setParameter(Map parameter) { + this.parameter = parameter; + } - final JsonObject rootJ = new JsonObject(); - rootJ.addProperty(Tags.Json.OBJECT_TYPE, "QueryRequest"); - rootJ.addProperty(STATEMENT, statement); + /** + * @return the query as JsonObject + */ + public JsonObject asJson() { - final JsonObject parameterJ = new JsonObject(); - rootJ.add(PARAMETER, parameterJ); + JsonObject rootJ = new JsonObject(); + rootJ.addProperty(Tags.Json.OBJECT_TYPE, "QueryRequest"); + rootJ.addProperty(STATEMENT, statement); - final Set keys = parameter.keySet(); - for (Iterator iterator = keys.iterator(); iterator.hasNext(); ) { - final String key = iterator.next(); - final Object param = parameter.get(key); - parameterJ.addProperty(key, param.toString()); - } + JsonObject parameterJ = new JsonObject(); + rootJ.add(PARAMETER, parameterJ); - return rootJ; - } + Set keys = parameter.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + String key = iterator.next(); + Object param = parameter.get(key); + parameterJ.addProperty(key, param.toString()); + } - /** - * build request from Json object - * - * @return - */ - public QueryRequest fromJson(JsonObject jsonObject) { + return rootJ; + } - final String statement = jsonObject.get(STATEMENT).getAsString(); - setStatement(statement); + /** + * build request from Json object + * + * @return + */ + public QueryRequest fromJson(JsonObject jsonObject) { - final JsonObject params = jsonObject.getAsJsonObject(PARAMETER); - final Set> entrySet = params.entrySet(); - for (final Map.Entry entry : entrySet) { - parameter.put(entry.getKey(), entry.getValue().getAsString()); - } + String statement = jsonObject.get(STATEMENT).getAsString(); + setStatement(statement); - return this; - } + JsonObject params = jsonObject.getAsJsonObject(PARAMETER); + Set> entrySet = params.entrySet(); + for (Map.Entry entry : entrySet) { + parameter.put(entry.getKey(), entry.getValue().getAsString()); + } + + return this; + } } diff --git a/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryResponse.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryResponse.java index c1c2b52b9..e1285a5d2 100644 --- a/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryResponse.java +++ b/li.strolch.soql/src/main/java/li/strolch/soql/core/QueryResponse.java @@ -2,34 +2,49 @@ package li.strolch.soql.core; import com.google.gson.JsonObject; +import li.strolch.model.Tags; + /** * @author msmock */ 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 - public String message; + // an exception or error message in case of error + public String message; - // - public final ResultSet resultSet = new ResultSet(); + // the returned objects + public ResultSet resultSet = new ResultSet(); - /** - * @return the query as JsonObject - */ - public JsonObject asJson() { + /** + * @param resultSet the resultSet to set + */ + public void setResultSet(ResultSet resultSet) { + this.resultSet = resultSet; + } - final JsonObject rootJ = super.asJson(); + /** + * @return the resultSet + */ + public ResultSet getResultSet() { + return resultSet; + } - if (message != null && !message.isEmpty()) { - rootJ.addProperty("Message", message); - } + /** + * @return the query as JsonObject + */ + public JsonObject asJson() { - rootJ.add(RESULT_SET, resultSet.asJson()); + JsonObject rootJ = super.asJson(); + rootJ.addProperty(Tags.Json.OBJECT_TYPE, "QueryResponse"); - return rootJ; - } + if (message != null && !message.isEmpty()) { + rootJ.addProperty("Message", message); + } + + rootJ.add(RESULT_SET, resultSet.asJson()); + return rootJ; + } } diff --git a/li.strolch.soql/src/main/java/li/strolch/soql/core/ResultSet.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/ResultSet.java index 8ef1496fb..3b9d2ed8c 100644 --- a/li.strolch.soql/src/main/java/li/strolch/soql/core/ResultSet.java +++ b/li.strolch.soql/src/main/java/li/strolch/soql/core/ResultSet.java @@ -1,56 +1,71 @@ 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.Iterator; +import java.util.LinkedList; 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 *

* - * TODO: the result set should carry arbitrary objects, not only StrolchRootElements + * TODO: the result set should carry arbitrary objects, not only + * StrolchRootElements * * @author msmock */ public class ResultSet { - final StrolchElementToJsonVisitor visitor = new StrolchElementToJsonVisitor(); + final StrolchElementToJsonVisitor visitor = new StrolchElementToJsonVisitor(); - public final List> rows = new ArrayList<>(); + public final List> rows = new ArrayList<>(); - /** - * @param row the result of the execution of a single statement - */ - public void add(final List row) { - rows.add(row); - } + /** + * @param row + * the result of the execution of a single statement + */ + public void add(final List row) { - /** - * @return all rows as JSON Array - */ - public JsonArray asJson() { + List 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."); + } + } - final JsonArray rowsAsJson = new JsonArray(); + rows.add(toBeAdded); + } - for (Iterator> rowsIter = rows.iterator(); rowsIter.hasNext(); ) - rowsAsJson.add(row2Json(rowsIter.next())); + /** + * @return all rows as JSON Array + */ + public JsonArray asJson() { - return rowsAsJson; - } + JsonArray rowsAsJson = new JsonArray(); - /** - * @return a single row as JSON Array - */ - private JsonArray row2Json(final List evalResult) { - final JsonArray rowAsJson = new JsonArray(); - for (Iterator iterator = evalResult.iterator(); iterator.hasNext(); ) { - rowAsJson.add(iterator.next().accept(visitor)); - } - return rowAsJson; - } + for (Iterator> rowsIter = rows.iterator(); rowsIter.hasNext();) + rowsAsJson.add(row2Json(rowsIter.next())); + + return rowsAsJson; + } + + /** + * @return a single row as JSON Array + */ + private JsonArray row2Json(final List evalResult) { + JsonArray rowAsJson = new JsonArray(); + for (Iterator iterator = evalResult.iterator(); iterator.hasNext();) { + rowAsJson.add(iterator.next().accept(visitor)); + } + return rowAsJson; + } } diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/VerboseListener.java b/li.strolch.soql/src/main/java/li/strolch/soql/core/VerboseListener.java similarity index 100% rename from li.strolch.soql/src/test/java/li/strolch/soql/core/VerboseListener.java rename to li.strolch.soql/src/main/java/li/strolch/soql/core/VerboseListener.java diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/BaseTest.java b/li.strolch.soql/src/test/java/li/strolch/soql/core/BaseTest.java index 617e71fc7..58c71668c 100644 --- a/li.strolch.soql/src/test/java/li/strolch/soql/core/BaseTest.java +++ b/li.strolch.soql/src/test/java/li/strolch/soql/core/BaseTest.java @@ -1,125 +1,156 @@ package li.strolch.soql.core; -import li.strolch.model.*; -import li.strolch.model.parameter.FloatParameter; -import li.strolch.model.parameter.Parameter; -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 java.util.ArrayList; +import java.util.Date; +import java.util.List; + 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; +import li.strolch.model.Order; +import li.strolch.model.ParameterBag; +import li.strolch.model.Resource; +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 */ public abstract class BaseTest { - /** - * parse the string and return the antlr tree - * - * @throws Exception - */ - ParseTree parseString(final String s) throws Exception { + /** + * parse the string and return the antlr tree + * + * @throws Exception + */ + ParseTree parseString(final String s) throws Exception { - final CharStream input = CharStreams.fromString(s); - final SOQLLexer lexer = new SOQLLexer(input); // create a buffer of tokens pulled from the lexer + final CharStream input = CharStreams.fromString(s); + 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 SOQLParser parser = new SOQLParser(tokens); - parser.addErrorListener(new VerboseListener()); + final CommonTokenStream tokens = new CommonTokenStream(lexer); // create a parser that feeds off the tokens + // buffer + final SOQLParser parser = new SOQLParser(tokens); + parser.addErrorListener(new VerboseListener()); - final ParseTree tree = parser.select_statement(); // begin parsing at block + final ParseTree tree = parser.select_statement(); // begin parsing at block - // System.out.println(tree.toStringTree(parser)); // print LISP-style tree + // System.out.println(tree.toStringTree(parser)); // print LISP-style tree - return tree; - } + return tree; + } - /** - * compile the antlr tree to executable - * - * @param tree - * @return CompiledSOQLStatement - * @throws Exception - */ - CompiledStatement compile(final ParseTree tree) throws Exception { + /** + * compile the antlr tree to executable + * + * @param tree + * @return CompiledSOQLStatement + * @throws Exception + */ + CompiledStatement compile(final ParseTree tree) throws Exception { - final ParseTreeWalker walker = new ParseTreeWalker(); - final SOQLListener listener = new SOQLListener(); - walker.walk(listener, tree); + final ParseTreeWalker walker = new ParseTreeWalker(); + final SOQLListener listener = new SOQLListener(); + walker.walk(listener, tree); - final CompiledStatement soqlStatement = new CompiledStatement(); - soqlStatement.entities = listener.getEntities(); - soqlStatement.whereExpression = listener.getWhereExpression(); - soqlStatement.selectClause = listener.getSelectClause(); + final CompiledStatement soqlStatement = new CompiledStatement(); + soqlStatement.entities = listener.getEntities(); + soqlStatement.whereExpression = listener.getWhereExpression(); + soqlStatement.selectClause = listener.getSelectClause(); - return soqlStatement; - } + return soqlStatement; + } - /** - * @return a test resource - */ - StrolchRootElement getTestResource(final String id) { - final Resource resource = new Resource(); - resource.setId(id); + /** + * @return a test resource + */ + StrolchRootElement getTestResource(final String id) { + final Resource resource = new Resource(); + resource.setId(id); - final ParameterBag bag = new ParameterBag(); - bag.setId("testBag"); - resource.addParameterBag(bag); + final ParameterBag bag = new ParameterBag(); + bag.setId("testBag"); + resource.addParameterBag(bag); - final Parameter parameter = new FloatParameter(); - parameter.setId("testId"); - parameter.setValue(100d); + final Parameter parameter = new FloatParameter(); + parameter.setId("testId"); + parameter.setValue(100d); - resource.addParameter("testBag", parameter); - return resource; - } + resource.addParameter("testBag", parameter); + return resource; + } - /** - * @return a test order - */ - StrolchRootElement getTestOrder(final String id) { - final Order order = new Order(); - order.setId("testId"); + /** + * @return a test order + */ + StrolchRootElement getTestOrder(String id) { + Order order = new Order(); + order.setId(id); + order.setState(State.CREATED); - final ParameterBag bag = new ParameterBag(); - bag.setId("testBag"); - order.addParameterBag(bag); + order.setDate(new Date()); - final Parameter parameter = new FloatParameter(); - parameter.setId("testId"); - parameter.setValue(100d); + ParameterBag bag = new ParameterBag(); + bag.setId("testBag"); + order.addParameterBag(bag); - order.addParameter("testBag", parameter); - return order; - } + Parameter parameter = new FloatParameter(); + parameter.setId("testId"); + parameter.setValue(100d); - List getTestRessources(int n) { - final List result = new ArrayList<>(n); - for (int i = 0; i < n; i++) { - result.add(getTestResource(String.valueOf(n))); - } - return result; - } + order.addParameter("testBag", parameter); + return order; + } - List getTestOrders(int n) { - final List result = new ArrayList<>(n); - for (int i = 0; i < n; i++) { - result.add(getTestOrder(String.valueOf(n))); - } - return result; - } + /** + * @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 parameter = new FloatParameter(); + parameter.setId("testId"); + parameter.setValue(100d); + + activity.addParameter("testBag", parameter); + return activity; + } + + List getTestRessources(int n) { + final List result = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + result.add(getTestResource(String.valueOf(i))); + } + return result; + } + + List getTestOrders(int n) { + final List result = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + result.add(getTestOrder(String.valueOf(i))); + } + return result; + } + + List getTestActivities(int n) { + final List result = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + result.add(getTestActivity(String.valueOf(i))); + } + return result; + } } diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/DataStructureTest.java b/li.strolch.soql/src/test/java/li/strolch/soql/core/DataStructureTest.java new file mode 100644 index 000000000..15b80723b --- /dev/null +++ b/li.strolch.soql/src/test/java/li/strolch/soql/core/DataStructureTest.java @@ -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> 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> cartesianProduct = new ArrayList<>(); + final IndexPointer indexPointer = new IndexPointer(numberOfEntities); + while(indexPointer.hasNext()){ + + final List 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 elements = structure.get(key); + final StrolchRootElement element = elements.get(pointer[keyIndex]); + row.add(element); + } + } + + // TODO + } + +} diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/MethodExpressionTest.java b/li.strolch.soql/src/test/java/li/strolch/soql/core/MethodExpressionTest.java index b09d9c92f..3f2de8c34 100644 --- a/li.strolch.soql/src/test/java/li/strolch/soql/core/MethodExpressionTest.java +++ b/li.strolch.soql/src/test/java/li/strolch/soql/core/MethodExpressionTest.java @@ -1,23 +1,21 @@ 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.Resource; -import li.strolch.model.StrolchElement; import li.strolch.model.StrolchRootElement; -import li.strolch.model.json.StrolchElementToJsonVisitor; import li.strolch.model.parameter.Parameter; import li.strolch.model.parameter.StringParameter; import li.strolch.soql.core.expresssion.ChainedMethodExpression; import li.strolch.soql.core.expresssion.MethodArgumentDeclaration; import li.strolch.soql.core.expresssion.MethodExpression; 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 @@ -32,7 +30,7 @@ public class MethodExpressionTest { bag.setId("testBag"); resource.addParameterBag(bag); - final Parameter parameter = new StringParameter(); + final Parameter parameter = new StringParameter(); parameter.setId("testId"); parameter.setValue("testValue"); diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryProcessorTest.java b/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryProcessorTest.java new file mode 100644 index 000000000..7589bd466 --- /dev/null +++ b/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryProcessorTest.java @@ -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 resources = getTestRessources(10); + List orders = getTestOrders(10); + + Map> 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 + } + +} diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryTest.java b/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryTest.java index 4bddfe4ee..645aa7327 100644 --- a/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryTest.java +++ b/li.strolch.soql/src/test/java/li/strolch/soql/core/QueryTest.java @@ -1,28 +1,19 @@ package li.strolch.soql.core; -import li.strolch.model.Order; -import li.strolch.model.ParameterBag; -import li.strolch.model.Resource; -import li.strolch.model.StrolchElement; -import li.strolch.model.parameter.FloatParameter; -import li.strolch.model.parameter.Parameter; +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +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.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 org.junit.Test; - -import java.util.*; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; /** * @author msmock @@ -31,7 +22,7 @@ public class QueryTest extends BaseTest { /** * @param entities - * @return Map of queries for the entities + * @return Map of queries for the entities defining the objects returned */ public Map resolveEntities(final Map entities) { diff --git a/li.strolch.soql/src/test/java/li/strolch/soql/core/SerialisationTest.java b/li.strolch.soql/src/test/java/li/strolch/soql/core/SerialisationTest.java index 91bafcb37..1483c56c3 100644 --- a/li.strolch.soql/src/test/java/li/strolch/soql/core/SerialisationTest.java +++ b/li.strolch.soql/src/test/java/li/strolch/soql/core/SerialisationTest.java @@ -13,66 +13,61 @@ import static org.junit.Assert.assertEquals; */ public class SerialisationTest extends BaseTest { - private QueryRequest buildTestRequest() { - String s = "SELECT a FROM Activity a WHERE a.getId() = :p"; - final QueryRequest request = new QueryRequest(); - request.setStatement(s); - request.getParameter().put("r", "Just a string!"); - return request; - } + private QueryRequest buildTestRequest() { + String s = "SELECT a FROM Activity a WHERE a.getId() = :p"; + final QueryRequest request = new QueryRequest(); + request.setStatement(s); + request.getParameter().put("r", "Just a string!"); + return request; + } - private QueryResponse buildTestResponse() { - String s = "SELECT a FROM Activity a WHERE a.getId() = :p"; - final QueryResponse response = new QueryResponse(); - response.setStatement(s); - response.getParameter().put("r", "Just a string!"); - return response; - } + private QueryResponse buildTestResponse() { + String s = "SELECT a FROM Activity a WHERE a.getId() = :p"; + final QueryResponse response = new QueryResponse(); + response.setStatement(s); + response.getParameter().put("r", "Just a string!"); + return response; + } + @Test + public void testQuery2JSON() { + final QueryRequest request = buildTestRequest(); + JsonObject jsonObject = request.asJson(); - @Test - public void testQuery2JSON() { - final QueryRequest request = buildTestRequest(); - JsonObject jsonObject = request.asJson(); + String expected = "{\"objectType\":\"QueryRequest\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() " + + "= :p\",\"queryParameter\":{\"r\":\"Just a string!\"}}"; + assertEquals(expected.trim(), jsonObject.toString()); + } - String expected = "{\"objectType\":\"QueryRequest\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() " + - "= :p\",\"parameter\":{\"r\":\"Just a string!\"}}"; - assertEquals(expected.trim(), jsonObject.toString()); - } + @Test + public void testJSON2Query() { - @Test - public void testJSON2Query() { + String s = "SELECT a FROM Activity a WHERE a.getId() = :p"; - String s = "SELECT a FROM Activity a WHERE a.getId() = :p"; + final QueryRequest initial = new QueryRequest(); + initial.setStatement(s); + initial.getParameter().put("p", "10010"); + final JsonObject jsonObject = initial.asJson(); - final QueryRequest initial = new QueryRequest(); - initial.setStatement(s); - initial.getParameter().put("p", "10010"); - final JsonObject jsonObject = initial.asJson(); + final QueryRequest query = new QueryRequest(); + query.fromJson(jsonObject); - final QueryRequest query = new QueryRequest(); - query.fromJson(jsonObject); + assertEquals(s, query.getStatement()); + assertEquals("10010", query.getParameter().get("p")); + } - assertEquals(s, query.getStatement()); - assertEquals("10010", query.getParameter().get("p")); - } + @Test + public void testResponse2JSON() { + final QueryResponse response = buildTestResponse(); + final List evalResult = getTestRessources(2); + response.getResultSet().add(evalResult); - @Test - public void testResponse2JSON() { - final QueryResponse response = buildTestResponse(); - final List evalResult = getTestRessources(2); - response.resultSet.add(evalResult); + 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\"}}}}}]]}"; - String expected = "{\"objectType\":\"QueryRequest\",\"statement\":\"SELECT a FROM Activity a WHERE a.getId() " + - "= :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(); + assertEquals(expected.trim(), jsonObject.toString()); - final JsonObject jsonObject = response.asJson(); - assertEquals(expected.trim(), jsonObject.toString()); - } + System.out.println(jsonObject.toString()); + } }