Search in sources :

Example 16 with Attribute

use of io.requery.meta.Attribute in project requery by requery.

the class EntityWriter method batchInsert.

GeneratedKeys<E> batchInsert(Iterable<E> entities, boolean returnKeys) {
    // true if using JDBC batching
    final boolean batchInStatement = canBatchInStatement();
    final int batchSize = context.getBatchUpdateSize();
    final EntityReader<E, S> reader = context.read(entityClass);
    final Iterator<E> iterator = entities.iterator();
    final boolean isImmtuable = type.isImmutable();
    final GeneratedKeys<E> keys = returnKeys && hasGeneratedKey ? new GeneratedKeys<E>() : null;
    int collectionSize = entities instanceof Collection ? ((Collection) entities).size() : -1;
    @SuppressWarnings("unchecked") final E[] elements = (E[]) new Object[Math.min(collectionSize, batchSize)];
    while (iterator.hasNext()) {
        int index = 0;
        Map<Class<? extends S>, List<S>> associations = new HashMap<>();
        while (iterator.hasNext() && index < batchSize) {
            E entity = iterator.next();
            EntityProxy<E> proxy = proxyProvider.apply(entity);
            elements[index] = entity;
            if (hasForeignKeys) {
                for (Attribute<E, ?> attribute : associativeAttributes) {
                    S referenced = foreignKeyReference(proxy, attribute);
                    if (referenced != null) {
                        EntityProxy<S> otherProxy = context.proxyOf(referenced, false);
                        if (otherProxy != null && !otherProxy.isLinked()) {
                            Class<? extends S> key = otherProxy.type().getClassType();
                            List<S> values = associations.get(key);
                            if (values == null) {
                                associations.put(key, values = new ArrayList<>());
                            }
                            values.add(referenced);
                        }
                    }
                }
            }
            incrementVersion(proxy);
            context.getStateListener().preInsert(entity, proxy);
            index++;
        }
        cascadeBatch(associations);
        final int count = index;
        GeneratedResultReader keyReader = null;
        if (hasGeneratedKey) {
            keyReader = new GeneratedResultReader() {

                @Override
                public void read(int index, ResultSet results) throws SQLException {
                    // check if reading batch keys, otherwise read 1
                    int readCount = batchInStatement ? count : 1;
                    for (int i = index; i < index + readCount; i++) {
                        if (!results.next()) {
                            throw new IllegalStateException();
                        }
                        EntityProxy<E> proxy = proxyProvider.apply(elements[i]);
                        Settable<E> keyProxy = keys == null ? proxy : keys.proxy(isImmtuable ? null : proxy);
                        readGeneratedKeys(keyProxy, results);
                    }
                }

                @Override
                public String[] generatedColumns() {
                    return generatedColumnNames;
                }
            };
        }
        BatchUpdateOperation<E> operation = new BatchUpdateOperation<>(context, elements, count, this, keyReader, batchInStatement);
        QueryElement<int[]> query = new QueryElement<>(QueryType.INSERT, model, operation);
        query.from(entityClass);
        for (Attribute attribute : bindableAttributes) {
            query.value((Expression) attribute, null);
        }
        int[] updates = query.get();
        for (int i = 0; i < updates.length; i++) {
            E entity = elements[i];
            EntityProxy<E> proxy = proxyProvider.apply(entity);
            checkRowsAffected(updates[i], entity, proxy);
            proxy.link(reader);
            updateAssociations(Cascade.AUTO, entity, proxy, null);
            context.getStateListener().postInsert(entity, proxy);
            // cache entity
            if (cacheable) {
                cache.put(entityClass, proxy.key(), entity);
            }
        }
    }
    return keys;
}
Also used : UPDATE(io.requery.query.element.QueryType.UPDATE) HashMap(java.util.HashMap) SQLException(java.sql.SQLException) QueryAttribute(io.requery.meta.QueryAttribute) Attribute(io.requery.meta.Attribute) ArrayList(java.util.ArrayList) QueryElement(io.requery.query.element.QueryElement) EntityProxy(io.requery.proxy.EntityProxy) Settable(io.requery.proxy.Settable) ResultSet(java.sql.ResultSet) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) ObservableCollection(io.requery.util.ObservableCollection) Collection(java.util.Collection)

