diff --git a/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/BindType.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/BindType.java
new file mode 100644
index 000000000..14211366e
--- /dev/null
+++ b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/BindType.java
@@ -0,0 +1,30 @@
+package io.nosqlbench.engine.api.templating;
+
+/**
+ * The type of a parsed template depends on the structure of the bindings provided.
+ */
+public enum BindType {
+
+ /**
+ * A literal template is one which has no bindings that need to be provided to render a specific statement.
+ * These templates are basically static statements.
+ * Example: {@code truncate testks.testtable;}
+ */
+ literal,
+
+ /**
+ * A bindref template is one which has only a single bind point and no leading or trailing text.
+ * It represents a single value which is to be injected, with no clear indication as to whether the
+ * value should be in string form or not. These are used when referencing objects by bind point name.
+ * Callers which use rawbind templates where Strings are needed should convert them with {@link Object#toString()}}
+ * Example: {@code {myvalue}}
+ */
+ bindref,
+
+ /**
+ * A string template is one which is neither a literal template nor a bindref template. This includes
+ * any template which has any amount of literal text and any template with more than one bind point.
+ */
+ concat
+
+}
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/NamedTarget.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/NamedTarget.java
similarity index 100%
rename from adapters-api/src/main/java/io/nosqlbench/engine/api/templating/NamedTarget.java
rename to virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/NamedTarget.java
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ObjectCache.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ObjectCache.java
similarity index 100%
rename from adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ObjectCache.java
rename to virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ObjectCache.java
diff --git a/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateList.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateList.java
new file mode 100644
index 000000000..fe9838798
--- /dev/null
+++ b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateList.java
@@ -0,0 +1,51 @@
+package io.nosqlbench.engine.api.templating;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.LongFunction;
+
+public class ParsedTemplateList implements LongFunction> {
+ private final List protolist = new ArrayList<>();
+ private final int[] dynamic_idx;
+ private final LongFunction>[] functions;
+
+ public ParsedTemplateList(List sublist, Map bindings, List> cfgsources) {
+
+ List> funcs = new ArrayList<>();
+ List dindexes = new ArrayList<>();
+
+ for (int i = 0; i < sublist.size(); i++) {
+ Object item = sublist.get(i);
+ Templatizer.Result result = Templatizer.make(bindings, item, null, cfgsources);
+ switch (result.getType()) {
+ case literal:
+ protolist.add(result.getValue());
+ break;
+ case bindref:
+ case concat:
+ protolist.add(null);
+ funcs.add(result.getFunction());
+ dindexes.add(i);
+ break;
+ }
+ }
+ this.dynamic_idx = dindexes.stream().mapToInt(Integer::intValue).toArray();
+ this.functions = funcs.toArray(new LongFunction>[0]);
+
+ }
+
+ @Override
+ public List> apply(long value) {
+ List list = new ArrayList<>(protolist);
+ for (int i = 0; i < dynamic_idx.length; i++) {
+ Object obj = functions[i].apply(value);
+ list.set(dynamic_idx[i], obj);
+ }
+ return list;
+ }
+
+ public boolean isStatic() {
+ return dynamic_idx.length==0;
+ }
+}
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java
similarity index 99%
rename from adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java
rename to virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java
index 3ec03fb1a..82c19a889 100644
--- a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java
+++ b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java
@@ -118,7 +118,9 @@ public class ParsedTemplateMap implements LongFunction>, StaticFi
dynamics.put(k, subtpl);
protomap.put(k, null);
}
-
+ } else if (v instanceof List) {
+ List sublist = (List) v;
+ ParsedTemplateList subtpl = new ParsedTemplateList(sublist, bindings, cfgsources);
} else {
// Eventually, nested and mixed static dynamic structure could be supported, but
// it would be complex to implement and also not that efficient, so let's just copy
diff --git a/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/Templatizer.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/Templatizer.java
new file mode 100644
index 000000000..60fd3ef91
--- /dev/null
+++ b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/Templatizer.java
@@ -0,0 +1,126 @@
+package io.nosqlbench.engine.api.templating;
+
+import io.nosqlbench.nb.api.errors.OpConfigError;
+import io.nosqlbench.virtdata.core.bindings.DataMapper;
+import io.nosqlbench.virtdata.core.bindings.VirtData;
+import io.nosqlbench.virtdata.core.templates.CapturePoint;
+import io.nosqlbench.virtdata.core.templates.ParsedTemplate;
+import io.nosqlbench.virtdata.core.templates.StringBindings;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.LongFunction;
+
+public class Templatizer {
+
+ public static Result make(Map bindings, Object v, String name, List> cfgsources) {
+ Result result = new Result();
+ result.setName(name);
+
+ if (v instanceof CharSequence) {
+ ParsedTemplate pt = ParsedTemplate.of(((CharSequence) v).toString(), bindings);
+ result.addCaptures(pt.getCaptures());
+ result.setType(pt.getType());
+ switch (pt.getType()) {
+ case literal:
+ result.setValue(((CharSequence)v).toString());
+ break;
+ case bindref:
+ String spec = pt.asBinding().orElseThrow().getBindspec();
+ if (spec == null) {
+ throw new OpConfigError("Empty binding spec for '" + (name!=null?name:"anonymous binding") + "'");
+ }
+ Optional> mapper = VirtData.getOptionalMapper(spec);
+ result.setFunction(mapper.orElseThrow());
+ break;
+ case concat:
+ StringBindings sb = new StringBindings(pt);
+ result.setFunction(sb);
+ break;
+ }
+ } else if (v instanceof Map) {
+ ((Map) v).keySet().forEach(smk -> {
+ if (!CharSequence.class.isAssignableFrom(smk.getClass())) {
+ throw new OpConfigError("Only string keys are allowed in submaps.");
+ }
+ });
+ Map submap = (Map) v;
+ ParsedTemplateMap subtpl = new ParsedTemplateMap(submap, bindings, cfgsources);
+ if (subtpl.isStatic()) {
+ result.setValue(submap);
+ } else {
+ result.setFunction(subtpl);
+ }
+ } else if (v instanceof List) {
+ List sublist = (List) v;
+ ParsedTemplateList subtpl = new ParsedTemplateList(sublist, bindings, cfgsources);
+ if (subtpl.isStatic()) {
+ result.setValue(sublist);
+ } else {
+ result.setFunction(subtpl);
+ }
+ } else {
+ result.setValue(v);
+ // Eventually, nested and mixed static dynamic structure could be supported, but
+ // it would be complex to implement and also not that efficient, so let's just copy
+ // structure for now
+ }
+ return result;
+ }
+
+ public static class Result {
+ private BindType type;
+ private final List captures = new ArrayList<>();
+ private String name;
+ private Object value;
+ private LongFunction> function;
+
+ public Result() {
+ this.type = null;
+ }
+
+ public BindType getType() {
+ return this.type;
+ }
+
+ public List getCaptures() {
+ return this.captures;
+ }
+
+ public void addCaptures(List captures) {
+ this.captures.addAll(captures);
+ }
+
+ public void setType(BindType type) {
+ this.type = type;
+ }
+
+ public void setName(String name) {
+ this.name =name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setValue(Object v) {
+ this.value = v;
+ }
+
+ public void setFunction(LongFunction> mapper) {
+ this.function = mapper;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public LongFunction> getFunction() {
+ return this.function;
+ }
+ }
+
+
+}
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ArrayBinder.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ArrayBinder.java
similarity index 100%
rename from adapters-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ArrayBinder.java
rename to virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ArrayBinder.java
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ListBinder.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ListBinder.java
similarity index 100%
rename from adapters-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ListBinder.java
rename to virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/binders/ListBinder.java
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/binders/OrderedMapBinder.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/binders/OrderedMapBinder.java
similarity index 100%
rename from adapters-api/src/main/java/io/nosqlbench/engine/api/templating/binders/OrderedMapBinder.java
rename to virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/binders/OrderedMapBinder.java
diff --git a/virtdata-api/src/main/java/io/nosqlbench/virtdata/core/templates/ParsedTemplate.java b/virtdata-api/src/main/java/io/nosqlbench/virtdata/core/templates/ParsedTemplate.java
index 88e8d52ba..746430a48 100644
--- a/virtdata-api/src/main/java/io/nosqlbench/virtdata/core/templates/ParsedTemplate.java
+++ b/virtdata-api/src/main/java/io/nosqlbench/virtdata/core/templates/ParsedTemplate.java
@@ -18,6 +18,7 @@
package io.nosqlbench.virtdata.core.templates;
+import io.nosqlbench.engine.api.templating.BindType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -118,32 +119,6 @@ public class ParsedTemplate {
return new ParsedTemplate(rawtemplate, bindings);
}
- /**
- * The type of a parsed template depends on the structure of the bindings provided.
- */
- public enum Type {
-
- /**
- * A literal template is one which has no bindings that need to be provided to render a specific statement.
- * These templates are basically static statements.
- * Example: {@code truncate testks.testtable;}
- */
- literal,
- /**
- * A bindref template is one which has only a single bind point and no leading or trailing text.
- * It represents a single value which is to be injected, with no clear indication as to whether the
- * value should be in string form or not. These are used when referencing objects by bind point name.
- * Callers which use rawbind templates where Strings are needed should convert them with {@link Object#toString()}}
- * Example: {@code {myvalue}}
- */
- bindref,
- /**
- * A string template is one which is neither a literal template nor a bindref template. This includes
- * any template which has any amount of literal text and any template with more than one bind point.
- */
- concat
- }
-
/**
* Spans is an even-odd form of (literal, variable, ..., ..., literal)
* Thus a 1-length span is a single literal, and a 3 length span has a single bind point
@@ -176,13 +151,13 @@ public class ParsedTemplate {
this.bindpoints = bindPointsResult.getBindpoints();
}
- public Type getType() {
+ public BindType getType() {
if (this.spans.length == 1) {
- return Type.literal;
+ return BindType.literal;
} else if (this.spans[0].isEmpty() && this.spans[2].isEmpty()) {
- return Type.bindref;
+ return BindType.bindref;
} else {
- return Type.concat;
+ return BindType.concat;
}
}
diff --git a/virtdata-api/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/virtdata-api/src/main/resources/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 000000000..ceb8ce941
--- /dev/null
+++ b/virtdata-api/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+io.nosqlbench.nb.annotations.ServiceProcessor
diff --git a/virtdata-api/src/test/java/io/nosqlbench/engine/api/templating/ParsedTemplateListTest.java b/virtdata-api/src/test/java/io/nosqlbench/engine/api/templating/ParsedTemplateListTest.java
new file mode 100644
index 000000000..73e8fca42
--- /dev/null
+++ b/virtdata-api/src/test/java/io/nosqlbench/engine/api/templating/ParsedTemplateListTest.java
@@ -0,0 +1,26 @@
+package io.nosqlbench.engine.api.templating;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ParsedTemplateListTest {
+
+ @Test
+ public void testTemplateListLiterals() {
+ ParsedTemplateList ptl = new ParsedTemplateList(List.of("a","b"), Map.of(),List.of());
+ List> made = ptl.apply(2L);
+ assertThat(made).isEqualTo(List.of("a","b"));
+ }
+
+// @Test
+// public void testTemplateListReferences() {
+// ParsedTemplateList ptl = new ParsedTemplateList(List.of("{a}","{b}"), Map.of("a","TestingRepeater(2)","b","TestingRepeater(4)"),List.of());
+// List> made = ptl.apply(2L);
+// assertThat(made).isEqualTo(List.of("a","b"));
+// }
+
+}
diff --git a/virtdata-api/src/test/java/io/nosqlbench/virtdata/core/templates/ParsedTemplateTest.java b/virtdata-api/src/test/java/io/nosqlbench/virtdata/core/templates/ParsedTemplateTest.java
index 789df5534..953d851c6 100644
--- a/virtdata-api/src/test/java/io/nosqlbench/virtdata/core/templates/ParsedTemplateTest.java
+++ b/virtdata-api/src/test/java/io/nosqlbench/virtdata/core/templates/ParsedTemplateTest.java
@@ -1,12 +1,9 @@
package io.nosqlbench.virtdata.core.templates;
-import org.junit.jupiter.api.Disabled;
+import io.nosqlbench.engine.api.templating.BindType;
import org.junit.jupiter.api.Test;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import java.util.Map;
-import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@@ -82,7 +79,7 @@ public class ParsedTemplateTest {
"select [u],[v as v1] from users where userid={userid}", Map.of("userid", "NumberNameToString()")
);
assertThat(pt.getAnchors()).containsExactly("userid");
- assertThat(pt.getType()).isEqualTo(ParsedTemplate.Type.concat);
+ assertThat(pt.getType()).isEqualTo(BindType.concat);
assertThat(pt.getCaptures()).containsExactly(CapturePoint.of("u"),CapturePoint.of("v","v1"));
}