diff --git a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/Binding.java b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/Binding.java new file mode 100644 index 000000000..d95f98ba3 --- /dev/null +++ b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/Binding.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.converters.cql.exporters; + +public record Binding(String name, String recipe) { + +} diff --git a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/BindingsAccumulator.java b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/BindingsAccumulator.java new file mode 100644 index 000000000..6b5d8b107 --- /dev/null +++ b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/BindingsAccumulator.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.converters.cql.exporters; + +import io.nosqlbench.converters.cql.cqlast.CqlColumnDef; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class BindingsAccumulator { + + private final NamingFolio namer; + private final List libraries; + private final Map accumulated = new LinkedHashMap<>(); + + public BindingsAccumulator(NamingFolio namer, List libraries) { + this.namer = namer; + this.libraries = libraries; + } + + public Binding forColumn(CqlColumnDef def, String... extra) { + String name = namer.nameFor(def, extra); + for (BindingsLibrary library : libraries) { + Optional bindingRecipe = library.resolveBindingsFor(def); + if (bindingRecipe.isPresent()) { + Binding newBinding = new Binding(name, bindingRecipe.get()); + registerBinding(newBinding); + return newBinding; + } + } + throw new RuntimeException("Unable to find a binding for column def '" + def + "'"); + } + + private void registerBinding(Binding newBinding) { + accumulated.put(newBinding.name(), newBinding.recipe()); + } + + public Map getAccumulatedBindings() { + return accumulated; + } +} diff --git a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/BindingsLibrary.java b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/BindingsLibrary.java new file mode 100644 index 000000000..80bfc76ec --- /dev/null +++ b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/BindingsLibrary.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.converters.cql.exporters; + +import io.nosqlbench.converters.cql.cqlast.CqlColumnDef; + +import java.util.Optional; + +public interface BindingsLibrary { + Optional resolveBindingsFor(CqlColumnDef def); +} diff --git a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/CqlWorkloadExporter.java b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/CqlWorkloadExporter.java index 49b9eb0e5..c4eeac95e 100644 --- a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/CqlWorkloadExporter.java +++ b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/CqlWorkloadExporter.java @@ -47,30 +47,28 @@ import java.util.stream.Collectors; */ public class CqlWorkloadExporter { private final static Logger logger = LogManager.getLogger(CqlWorkloadExporter.class); - public final static String DEFAULT_NAMING_TEMPLATE = "[OPTYPE-][COLUMN-][TYPEDEF][-TABLE!][-KEYSPACE]"; + public final static String DEFAULT_NAMING_TEMPLATE = "[OPTYPE-][COLUMN-][TYPEDEF-][TABLE!]-[KEYSPACE]"; - private final Map defaultBindings = new DefaultCqlBindings(); + private final BindingsLibrary defaultBindings = new DefaultCqlBindings(); - private final NamingFolio namer; + private final NamingFolio namer = new NamingFolio(DEFAULT_NAMING_TEMPLATE); + private final BindingsAccumulator bindings = new BindingsAccumulator(namer, List.of(defaultBindings)); private final CqlModel model; + private final Map bindingsMap = new LinkedHashMap<>(); public CqlWorkloadExporter(CqlModel model) { - namer = new NamingFolio(DEFAULT_NAMING_TEMPLATE); this.model = model; } public CqlWorkloadExporter(String ddl, Path srcpath) { - namer = new NamingFolio(DEFAULT_NAMING_TEMPLATE); this.model = CqlModelParser.parse(ddl, srcpath); } public CqlWorkloadExporter(String ddl) { - namer = new NamingFolio(DEFAULT_NAMING_TEMPLATE); this.model = CqlModelParser.parse(ddl, null); } public CqlWorkloadExporter(Path path) { - namer = new NamingFolio(DEFAULT_NAMING_TEMPLATE); this.model = CqlModelParser.parse(path); } @@ -122,12 +120,13 @@ public class CqlWorkloadExporter { namer.populate(model); Map workload = new LinkedHashMap<>(); - workload.put("bindings", defaultBindings); + workload.put("bindings", bindingsMap); Map blocks = new LinkedHashMap<>(); workload.put("blocks", blocks); blocks.put("schema", genSchemaBlock(model)); blocks.put("rampup", genRampupBlock(model)); blocks.put("main", genMainBlock(model)); + bindingsMap.putAll(bindings.getAccumulatedBindings()); return workload; } @@ -137,7 +136,9 @@ public class CqlWorkloadExporter { mainOpTemplates.putAll( model.getAllTables() .stream() - .collect(Collectors.toMap(namer::nameFor, this::genUpsertTemplate)) + .collect(Collectors.toMap( + t -> namer.nameFor(t, "optype", "insert"), + this::genUpsertTemplate)) ); mainOpTemplates.putAll( @@ -201,19 +202,25 @@ public class CqlWorkloadExporter { logger.warn("Unknown literal format for " + typeName); } - return def.getName() + "=" + cqlLiteralFormat.format("{" + namer.nameFor(def) + "}"); + Binding binding = bindings.forColumn(def); + + return def.getName() + "=" + cqlLiteralFormat.format("{" + binding.name() + "}"); } private String genUpsertTemplate(CqlTable table) { List cdefs = table.getColumnDefinitions(); - return "insert into " + table.getKeySpace() + "." + table.getTableName() + "\n ( " - + cdefs.stream().map(cd -> cd.getName()) + return "insert into " + + table.getKeySpace() + "." + table.getTableName() + "\n" + + " ( " + cdefs.stream().map(CqlColumnDef::getName) .collect(Collectors.joining(" , ")) + " )\n values\n (" + cdefs .stream() - .map(cd -> namer.nameFor(cd)) + .map(cd -> { + Binding binding = bindings.forColumn(cd); + return binding.name(); + }) .collect(Collectors.joining("},{", "{", "}")) + ");"; } diff --git a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/ElementNamer.java b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/ElementNamer.java index d1e333276..c0b5d142d 100644 --- a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/ElementNamer.java +++ b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/ElementNamer.java @@ -47,6 +47,10 @@ public class ElementNamer implements Function, String> { Pattern pattern = Pattern.compile("(?[^\\]]+)?\\[(?
(?
.*?)(?[A-Z]+)(?!)?(?.*?))?]");
         Matcher scanner = pattern.matcher(template);
         while (scanner.find()) {
+            if (scanner.group("prefix")!=null) {
+                String prefix = scanner.group("prefix");
+                sections.add(new Section(null, prefix, true));
+            }
             if (scanner.group("section")!=null) {
                 Section section = new Section(
                     scanner.group("name").toLowerCase(),
@@ -56,10 +60,6 @@ public class ElementNamer implements Function, String> {
                     scanner.group("required") != null);
                 sections.add(section);
             }
-            if (scanner.group("prefix")!=null) {
-                String prefix = scanner.group("prefix");
-                sections.add(new Section(null, prefix, true));
-            }
         }
     }
 
diff --git a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/NamingFolio.java b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/NamingFolio.java
index cbf8a2d69..a59376e3c 100644
--- a/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/NamingFolio.java
+++ b/adapter-cqld4/src/main/java/io/nosqlbench/converters/cql/exporters/NamingFolio.java
@@ -24,6 +24,13 @@ import io.nosqlbench.nb.api.labels.Labeled;
 import java.util.*;
 
 /**
+ * The purpose of this class is to put all the logic/complexity of name condensing into one place.
+ * Basically if you have identifiers that are globally unique within the active namespace,
+ * WITHOUT using fully qualified names, then it is easier for users to use short names.
+ * For example, if you have a column named "score" which is used as an int in one table and as
+ * a double in another, then you must include the type information to provide two distinct identifiers
+ * for the purpose of mapping bindings.
+ *
  * This will be a pre-built inverted index of all field which need to have bindings assigned.
  * A field reference is presumed to be unique within the scope from which the traversal to
  * the working set has a single path.