Example 17 with Attribute

use of io.requery.meta.Attribute in project requery by requery.

the class EntityReader method fromResult.

final E fromResult(E entity, ResultSet results, Attribute[] selection) throws SQLException {
    // if refreshing (entity not null) overwrite the properties
    boolean overwrite = entity != null || stateless;
    if (entity == null) {
        // get or create the entity object
        if (cacheable) {
            synchronized (type) {
                // try lookup cached object
                final Object key = readCacheKey(results);
                if (key != null) {
                    entity = cache.get(type.getClassType(), key);
                }
                // not cached create a new one
                if (entity == null) {
                    entity = createEntity();
                    if (key != null) {
                        cache.put(type.getClassType(), key, entity);
                    }
                }
            }
        } else {
            entity = createEntity();
        }
    }
    // set the properties
    EntityProxy<E> proxy = type.getProxyProvider().apply(entity);
    synchronized (proxy.syncObject()) {
        proxy.link(this);
        int index = 1;
        for (Attribute expression : selection) {
            @SuppressWarnings("unchecked") Attribute<E, ?> attribute = (Attribute<E, ?>) expression;
            boolean isAssociation = attribute.isAssociation();
            if ((attribute.isForeignKey() || attribute.isKey()) && isAssociation) {
                // handle loading the foreign key into referenced object
                Attribute referenced = Attributes.get(attribute.getReferencedAttribute());
                Object key = mapping.read((Expression) referenced, results, index);
                if (key != null) {
                    Object value = proxy.get(attribute, false);
                    if (value == null) {
                        // create one...
                        Class classType = attribute.getClassType();
                        EntityReader reader = context.read(classType);
                        value = reader.createEntity();
                    }
                    context.proxyOf(value, false).set(Attributes.get(attribute.getReferencedAttribute()), key, PropertyState.LOADED);
                    // leave in fetch state if only key is loaded
                    PropertyState state = PropertyState.LOADED;
                    if (!stateless) {
                        state = proxy.getState(attribute);
                        state = state == PropertyState.LOADED ? state : PropertyState.FETCH;
                    }
                    proxy.setObject(attribute, value, state);
                }
            } else if (isAssociation) {
                continue;
            } else if (overwrite || proxy.getState(attribute) != PropertyState.MODIFIED) {
                if (attribute.getPrimitiveKind() != null) {
                    readPrimitiveField(proxy, attribute, results, index);
                } else {
                    Object value = mapping.read((Expression) attribute, results, index);
                    proxy.setObject(attribute, value, PropertyState.LOADED);
                }
            }
            index++;
        }
    }
    context.getStateListener().postLoad(entity, proxy);
    return entity;
}
Also used : WHERE(io.requery.sql.Keyword.WHERE) QueryAttribute(io.requery.meta.QueryAttribute) Attribute(io.requery.meta.Attribute) PropertyState(io.requery.proxy.PropertyState)

Example 18 with Attribute

use of io.requery.meta.Attribute in project requery by requery.

the class EntityReader method refresh.

