Search in sources :

Example 1 with Attribute

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

the class SchemaUpdater method update.

public void update() {
    SchemaModifier schema = new SchemaModifier(configuration);
    schema.createTables(mode);
    if (mode == TableCreationMode.DROP_CREATE) {
        // don't need to check missing columns
        return;
    }
    Function<String, String> columnTransformer = configuration.getColumnTransformer();
    Function<String, String> tableTransformer = configuration.getTableTransformer();
    // check for missing columns
    List<Attribute> missingAttributes = new ArrayList<>();
    for (Type<?> type : configuration.getModel().getTypes()) {
        if (type.isView()) {
            continue;
        }
        String tableName = type.getName();
        if (tableTransformer != null) {
            tableName = tableTransformer.apply(tableName);
        }
        Cursor cursor = queryFunction.apply("PRAGMA table_info(" + tableName + ")");
        Map<String, Attribute> map = new LinkedHashMap<>();
        for (Attribute attribute : type.getAttributes()) {
            if (attribute.isAssociation() && !attribute.isForeignKey()) {
                continue;
            }
            if (columnTransformer == null) {
                map.put(attribute.getName(), attribute);
            } else {
                map.put(columnTransformer.apply(attribute.getName()), attribute);
            }
        }
        if (cursor.getCount() > 0) {
            int nameIndex = cursor.getColumnIndex("name");
            while (cursor.moveToNext()) {
                String name = cursor.getString(nameIndex);
                map.remove(name);
            }
        }
        cursor.close();
        // whats left in the map are are the missing columns for this type
        missingAttributes.addAll(map.values());
    }
    // foreign keys are created last
    Collections.sort(missingAttributes, new Comparator<Attribute>() {

        @Override
        public int compare(Attribute lhs, Attribute rhs) {
            if (lhs.isForeignKey() && rhs.isForeignKey()) {
                return 0;
            }
            if (lhs.isForeignKey()) {
                return 1;
            }
            return -1;
        }
    });
    for (Attribute<?, ?> attribute : missingAttributes) {
        schema.addColumn(attribute);
    }
}
Also used : Attribute(io.requery.meta.Attribute) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) SchemaModifier(io.requery.sql.SchemaModifier) LinkedHashMap(java.util.LinkedHashMap)

Example 2 with Attribute

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

the class SelectResult method iterator.

@Override
public CloseableIterator<E> iterator(int skip, int take) {
    Statement statement = null;
    try {
        // connection held by the iterator if statement not reused
        BoundParameters parameters = createQuery(skip, take);
        statement = createStatement(!parameters.isEmpty());
        statement.setFetchSize(limit == null ? 0 : limit);
        StatementListener listener = configuration.getStatementListener();
        listener.beforeExecuteQuery(statement, sql, parameters);
        ResultSet results;
        if (parameters.isEmpty()) {
            results = statement.executeQuery(sql);
        } else {
            PreparedStatement preparedStatement = (PreparedStatement) statement;
            Mapping mapping = configuration.getMapping();
            for (int i = 0; i < parameters.count(); i++) {
                Expression expression = parameters.expressionAt(i);
                Object value = parameters.valueAt(i);
                if (expression instanceof Attribute) {
                    // extract foreign key reference
                    Attribute attribute = (Attribute) expression;
                    if (attribute.isAssociation() && (attribute.isForeignKey() || attribute.isKey())) {
                        // get the referenced value
                        if (value != null && ((Expression<?>) expression).getClassType().isAssignableFrom(value.getClass())) {
                            value = Attributes.replaceKeyReference(value, attribute);
                        }
                    }
                }
                mapping.write(expression, preparedStatement, i + 1, value);
            }
            results = preparedStatement.executeQuery();
        }
        listener.afterExecuteQuery(statement);
        return new ResultSetIterator<>(reader, results, selection, true, closeConnection);
    } catch (Exception e) {
        throw StatementExecutionException.closing(statement, e, sql);
    }
}
Also used : Expression(io.requery.query.Expression) Attribute(io.requery.meta.Attribute) PreparedStatement(java.sql.PreparedStatement) Statement(java.sql.Statement) ResultSet(java.sql.ResultSet) PreparedStatement(java.sql.PreparedStatement) SQLException(java.sql.SQLException)

Example 3 with Attribute

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

the class EntityMetaGenerator method generateType.

