app/src/main/java/db/juhaku/juhakudb/core/android/transaction/QueryTransactionTemplate.java
/**
     * Cascade query for given query result of objects. Cascading will be done if fields of the
     * returned entities has EAGER loading allowed.
     *
     * @param result List of query result objects to cascade query for.
     * @param rootClass Root class of the queried entity.
     *
     * @since 2.0.0
     *
     * @hide
     */
Cascade query for given query result of objects. Cascading will be done if fields of the
returned entities has EAGER loading allowed.

@param result List of query result objects to cascade query for.
@param rootClass Root class of the queried entity.



@hide
Cascade query for given query result of objects . Cascading will be done if fields of the returned entities has EAGER loading allowed . @param result List of query result objects to cascade query for . @param rootClass Root class of the queried entity . @hide
private <E> void cascadeQuery(List<E> result, final Class<?> rootClass) {
        for (final E entity : result) {
            for (Field field : rootClass.getDeclaredFields()) {
                field.setAccessible(true);
                final Object fieldValue = ReflectionUtils.getFieldValue(entity, field);
                final Class<?> type = ReflectionUtils.getFieldType(field);
                if (isPrimaryKeyReverseJoinEagerFetchAllowed(field) && !isCached(new FetchHistory(field.getName(), entity.getClass()))) {
                    Query primaryKeySubQuery = getProcessor().createQuery(type, new Filter() {
                        @Override
                        public void filter(Root root, PredicateBuilder builder) {
                            String alias = Alias.forModel(rootClass);
                            Object id = ReflectionUtils.getIdFieldValue(entity);
                            root.join(getAssociatedRootClassFieldNameByType(type, rootClass),
                                    alias, JoinMode.INNER_JOIN);
                            builder.eq(String.valueOf(alias)
                                    .concat(".").concat(resolveIdColumn(rootClass)), id);
                        }
                    });
                    cache(new FetchHistory(field.getName(), entity.getClass()));
                    query(primaryKeySubQuery, type, entity, field);
                    /*
                     * After cascading query is made remove it from cache in case next entity wants
                     * to make same cascading query.
                     */
                    removeFromCache(new FetchHistory(field.getName(), entity.getClass()));
                } else {
                    if (isForeignKeyJoinEagerFetchAllowed(field) && fieldValue != null) {
                        Query associatedSubQuery = getProcessor().createQuery(type, new Filter() {
                            @Override
                            public void filter(Root root, PredicateBuilder builder) {
                                String alias = Alias.forModel(type);
                                Object id = ReflectionUtils.getFieldValue(fieldValue, ReflectionUtils.findIdField(fieldValue.getClass()));
                                builder.eq(alias.concat(".").concat(resolveIdColumn(type)), id);
                            }
                        });
                        query(associatedSubQuery, type, entity, field);
                    }
                }
                if (fieldValue != null && type.isAnnotationPresent(Entity.class)) {
                    if (Collection.class.isAssignableFrom(fieldValue.getClass())) {
                        Object next;
                        if ((next = ((Collection) fieldValue).iterator().hasNext()
                                ? ((Collection) fieldValue).iterator().next() : null) != null) {
                            if (allowCascadingToFetchElements(next)) {
                                cascadeQuery((List<Object>) fieldValue, type);
                            }
                        }
                    } else if (allowCascadingToFetchElements(fieldValue)) {
                        cascadeQuery(Arrays.asList(fieldValue), type);
                    }
                }
            }
        }
    }
private < E > void cascadeQuery ( List < E > result , final Class < ? > rootClass ) { for ( final E entity : result ) { for ( Field field : rootClass . getDeclaredFields ( ) ) { field . setAccessible ( true ) ; final Object fieldValue = ReflectionUtils . getFieldValue ( entity , field ) ; final Class < ? > type = ReflectionUtils . getFieldType ( field ) ; if ( isPrimaryKeyReverseJoinEagerFetchAllowed ( field ) && ! isCached ( new FetchHistory ( field . getName ( ) , entity . getClass ( ) ) ) ) { Query primaryKeySubQuery = getProcessor ( ) . createQuery ( type , new Filter ( ) { @ Override public void filter ( Root root , PredicateBuilder builder ) { String alias = Alias . forModel ( rootClass ) ; Object id = ReflectionUtils . getIdFieldValue ( entity ) ; root . join ( getAssociatedRootClassFieldNameByType ( type , rootClass ) , alias , JoinMode . INNER_JOIN ) ; builder . eq ( String . valueOf ( alias ) . concat ( "." ) . concat ( resolveIdColumn ( rootClass ) ) , id ) ; } } ) ; cache ( new FetchHistory ( field . getName ( ) , entity . getClass ( ) ) ) ; query ( primaryKeySubQuery , type , entity , field ) ; /*
                     * After cascading query is made remove it from cache in case next entity wants
                     * to make same cascading query.
                     */ removeFromCache ( new FetchHistory ( field . getName ( ) , entity . getClass ( ) ) ) ; } else { if ( isForeignKeyJoinEagerFetchAllowed ( field ) && fieldValue != null ) { Query associatedSubQuery = getProcessor ( ) . createQuery ( type , new Filter ( ) { @ Override public void filter ( Root root , PredicateBuilder builder ) { String alias = Alias . forModel ( type ) ; Object id = ReflectionUtils . getFieldValue ( fieldValue , ReflectionUtils . findIdField ( fieldValue . getClass ( ) ) ) ; builder . eq ( alias . concat ( "." ) . concat ( resolveIdColumn ( type ) ) , id ) ; } } ) ; query ( associatedSubQuery , type , entity , field ) ; } } if ( fieldValue != null && type . isAnnotationPresent ( Entity . class ) ) { if ( Collection . class . isAssignableFrom ( fieldValue . getClass ( ) ) ) { Object next ; if ( ( next = ( ( Collection ) fieldValue ) . iterator ( ) . hasNext ( ) ? ( ( Collection ) fieldValue ) . iterator ( ) . next ( ) : null ) != null ) { if ( allowCascadingToFetchElements ( next ) ) { cascadeQuery ( ( List < Object > ) fieldValue , type ) ; } } } else if ( allowCascadingToFetchElements ( fieldValue ) ) { cascadeQuery ( Arrays . asList ( fieldValue ) , type ) ; } } } } }
Cascade query for given query result of objects.
Cascade query for given query result of objects .
// set primary key associations if available // If field references to a foreign key in another table fetch items if necessary // TODO may break the functionality if multiple joins occurs to same table with same type. // Cascade query for fetched elements. // Check cascading for first element in the list as rest of element's are from same template.