Search in sources :

Example 1 with StatementContext

use of org.jdbi.v3.core.statement.StatementContext in project jdbi by jdbi.

the class BeanMapper method specialize0.

private RowMapper<T> specialize0(ResultSet rs, StatementContext ctx, List<String> columnNames, List<ColumnNameMatcher> columnNameMatchers, List<String> unmatchedColumns) throws SQLException {
    final List<RowMapper<?>> mappers = new ArrayList<>();
    final List<PropertyDescriptor> properties = new ArrayList<>();
    for (PropertyDescriptor descriptor : info.getPropertyDescriptors()) {
        Nested anno = Stream.of(descriptor.getReadMethod(), descriptor.getWriteMethod()).filter(Objects::nonNull).map(m -> m.getAnnotation(Nested.class)).filter(Objects::nonNull).findFirst().orElse(null);
        if (anno == null) {
            String paramName = prefix + paramName(descriptor);
            findColumnIndex(paramName, columnNames, columnNameMatchers, () -> debugName(descriptor)).ifPresent(index -> {
                Type type = descriptor.getReadMethod().getGenericReturnType();
                ColumnMapper<?> mapper = ctx.findColumnMapperFor(type).orElse((r, n, c) -> r.getObject(n));
                mappers.add(new SingleColumnMapper<>(mapper, index + 1));
                properties.add(descriptor);
                unmatchedColumns.remove(columnNames.get(index));
            });
        } else {
            String nestedPrefix = prefix + anno.value();
            RowMapper<?> nestedMapper = nestedMappers.computeIfAbsent(descriptor, d -> new BeanMapper<>(d.getPropertyType(), nestedPrefix)).specialize0(rs, ctx, columnNames, columnNameMatchers, unmatchedColumns);
            mappers.add(nestedMapper);
            properties.add(descriptor);
        }
    }
    if (mappers.isEmpty() && columnNames.size() > 0) {
        throw new IllegalArgumentException(String.format("Mapping bean type %s " + "didn't find any matching columns in result set", type));
    }
    return (r, c) -> {
        T bean = construct();
        for (int i = 0; i < mappers.size(); i++) {
            RowMapper<?> mapper = mappers.get(i);
            PropertyDescriptor property = properties.get(i);
            Object value = mapper.map(r, ctx);
            writeProperty(bean, property, value);
        }
        return bean;
    };
}
Also used : ReflectionMapperUtil.getColumnNames(org.jdbi.v3.core.mapper.reflect.ReflectionMapperUtil.getColumnNames) RowMapperFactory(org.jdbi.v3.core.mapper.RowMapperFactory) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Nested(org.jdbi.v3.core.mapper.Nested) SingleColumnMapper(org.jdbi.v3.core.mapper.SingleColumnMapper) IntrospectionException(java.beans.IntrospectionException) InvocationTargetException(java.lang.reflect.InvocationTargetException) ArrayList(java.util.ArrayList) StatementContext(org.jdbi.v3.core.statement.StatementContext) Objects(java.util.Objects) Introspector(java.beans.Introspector) SQLException(java.sql.SQLException) List(java.util.List) Stream(java.util.stream.Stream) Type(java.lang.reflect.Type) PropertyDescriptor(java.beans.PropertyDescriptor) ResultSet(java.sql.ResultSet) BeanInfo(java.beans.BeanInfo) Map(java.util.Map) ReflectionMapperUtil.findColumnIndex(org.jdbi.v3.core.mapper.reflect.ReflectionMapperUtil.findColumnIndex) ColumnMapper(org.jdbi.v3.core.mapper.ColumnMapper) RowMapper(org.jdbi.v3.core.mapper.RowMapper) PropertyDescriptor(java.beans.PropertyDescriptor) ArrayList(java.util.ArrayList) Nested(org.jdbi.v3.core.mapper.Nested) Type(java.lang.reflect.Type) Objects(java.util.Objects) RowMapper(org.jdbi.v3.core.mapper.RowMapper)

Example 2 with StatementContext

use of org.jdbi.v3.core.statement.StatementContext in project jdbi by jdbi.

the class DefinedAttributeTemplateEngine method render.