private void generateType(TypeSpec.Builder builder, TypeName targetName) {
    CodeBlock.Builder block = CodeBlock.builder().add("new $T<$T>($T.class, $S)\n", TypeBuilder.class, targetName, targetName, entity.tableName());
    block.add(".setBaseType($T.class)\n", ClassName.get(typeElement)).add(".setCacheable($L)\n", entity.isCacheable()).add(".setImmutable($L)\n", entity.isImmutable()).add(".setReadOnly($L)\n", entity.isReadOnly()).add(".setStateless($L)\n", entity.isStateless()).add(".setView($L)\n", entity.isView());
    String factoryName = entity.classFactoryName();
    if (!Names.isEmpty(factoryName)) {
        block.add(".setFactory(new $L())\n", ClassName.bestGuess(factoryName));
    } else if (entity.isImmutable()) {
        // returns this class as the builder
        TypeSpec.Builder supplier = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Supplier.class, typeName));
        supplier.addMethod(CodeGeneration.overridePublicMethod("get").returns(typeName).addStatement("return new $T()", typeName).build());
        block.add(".setBuilderFactory($L)\n", supplier.build());
        MethodSpec.Builder applyMethod = CodeGeneration.overridePublicMethod("apply").addParameter(typeName, "value").returns(targetName);
        // add embedded builder calls
        entity.attributes().stream().filter(AttributeDescriptor::isEmbedded).forEach(attribute -> graph.embeddedDescriptorOf(attribute).ifPresent(embedded -> embedded.builderType().ifPresent(type -> {
            String fieldName = attribute.fieldName() + "Builder";
            String methodName = attribute.setterName();
            applyMethod.addStatement("value.builder.$L(value.$L.build())", methodName, fieldName);
        })));
        applyMethod.addStatement(entity.builderType().isPresent() ? "return value.builder.build()" : "return value.build()");
        TypeSpec.Builder buildFunction = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Function.class, typeName, targetName)).addMethod(applyMethod.build());
        block.add(".setBuilderFunction($L)\n", buildFunction.build());
    } else {
        TypeSpec.Builder typeFactory = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Supplier.class, targetName)).addMethod(CodeGeneration.overridePublicMethod("get").addStatement("return new $T()", targetName).returns(targetName).build());
        block.add(".setFactory($L)\n", typeFactory.build());
    }
    ParameterizedTypeName proxyType = parameterizedTypeName(EntityProxy.class, targetName);
    TypeSpec.Builder proxyProvider = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Function.class, targetName, proxyType));
    MethodSpec.Builder proxyFunction = CodeGeneration.overridePublicMethod("apply").addParameter(targetName, "entity").returns(proxyType);
    if (entity.isImmutable() || entity.isUnimplementable()) {
        proxyFunction.addStatement("return new $T(entity, $L)", proxyType, TYPE_NAME);
    } else {
        proxyFunction.addStatement("return entity.$L", PROXY_NAME);
    }
    proxyProvider.addMethod(proxyFunction.build());
    block.add(".setProxyProvider($L)\n", proxyProvider.build());
    if (entity.tableAttributes().length > 0) {
        StringJoiner joiner = new StringJoiner(",", "new String[] {", "}");
        for (String attribute : entity.tableAttributes()) {
            joiner.add("\"" + attribute + "\"");
        }
        block.add(".setTableCreateAttributes($L)\n", joiner.toString());
    }
    if (entity.tableUniqueIndexes().length > 0) {
        StringJoiner joiner = new StringJoiner(",", "new String[] {", "}");
        for (String attribute : entity.tableUniqueIndexes()) {
            joiner.add("\"" + attribute + "\"");
        }
        block.add(".setTableUniqueIndexes($L)\n", joiner.toString());
    }
    attributeNames.forEach(name -> block.add(".addAttribute($L)\n", name));
    expressionNames.forEach(name -> block.add(".addExpression($L)\n", name));
    block.add(".build()");
    ParameterizedTypeName type = parameterizedTypeName(Type.class, targetName);
    builder.addField(FieldSpec.builder(type, TYPE_NAME, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("$L", block.build()).build());
}
Also used : EntityProxy(io.requery.proxy.EntityProxy) Modifier(javax.lang.model.element.Modifier) BooleanProperty(io.requery.proxy.BooleanProperty) FieldSpec(com.squareup.javapoet.FieldSpec) LongProperty(io.requery.proxy.LongProperty) VariableElement(javax.lang.model.element.VariableElement) ClassName(com.squareup.javapoet.ClassName) QueryAttribute(io.requery.meta.QueryAttribute) TypeBuilder(io.requery.meta.TypeBuilder) NumericAttribute(io.requery.meta.NumericAttribute) TypeElement(javax.lang.model.element.TypeElement) ReferentialAction(io.requery.ReferentialAction) HashSet(java.util.HashSet) Function(io.requery.util.function.Function) ByteProperty(io.requery.proxy.ByteProperty) Diagnostic(javax.tools.Diagnostic) Type(io.requery.meta.Type) FloatProperty(io.requery.proxy.FloatProperty) ElementFilter(javax.lang.model.util.ElementFilter) LinkedList(java.util.LinkedList) CodeBlock(com.squareup.javapoet.CodeBlock) Property(io.requery.proxy.Property) MethodSpec(com.squareup.javapoet.MethodSpec) IntProperty(io.requery.proxy.IntProperty) ExecutableElement(javax.lang.model.element.ExecutableElement) Supplier(io.requery.util.function.Supplier) Set(java.util.Set) ParameterizedTypeName(com.squareup.javapoet.ParameterizedTypeName) IOException(java.io.IOException) Attribute(io.requery.meta.Attribute) PropertyState(io.requery.proxy.PropertyState) TypeSpec(com.squareup.javapoet.TypeSpec) Order(io.requery.query.Order) QueryExpression(io.requery.meta.QueryExpression) TypeKind(javax.lang.model.type.TypeKind) CascadeAction(io.requery.CascadeAction) TypeMirror(javax.lang.model.type.TypeMirror) List(java.util.List) Cardinality(io.requery.meta.Cardinality) DoubleProperty(io.requery.proxy.DoubleProperty) StringJoiner(java.util.StringJoiner) ProcessingEnvironment(javax.annotation.processing.ProcessingEnvironment) TypeName(com.squareup.javapoet.TypeName) Optional(java.util.Optional) ShortProperty(io.requery.proxy.ShortProperty) StringAttribute(io.requery.meta.StringAttribute) MethodSpec(com.squareup.javapoet.MethodSpec) TypeBuilder(io.requery.meta.TypeBuilder) CodeBlock(com.squareup.javapoet.CodeBlock) Function(io.requery.util.function.Function) Supplier(io.requery.util.function.Supplier) StringJoiner(java.util.StringJoiner) ParameterizedTypeName(com.squareup.javapoet.ParameterizedTypeName) TypeSpec(com.squareup.javapoet.TypeSpec)