private E refresh(E entity, EntityProxy<E> proxy, final Set<Attribute<E, ?>> attributes) {
    Predicate<Attribute<E, ?>> basicFilter = new Predicate<Attribute<E, ?>>() {

        @Override
        public boolean test(Attribute<E, ?> value) {
            return attributes.contains(value) && (!value.isAssociation() || value.isForeignKey());
        }
    };
    FilteringIterator<Attribute<E, ?>> filterator = new FilteringIterator<>(attributes.iterator(), basicFilter);
    if (filterator.hasNext()) {
        QueryBuilder qb = new QueryBuilder(context.getQueryBuilderOptions()).keyword(SELECT).commaSeparated(filterator, new QueryBuilder.Appender<Attribute<E, ?>>() {

            @Override
            public void append(QueryBuilder qb, Attribute<E, ?> value) {
                String versionColumn = context.getPlatform().versionColumnDefinition().columnName();
                if (value.isVersion() && versionColumn != null) {
                    qb.append(versionColumn).space().append(AS).space().append(value.getName()).space();
                } else {
                    qb.attribute(value);
                }
            }
        }).keyword(FROM).tableName(type.getName()).keyword(WHERE).appendWhereConditions(type.getKeyAttributes());
        String sql = qb.toString();
        try (Connection connection = context.getConnection();
            PreparedStatement statement = connection.prepareStatement(sql)) {
            int index = 1;
            for (Attribute<E, ?> attribute : type.getKeyAttributes()) {
                Object value = proxy.getKey(attribute);
                if (value == null) {
                    throw new MissingKeyException(proxy);
                }
                mapping.write((Expression) attribute, statement, index++, value);
            }
            context.getStatementListener().beforeExecuteQuery(statement, sql, null);
            ResultSet results = statement.executeQuery();
            context.getStatementListener().afterExecuteQuery(statement);
            if (results.next()) {
                Attribute[] selection = new Attribute[attributes.size()];
                attributes.toArray(selection);
                // modify the given entity
                if (type.isImmutable()) {
                    entity = fromBuilder(results, selection);
                } else {
                    entity = fromResult(entity, results, selection);
                }
            }
        } catch (SQLException e) {
            throw new PersistenceException(e);
        }
    }
    // refresh associations
    for (Attribute<E, ?> attribute : attributes) {
        // if it's a foreign key its resolved as part of the basic properties
        if (attribute.isAssociation()) {
            refreshAssociation(proxy, attribute);
        }
    }
    return entity;
}
Also used : QueryAttribute(io.requery.meta.QueryAttribute) Attribute(io.requery.meta.Attribute) WHERE(io.requery.sql.Keyword.WHERE) SQLException(java.sql.SQLException) FilteringIterator(io.requery.util.FilteringIterator) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) Predicate(io.requery.util.function.Predicate) ResultSet(java.sql.ResultSet) PersistenceException(io.requery.PersistenceException)

Example 19 with Attribute

use of io.requery.meta.Attribute in project requery by requery.

the class EntityReader method batchRefresh.