@Override
public String render(String template, StatementContext ctx) {
    StringBuilder b = new StringBuilder();
    DefineStatementLexer lexer = new DefineStatementLexer(new ANTLRStringStream(template));
    try {
        Token t = lexer.nextToken();
        while (t.getType() != EOF) {
            switch(t.getType()) {
                case COMMENT:
                case LITERAL:
                case QUOTED_TEXT:
                case DOUBLE_QUOTED_TEXT:
                    b.append(t.getText());
                    break;
                case DEFINE:
                    String text = t.getText();
                    String key = text.substring(1, text.length() - 1);
                    Object value = ctx.getAttribute(key);
                    if (value == null) {
                        throw new UnableToCreateStatementException("Undefined attribute for token '" + text + "'", ctx);
                    }
                    b.append(value);
                    break;
                case ESCAPED_TEXT:
                    b.append(t.getText().substring(1));
                    break;
                default:
                    break;
            }
            t = lexer.nextToken();
        }
        return b.toString();
    } catch (RuntimeException e) {
        throw new UnableToCreateStatementException("Error rendering SQL template: '" + template + "'", e, ctx);
    }
}
Also used : ANTLRStringStream(org.antlr.runtime.ANTLRStringStream) DefineStatementLexer(org.jdbi.v3.core.internal.lexer.DefineStatementLexer) Token(org.antlr.runtime.Token)

Example 3 with StatementContext

use of org.jdbi.v3.core.statement.StatementContext in project jdbi by jdbi.

the class SqlStatement method bindBeanList.

/**
 * Bind a parameter for each value in the given list * number of property names,
 * and defines an attribute as the comma-separated list of parameter references (using colon prefix).
 *
 * Used to create query similar to:
 * select * from things where (id, foo) in ((1,'abc'),(2,'def'),(3,'ghi'))
 * <p>
 * Examples:
 * <pre>
 *
 * List&lt;ThingKey&gt; thingKeys = ...
 * List&lt;Thing&gt; things = handle.createQuery("select * from things where (id, foo) in (&lt;thingKeys&gt;)")
 *     .bindBeanList("thingKeys", thingKeys, Arrays.asList("id", "foo"))
 *     .mapTo(Contact.class)
 *     .list();
 * </pre>
 *
 * @param key    attribute name
 * @param values list of values that will be comma-spliced into the defined attribute value.
 * @param propertyNames list of properties that will be invoked on the values.
 * @return this
 * @throws IllegalArgumentException if the list of values or properties is empty.
 * @throws UnableToCreateStatementException If a property can't be found on an value or we can't find a Argument for it.
 */
public final This bindBeanList(String key, List<?> values, List<String> propertyNames) throws UnableToCreateStatementException {
    if (values.isEmpty()) {
        throw new IllegalArgumentException(getClass().getSimpleName() + ".bindBeanList was called with no values.");
    }
    if (propertyNames.isEmpty()) {
        throw new IllegalArgumentException(getClass().getSimpleName() + ".bindBeanList was called with no properties.");
    }
    StringBuilder names = new StringBuilder();
    StatementContext ctx = getContext();
    for (int valueIndex = 0; valueIndex < values.size(); valueIndex++) {
        if (valueIndex > 0) {
            names.append(',');
        }
        Object bean = values.get(valueIndex);
        BeanPropertyArguments beanProperties = new BeanPropertyArguments(null, bean);
        names.append("(");
        for (int propertyIndex = 0; propertyIndex < propertyNames.size(); propertyIndex++) {
            if (propertyIndex > 0) {
                names.append(",");
            }
            String propertyName = propertyNames.get(propertyIndex);
            String name = "__" + key + "_" + valueIndex + "_" + propertyName;
            names.append(':').append(name);
            Argument argument = beanProperties.find(propertyName, ctx).orElseThrow(() -> new UnableToCreateStatementException("Unable to get " + propertyName + " argument for " + bean, ctx));
            bind(name, argument);
        }
        names.append(")");
    }
    return define(key, names.toString());
}
Also used : InputStreamArgument(org.jdbi.v3.core.argument.InputStreamArgument) NullArgument(org.jdbi.v3.core.argument.NullArgument) ObjectArgument(org.jdbi.v3.core.argument.ObjectArgument) Argument(org.jdbi.v3.core.argument.Argument) CharacterStreamArgument(org.jdbi.v3.core.argument.CharacterStreamArgument) BeanPropertyArguments(org.jdbi.v3.core.argument.BeanPropertyArguments)

Example 4 with StatementContext

use of org.jdbi.v3.core.statement.StatementContext in project jdbi by jdbi.

the class MapMapper method specialize.

