package org.mrcsparker.ceeql.handlbars; import java.io.IOException; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.Map.Entry; import org.mrcsparker.ceeql.jdbi.NamedParameterRewriter; import org.mrcsparker.ceeql.jdbi.NamedParameterRewriter.NameList; import org.skife.jdbi.v2.Batch; import org.skife.jdbi.v2.Handle; import org.skife.jdbi.v2.PreparedBatch; import org.skife.jdbi.v2.PreparedBatchPart; import com.github.jknack.handlebars.Context; import com.github.jknack.handlebars.Handlebars; import com.github.jknack.handlebars.Helper; import com.github.jknack.handlebars.Options; import com.github.jknack.handlebars.Template; /** * Override default helper to include batch and named parameters */ public class EachHelper implements Helper<Object> { /** * The helper's name. */ public static final String NAME = "each"; private Map<String, String> parameters; private Handle dbiHandle; private NameList names; public PreparedBatch batch; private String sql; public Batch npbatch; private boolean isBatch; public EachHelper(Map<String, String> parameters, NameList names, boolean isBatch, Handle dbiHandle) { this.parameters = parameters; this.names = names; this.dbiHandle = dbiHandle; this.isBatch = isBatch; } @SuppressWarnings({"rawtypes", "unchecked" }) @Override public CharSequence apply(final Object context, final Options options) throws IOException { if (context instanceof Iterable) { Options.Buffer buffer = options.buffer(); Iterator<Object> loop = ((Iterable) context).iterator(); int base = options.hash("base", 0); int index = base; boolean even = index % 2 == 0; Context parent = options.context; Template fn = options.fn; while (loop.hasNext()) { Object it = loop.next(); Context itCtx = Context.newContext(parent, it); itCtx.combine("@index", index) .combine("@first", index == base ? "first" : "") .combine("@last", !loop.hasNext() ? "last" : "") .combine("@odd", even ? "" : "odd") .combine("@even", even ? "even" : "") // 1-based index .combine("@index_1", index + 1); CharSequence cs = options.apply(fn, itCtx, Arrays.asList(it, index)); NamedParameterRewriter.ParsedStatement ps = NamedParameterRewriter.parseString(cs.toString(), parameters, names, itCtx); if (isBatch) { if (index == base) { buffer.append(ps.getParsedSql()); if (parameters != null && parameters.size() > 0) { sql = ps.getParsedSql(); batch = dbiHandle.prepareBatch(sql); } else { npbatch = dbiHandle.createBatch(); } } else { if (sql != null && !sql.equals(ps.getParsedSql())) { throw new UnsupportedOperationException("Dynamic sql for parameterized batch not supported."); } } if (npbatch != null) { npbatch.add(ps.getParsedSql()); } if (batch != null) { PreparedBatchPart part = batch.add(); for( Map.Entry<String, String> e: parameters.entrySet()) { part.bind(e.getKey(), e.getValue()); } parameters.clear(); names.rewind(); } } else { buffer.append(ps.getParsedSql()); names.reset(); } index += 1; even = !even; } // empty? if (base == index) { buffer.append(options.inverse()); } return buffer; } else if (context != null) { Iterator loop = options.propertySet(context).iterator(); Context parent = options.context; boolean first = true; Options.Buffer buffer = options.buffer(); Template fn = options.fn; while (loop.hasNext()) { Entry entry = (Entry) loop.next(); Object key = entry.getKey(); Object value = entry.getValue(); Context itCtx = Context.newBuilder(parent, value) .combine("@key", key) .combine("@first", first ? "first" : "") .combine("@last", !loop.hasNext() ? "last" : "") .build(); CharSequence cs = options.apply(fn, itCtx, Arrays.asList(value, key)); NamedParameterRewriter.ParsedStatement ps = NamedParameterRewriter.parseString(cs.toString(), parameters, names, itCtx); if (isBatch) { if (first) { buffer.append(ps.getParsedSql()); if (parameters != null && parameters.size() > 0) { sql = ps.getParsedSql(); batch = dbiHandle.prepareBatch(sql); } else { npbatch = dbiHandle.createBatch(); } } else { if (sql != null && !sql.equals(ps.getParsedSql())) { throw new UnsupportedOperationException("Dynamic sql for parameterized batch not supported."); } } if (npbatch != null) { npbatch.add(ps.getParsedSql()); } if (batch != null) { PreparedBatchPart part = batch.add(); for( Map.Entry<String, String> e: parameters.entrySet()) { part.bind(e.getKey(), e.getValue()); } parameters.clear(); names.rewind(); } } else { buffer.append(ps.getParsedSql()); names.reset(); } first = false; } // empty? if (first) { buffer.append(options.inverse()); } return buffer; } return options.buffer(); } private String[] aliases() { return new String[] {NAME}; } public EachHelper registerHelper(final Handlebars handlebars) { for (String name: aliases()) handlebars.registerHelper(name, this); return this; } }