Example 4 with Attribute

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

the class FunctionalTest method testFindByCompositeKey.

@Test
public void testFindByCompositeKey() {
    Group group = new Group();
    group.setName("group");
    group.setType(GroupType.PRIVATE);
    Person person = randomPerson();
    person.getGroups().add(group);
    data.insert(person);
    assertTrue(person.getId() > 0);
    // create the composite key
    Map<Attribute<Group_Person, Integer>, Integer> map = new LinkedHashMap<>();
    map.put(Group_Person.GROUPS_ID, group.getId());
    map.put(Group_Person.PERSON_ID, person.getId());
    CompositeKey<Group_Person> compositeKey = new CompositeKey<>(map);
    Group_Person joined = data.findByKey(Group_Person.class, compositeKey);
    assertNotNull(joined);
}
Also used : Group(io.requery.test.model.Group) Group_Person(io.requery.test.model.Group_Person) CompositeKey(io.requery.proxy.CompositeKey) Attribute(io.requery.meta.Attribute) Person(io.requery.test.model.Person) Group_Person(io.requery.test.model.Group_Person) LinkedHashMap(java.util.LinkedHashMap) Test(org.junit.Test)

Example 5 with Attribute

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

the class EntityWriter method updateAssociation.

@SuppressWarnings("unchecked")
private void updateAssociation(Cascade mode, E entity, EntityProxy<E> proxy, Attribute<E, ?> attribute) {
    switch(attribute.getCardinality()) {
        case ONE_TO_ONE:
            S value = (S) proxy.get(attribute, false);
            if (value != null) {
                Attribute<S, Object> mapped = Attributes.get(attribute.getMappedAttribute());
                EntityProxy<S> referred = context.proxyOf(value, true);
                referred.set(mapped, entity, PropertyState.MODIFIED);
                cascadeWrite(mode, value, referred);
            } else if (!stateless) {
                throw new PersistenceException("1-1 relationship can only be removed from the owning side");
            }
            break;
        case ONE_TO_MANY:
            Object relation = proxy.get(attribute, false);
            if (relation instanceof ObservableCollection) {
                ObservableCollection<S> collection = (ObservableCollection<S>) relation;
                CollectionChanges<?, S> changes = (CollectionChanges<?, S>) collection.observer();
                List<S> added = new ArrayList<>(changes.addedElements());
                List<S> removed = new ArrayList<>(changes.removedElements());
                changes.clear();
                for (S element : added) {
                    updateMappedAssociation(mode, element, attribute, entity);
                }
                for (S element : removed) {
                    updateMappedAssociation(Cascade.UPDATE, element, attribute, null);
                }
            } else if (relation instanceof Iterable) {
                Iterable<S> iterable = (Iterable<S>) relation;
                for (S added : iterable) {
                    updateMappedAssociation(mode, added, attribute, entity);
                }
            } else {
                throw new IllegalStateException("unsupported relation type " + relation);
            }
            break;
        case MANY_TO_MANY:
            final Class referencedClass = attribute.getReferencedClass();
            if (referencedClass == null) {
                throw new IllegalStateException("Invalid referenced class in " + attribute);
            }
            Type<?> referencedType = model.typeOf(referencedClass);
            QueryAttribute<S, Object> tKey = null;
            QueryAttribute<S, Object> uKey = null;
            for (Attribute a : referencedType.getAttributes()) {
                Class<?> referenced = a.getReferencedClass();
                if (referenced != null) {
                    if (tKey == null && entityClass.isAssignableFrom(referenced)) {
                        tKey = Attributes.query(a);
                    } else if (attribute.getElementClass() != null && attribute.getElementClass().isAssignableFrom(referenced)) {
                        uKey = Attributes.query(a);
                    }
                }
            }
            Objects.requireNotNull(tKey);
            Objects.requireNotNull(uKey);
            Attribute<E, Object> tRef = Attributes.get(tKey.getReferencedAttribute());
            Attribute<S, Object> uRef = Attributes.get(uKey.getReferencedAttribute());
            CollectionChanges<?, S> changes = null;
            relation = proxy.get(attribute, false);
            Iterable<S> addedElements = (Iterable<S>) relation;
            boolean isObservable = relation instanceof ObservableCollection;
            if (relation instanceof ObservableCollection) {
                ObservableCollection<S> collection = (ObservableCollection<S>) relation;
                changes = (CollectionChanges<?, S>) collection.observer();
                if (changes != null) {
                    addedElements = changes.addedElements();
                }
            }
            for (S added : addedElements) {
                S junction = (S) referencedType.getFactory().get();
                EntityProxy<S> junctionProxy = context.proxyOf(junction, false);
                EntityProxy<S> uProxy = context.proxyOf(added, false);
                if (attribute.getCascadeActions().contains(CascadeAction.SAVE)) {
                    cascadeWrite(mode, added, uProxy);
                }
                Object tValue = proxy.get(tRef, false);
                Object uValue = uProxy.get(uRef, false);
                junctionProxy.set(tKey, tValue, PropertyState.MODIFIED);
                junctionProxy.set(uKey, uValue, PropertyState.MODIFIED);
                Cascade cascade = isObservable && mode == Cascade.UPSERT ? Cascade.UPSERT : Cascade.INSERT;
                cascadeWrite(cascade, junction, null);
            }
            if (changes != null) {
                Object keyValue = proxy.get(tRef, false);
                for (S removed : changes.removedElements()) {
                    Object otherValue = context.proxyOf(removed, false).get(uRef);
                    Class<? extends S> removeType = (Class<? extends S>) referencedType.getClassType();
                    Supplier<? extends Scalar<Integer>> query = queryable.delete(removeType).where(tKey.equal(keyValue)).and(uKey.equal(otherValue));
                    int count = query.get().value();
                    if (count != 1) {
                        throw new RowCountException(entity.getClass(), 1, count);
                    }
                }
                changes.clear();
            }
            break;
        case MANY_TO_ONE:
        default:
            break;
    }
    context.read(type.getClassType()).refresh(entity, proxy, attribute);
}
Also used : QueryAttribute(io.requery.meta.QueryAttribute) Attribute(io.requery.meta.Attribute) UPDATE(io.requery.query.element.QueryType.UPDATE) ArrayList(java.util.ArrayList) CollectionChanges(io.requery.proxy.CollectionChanges) ObservableCollection(io.requery.util.ObservableCollection) PersistenceException(io.requery.PersistenceException)

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