@Override
public RowMapper<Map<String, Object>> specialize(ResultSet rs, StatementContext ctx) throws SQLException {
    ResultSetMetaData m = rs.getMetaData();
    int columnCount = m.getColumnCount();
    String[] columnNames = new String[columnCount + 1];
    for (int i = 1; i <= columnCount; i++) {
        String key = m.getColumnName(i);
        String alias = m.getColumnLabel(i);
        if (alias == null) {
            alias = key;
        }
        if (foldCase) {
            alias = alias.toLowerCase(Locale.ROOT);
        }
        columnNames[i] = alias;
    }
    return (r, c) -> {
        Map<String, Object> row = new LinkedHashMap<>(columnCount);
        for (int i = 1; i <= columnCount; i++) {
            row.put(columnNames[i], rs.getObject(i));
        }
        return row;
    };
}
Also used : ResultSetMetaData(java.sql.ResultSetMetaData) LinkedHashMap(java.util.LinkedHashMap) SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) Locale(java.util.Locale) Map(java.util.Map) ResultSetMetaData(java.sql.ResultSetMetaData) StatementContext(org.jdbi.v3.core.statement.StatementContext) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 5 with StatementContext

use of org.jdbi.v3.core.statement.StatementContext in project jdbi by jdbi.

the class SqlBatchHandler method invoke.

@Override
public Object invoke(Object target, Object[] args, HandleSupplier h) {
    final Handle handle = h.getHandle();
    final String sql = locateSql(handle);
    final int chunkSize = batchChunkSize.call(args);
    final Iterator<Object[]> batchArgs = zipArgs(getMethod(), args);
    ResultIterator<Object> result;
    if (batchArgs.hasNext()) {
        result = new ResultIterator<Object>() {

            ResultIterator<?> batchResult;

            boolean closed = false;

            {
                // Ensure our batchResult is prepared, so we can get its context
                hasNext();
            }

            @Override
            public boolean hasNext() {
                if (closed) {
                    throw new IllegalStateException("closed");
                }
                // first, any elements already buffered?
                if (batchResult != null) {
                    if (batchResult.hasNext()) {
                        return true;
                    }
                    // no more in this chunk, release resources
                    batchResult.close();
                }
                // more chunks?
                if (!batchArgs.hasNext()) {
                    return false;
                }
                // execute a single chunk and buffer
                PreparedBatch batch = handle.prepareBatch(sql);
                for (int i = 0; i < chunkSize && batchArgs.hasNext(); i++) {
                    applyCustomizers(batch, batchArgs.next());
                    batch.add();
                }
                batchResult = executeBatch(handle, batch);
                // recurse to ensure we actually got elements
                return hasNext();
            }

            @Override
            public Object next() {
                if (closed) {
                    throw new IllegalStateException("closed");
                }
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                return batchResult.next();
            }

            @Override
            public StatementContext getContext() {
                return batchResult.getContext();
            }

            @Override
            public void close() {
                closed = true;
                batchResult.close();
            }
        };
    } else {
        PreparedBatch dummy = handle.prepareBatch(sql);
        result = new ResultIterator<Object>() {

            @Override
            public void close() {
            // no op
            }

            @Override
            public StatementContext getContext() {
                return dummy.getContext();
            }

            @Override
            public boolean hasNext() {
                return false;
            }

            @Override
            public Object next() {
                throw new NoSuchElementException();
            }
        };
    }
    ResultIterable<Object> iterable = ResultIterable.of(result);
    return magic.mappedResult(iterable, result.getContext());
}
Also used : Handle(org.jdbi.v3.core.Handle) StatementContext(org.jdbi.v3.core.statement.StatementContext) PreparedBatch(org.jdbi.v3.core.statement.PreparedBatch) NoSuchElementException(java.util.NoSuchElementException)

Aggregations

StatementContext (org.jdbi.v3.core.statement.StatementContext)9 Type (java.lang.reflect.Type)7 SQLException (java.sql.SQLException)7 ResultSet (java.sql.ResultSet)6 ArrayList (java.util.ArrayList)5 Map (java.util.Map)5 List (java.util.List)4 RowMapper (org.jdbi.v3.core.mapper.RowMapper)4 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 ColumnMapper (org.jdbi.v3.core.mapper.ColumnMapper)3 ByteArrayInputStream (java.io.ByteArrayInputStream)2 IOException (java.io.IOException)2 StringReader (java.io.StringReader)2 Constructor (java.lang.reflect.Constructor)2 Field (java.lang.reflect.Field)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 Timestamp (java.sql.Timestamp)2 PMessage (net.morimekta.providence.PMessage)2 PMessageDescriptor (net.morimekta.providence.descriptor.PMessageDescriptor)2 NullArgument (org.jdbi.v3.core.argument.NullArgument)2