diff --git a/adapters-api/src/main/java/io/nosqlbench/adapters/api/templating/ParsedOp.java b/adapters-api/src/main/java/io/nosqlbench/adapters/api/templating/ParsedOp.java index 709b8f243..2ad41b4e9 100644 --- a/adapters-api/src/main/java/io/nosqlbench/adapters/api/templating/ParsedOp.java +++ b/adapters-api/src/main/java/io/nosqlbench/adapters/api/templating/ParsedOp.java @@ -844,6 +844,77 @@ public class ParsedOp extends NBBaseComponent implements LongFunction opfields) { + String subopName = opfields.containsKey("name") ? opfields.get("name").toString() : fromOpField + "_" + elemName; + return new ParsedOp( + new OpData( + "sub-op of '" + this.getName() + "' field '" + fromOpField + "', element '" + elemName + "' name '" + subopName + "'", + subopName, + new LinkedHashMap(_opTemplate.getTags()) {{ + put("subop", subopName); + }}, + _opTemplate.getBindings(), + _opTemplate.getParams(), + opfields + ), + this.activityCfg, + List.of(), + this + ); + } + + public Map getAsSubOps(String fromOpField) { + Map subOpMap = new LinkedHashMap<>(); + Object o = getStaticValue(fromOpField); + if (o instanceof List list) { + String format = "subop%0" + ((int) Math.log10(list.size()) + 1) + "d"; + for (int i = 0; i < list.size(); i++) { + Object listElem = list.get(i); + + if (listElem instanceof Map lmap) { + ParsedOp parsedOp = makeSubOp(fromOpField, String.format(format, i), lmap); + subOpMap.put(parsedOp.getName(), parsedOp); + } else if (listElem instanceof CharSequence stmt) { + ParsedOp parsedOp = makeSubOp(fromOpField, String.format(format, i), stmt.toString()); + subOpMap.put(parsedOp.getName(), parsedOp); + } else { + throw new OpConfigError("For sub-ops field " + fromOpField + " of op '" + this.getName() + "', element " + + "types must be of Map or String, not '" + o.getClass().getCanonicalName() + "'"); + } + } + } else if (o instanceof Map map) { + for (Object nameKey : map.keySet()) { + Object opref = map.get(nameKey); + if (opref instanceof Map fmap) { + ParsedOp subOp = makeSubOp(fromOpField, nameKey.toString(), fmap); + subOpMap.put(subOp.getName(), subOp); + } else if (opref instanceof CharSequence stmt) { + ParsedOp subOp = makeSubOp(fromOpField, nameKey.toString(), stmt.toString()); + subOpMap.put(subOp.getName(), subOp); + } else { + throw new OpConfigError("For sub-ops field " + fromOpField + " of op '" + this.getName() + "', element " + + "types must be of Map or String, not '" + o.getClass().getCanonicalName() + "'"); + } + } + } else { + throw new OpConfigError("invalid subtype for mapping sub operations in op " + fromOpField + ":" + o.getClass().getCanonicalName()); + } + return subOpMap; + } + + public ParsedOp getAsSubOp(String name) { + Object o = getStaticValue(name); + if (o instanceof Map map) { + return makeSubOp(name, name, map); + } else { + throw new RuntimeException("Not allowed: op field named '" + name + "' as sub-op"); + } + } + /** *

Enhance an {@link Optional} {@link Function} with an optional named field or value combiner,