@SafeVarargs
final Iterable<E> batchRefresh(Iterable<E> entities, Attribute<E, ?>... attributes) {
    // if the type is immutable return a new collection with the rebuilt objects
    final Collection<E> collection = type.isImmutable() ? new ArrayList<E>() : null;
    if (keyAttribute == null) {
        // non optimal case objects with multiple keys or no keys
        for (E entity : entities) {
            entity = refresh(entity, type.getProxyProvider().apply(entity), attributes);
            if (collection != null) {
                collection.add(entity);
            }
        }
    } else {
        Set<Expression<?>> selection = new LinkedHashSet<>();
        Attribute[] selectAttributes;
        if (attributes == null || attributes.length == 0) {
            selection = defaultSelection;
            selectAttributes = defaultSelectionAttributes;
        } else {
            LinkedHashSet<Attribute> selectedAttributes = new LinkedHashSet<>();
            selection.add(keyAttribute);
            selectedAttributes.add(keyAttribute);
            for (Attribute<E, ?> attribute : attributes) {
                if (attribute.isVersion()) {
                    selection.add(aliasVersion(attribute));
                } else if (!attribute.isAssociation()) {
                    QueryAttribute<E, ?> queryAttribute = Attributes.query(attribute);
                    selection.add(queryAttribute);
                }
                selectedAttributes.add(attribute);
            }
            selectAttributes = selectedAttributes.toArray(new Attribute[selection.size()]);
        }
        Map<Object, EntityProxy<E>> map = new HashMap<>();
        for (E entity : entities) {
            EntityProxy<E> proxy = type.getProxyProvider().apply(entity);
            Object key = proxy.key();
            if (key == null) {
                throw new MissingKeyException();
            }
            map.put(key, proxy);
        }
        Condition<?, ?> condition = Attributes.query(keyAttribute).in(map.keySet());
        if (type.isCacheable()) {
            final Consumer<E> collector = new Consumer<E>() {

                @Override
                public void accept(E e) {
                    if (collection != null) {
                        collection.add(e);
                    }
                }
            };
            // readResult will merge the results into the target object in cache mode
            ResultReader<E> resultReader = newResultReader(selectAttributes);
            SelectOperation<E> select = new SelectOperation<>(context, resultReader);
            QueryElement<? extends Result<E>> query = new QueryElement<>(QueryType.SELECT, context.getModel(), select);
            try (Result<E> result = query.select(selection).where(condition).get()) {
                result.each(collector);
            }
        } else {
            try (Result<Tuple> result = queryable.select(selection).where(condition).get()) {
                for (Tuple tuple : result) {
                    Object key = tuple.get((Expression) keyAttribute);
                    EntityProxy<E> proxy = map.get(key);
                    synchronized (proxy.syncObject()) {
                        for (Expression expression : selection) {
                            Object value = tuple.get(expression);
                            if (expression instanceof AliasedExpression) {
                                AliasedExpression aliased = (AliasedExpression) expression;
                                expression = aliased.getInnerExpression();
                            }
                            Attribute<E, Object> attribute = Attributes.query((Attribute) expression);
                            proxy.set(attribute, value, PropertyState.LOADED);
                        }
                    }
                }
            }
        }
        // associations TODO can be optimized
        if (attributes != null) {
            for (Attribute<E, ?> attribute : attributes) {
                if (attribute.isAssociation()) {
                    for (EntityProxy<E> proxy : map.values()) {
                        refreshAssociation(proxy, attribute);
                    }
                }
            }
        }
    }
    return collection == null ? entities : collection;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) WHERE(io.requery.sql.Keyword.WHERE) QueryAttribute(io.requery.meta.QueryAttribute) Attribute(io.requery.meta.Attribute) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) QueryElement(io.requery.query.element.QueryElement) AliasedExpression(io.requery.query.AliasedExpression) EntityProxy(io.requery.proxy.EntityProxy) Consumer(io.requery.util.function.Consumer) AliasedExpression(io.requery.query.AliasedExpression) Expression(io.requery.query.Expression) QueryAttribute(io.requery.meta.QueryAttribute) Tuple(io.requery.query.Tuple)

Example 20 with Attribute

use of io.requery.meta.Attribute in project requery by requery.

the class QueryBuilder method tableNames.

public QueryBuilder tableNames(Iterable<Expression<?>> values) {
    Set<Type<?>> types = new LinkedHashSet<>();
    for (Expression<?> expression : values) {
        if (expression.getExpressionType() == ExpressionType.ATTRIBUTE) {
            Attribute attribute = (Attribute) expression;
            types.add(attribute.getDeclaringType());
        }
    }
    return commaSeparated(types, new Appender<Type<?>>() {

        @Override
        public void append(QueryBuilder qb, Type<?> value) {
            tableName(value.getName());
        }
    });
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ExpressionType(io.requery.query.ExpressionType) Type(io.requery.meta.Type) Attribute(io.requery.meta.Attribute)

Aggregations

Attribute (io.requery.meta.Attribute)30 QueryAttribute (io.requery.meta.QueryAttribute)13 ClassName (com.squareup.javapoet.ClassName)5 FieldSpec (com.squareup.javapoet.FieldSpec)5 ParameterizedTypeName (com.squareup.javapoet.ParameterizedTypeName)5 TypeName (com.squareup.javapoet.TypeName)5 TypeSpec (com.squareup.javapoet.TypeSpec)5 EntityProxy (io.requery.proxy.EntityProxy)5 Expression (io.requery.query.Expression)5 ResultSet (java.sql.ResultSet)5 SQLException (java.sql.SQLException)5 ArrayList (java.util.ArrayList)5 List (java.util.List)5 MethodSpec (com.squareup.javapoet.MethodSpec)4 PropertyState (io.requery.proxy.PropertyState)4 UPDATE (io.requery.query.element.QueryType.UPDATE)4 StringJoiner (java.util.StringJoiner)4 TypeElement (javax.lang.model.element.TypeElement)4 TypeMirror (javax.lang.model.type.TypeMirror)4 CodeBlock (com.squareup.javapoet.CodeBlock)3