Skip to content

Commit

Permalink
Merge pull request #2 from tchlyah/fix/cb-relationships
Browse files Browse the repository at this point in the history
Fix Couchbase entity relationships
  • Loading branch information
gkysaad authored Aug 22, 2021
2 parents dd1dcb0 + 153713d commit 06a39c8
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,15 @@ import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.neo4j.repository.Neo4jRepository;
<%_ } _%>
<%_ if (databaseTypeCouchbase) { _%>
import org.springframework.data.domain.Sort;
import com.couchbase.client.java.query.QueryScanConsistency;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.ScanConsistency;
<%_ if (relationshipsContainEagerLoad) { _%>
<%_ if (relationships.length != 0) { _%>
import org.springframework.data.couchbase.repository.Query;
import org.springframework.data.domain.PageImpl;
import java.util.Optional;
import static <%= packageName %>.repository.N1qlCouchbaseRepository.pageableStatement;
<%_ } _%>
<%_ } _%>
<%_ if (searchEngineCouchbase) { _%>
import <%= packageName %>.repository.search.SearchCouchbaseRepository;
<%_ } _%>
<%_ if (databaseTypeCassandra) { _%>
import org.springframework.data.cassandra.repository.CassandraRepository;
<%_ } _%>
Expand Down Expand Up @@ -125,50 +122,52 @@ public interface <%= entityClass %>Repository extends <% if (databaseTypeSql) {
@Query("{}")
Optional<<%= persistClass %>> findOneWithEagerRelationships(<%= primaryKey.type %> id);
<%_
} else if (databaseTypeCouchbase) { %>
}
}

if (databaseTypeCouchbase && relationships.length != 0) { %>

String SELECT = "SELECT #{#n1ql.fields}, #{#n1ql.bucket}.*" + <%
String SELECT = "SELECT meta(b).id as __id, meta(b).cas as __cas, b.*" + <%
for (const relationship of relationships) {
if (relationship.collection) {
%> ", (SELECT <%= relationship.relationshipFieldName %>.*, meta(<%= relationship.relationshipFieldName %>).id FROM <%= relationship.relationshipFieldNamePlural %> <%= relationship.relationshipFieldName %>) as <%= relationship.relationshipFieldNamePlural %>" + <%
%> ", (SELECT `<%= relationship.relationshipFieldName %>`.*, meta(`<%= relationship.relationshipFieldName %>`).id FROM `<%= relationship.relationshipFieldNamePlural %>` `<%= relationship.relationshipFieldName %>`) as `<%= relationship.relationshipFieldNamePlural %>`" + <%
} else {
%> ", (SELECT <%= relationship.relationshipFieldName %>.*, meta(<%= relationship.relationshipFieldName %>).id)[0] as <%= relationship.relationshipFieldName %>" + <%
%> ", (SELECT `<%= relationship.relationshipFieldName %>`.*, meta(`<%= relationship.relationshipFieldName %>`).id)[0] as `<%= relationship.relationshipFieldName %>`" + <%
}
} %>
" FROM #{#n1ql.bucket}";
" FROM #{#n1ql.bucket} b";

String JOIN = <%
relationships.forEach(function (relationship, index) {
if (!relationship.collection) { %>
" LEFT JOIN #{#n1ql.bucket} <%= relationship.relationshipFieldName %> ON KEYS #{#n1ql.bucket}.<%= relationship.relationshipFieldName %>"<%
" LEFT JOIN #{#n1ql.bucket} `<%= relationship.relationshipFieldName %>` ON KEYS b.`<%= relationship.relationshipFieldName %>`"<%
} else { %>
" LEFT NEST #{#n1ql.bucket} <%= relationship.relationshipFieldNamePlural %> ON KEYS #{#n1ql.bucket}.<%= relationship.relationshipFieldNamePlural %>"<%
" LEFT NEST #{#n1ql.bucket} `<%= relationship.relationshipFieldNamePlural %>` ON KEYS b.`<%= relationship.relationshipFieldNamePlural %>`"<%
}
if (index < relationships.length - 1) { %>
+ <%
}
}); %>;


default Page<<%= persistClass %>> findAllWithEagerRelationships(Pageable pageable) {
default Page<<%= persistClass %>> findAll(Pageable pageable) {
return new PageImpl<>(
findAllWithEagerRelationshipsWithPagination(new org.springframework.data.couchbase.core.query.Query().with(pageable).export()),
findAllWithPagination(pageableStatement(pageable, "b")),
pageable,
count()
);
}

@Query(SELECT + JOIN + " WHERE #{#n1ql.bucket}.#{#n1ql.filter} #{[0]}")
@Query(SELECT + JOIN + " WHERE b.#{#n1ql.filter} #{[0]}")
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
List<<%= persistClass %>> findAllWithEagerRelationshipsWithPagination(String pageableStatement);
List<<%= persistClass %>> findAllWithPagination(String pageableStatement);

@Query(SELECT + JOIN + " WHERE #{#n1ql.bucket}.#{#n1ql.filter}")
@Query(SELECT + JOIN + " WHERE b.#{#n1ql.filter}")
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
List<<%= persistClass %>> findAllWithEagerRelationships();
List<<%= persistClass %>> findAll();

@Query(SELECT + " USE KEYS $1" + JOIN)
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
Optional<<%= persistClass %>> findOneWithEagerRelationships(String id);<%
}
} _%>
Optional<<%= persistClass %>> findById(String id);<%
} _%>
}
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ _%>
if (field.fieldTypeZonedDateTime) { %>)<% } else
if (!field.fieldTypeString) { %>.toString()<% } %>))<%= !reactive ? ')' : '' %><%_ } _%>;
}
<% if (fieldsContainOwnerManyToMany && !databaseTypeNeo4j) { %>
<% if (fieldsContainOwnerManyToMany && !databaseTypeNeo4j && !databaseTypeCouchbase) { %>
@SuppressWarnings({"unchecked"})
void getAll<%= entityClassPlural %>WithEagerRelationshipsIsEnabled() <% if (!reactive) { %>throws Exception <% } %>{
<%_ if (!serviceNo) { _%>
Expand Down
4 changes: 2 additions & 2 deletions generators/entity/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -791,8 +791,8 @@ class EntityGenerator extends BaseBlueprintGenerator {
(this.context.paginate !== PAGINATION &&
relationship.relationshipType === 'many-to-many' &&
relationship.ownerSide === true)) &&
// Neo4j eagerly loads relations by default
this.context.databaseType !== NEO4J;
// Neo4j & Couchbase eagerly loads relations by default
![NEO4J, COUCHBASE].includes(this.context.databaseType);
});
this.context.relationshipsContainEagerLoad = this.context.relationships.some(relationship => relationship.relationshipEagerLoad);
this.context.eagerRelations = this.context.relationships.filter(rel => rel.relationshipEagerLoad);
Expand Down
2 changes: 1 addition & 1 deletion generators/server/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ const serverFiles = {
{
file: 'package/repository/N1qlCouchbaseRepository.java',
renameTo: generator => `${generator.javaDir}repository/N1qlCouchbaseRepository.java`,
}
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
<%_ } _%>
import org.springframework.context.annotation.Profile;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.GenericConversionService;
<%_ if (searchEngineElasticsearch) { _%>
import org.springframework.data.elasticsearch.repository.config.Enable<% if (reactive) { %>Reactive<% } %>ElasticsearchRepositories;
<%_ } _%>
Expand All @@ -55,6 +58,8 @@ import org.springframework.data.convert.WritingConverter;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.config.BeanNames;
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
<%_ if (!reactive) { _%>
import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
Expand All @@ -67,12 +72,8 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.*;
<%_ if (reactive) { _%>
import java.util.Set;
import java.lang.reflect.Field;
import org.springframework.data.repository.util.QueryExecutionConverters;
import reactor.core.publisher.Flux;
Expand Down Expand Up @@ -167,6 +168,13 @@ public class DatabaseConfiguration extends AbstractCouchbaseConfiguration {
return new CouchbaseCustomConversions(converters);
}

@Override
public MappingCouchbaseConverter mappingCouchbaseConverter(CouchbaseMappingContext couchbaseMappingContext, CouchbaseCustomConversions couchbaseCustomConversions) {
MappingCouchbaseConverter mappingCouchbaseConverter = super.mappingCouchbaseConverter(couchbaseMappingContext, couchbaseCustomConversions);
((GenericConversionService) mappingCouchbaseConverter.getConversionService()).addConverter(StringToObjectConverter.INSTANCE);
return mappingCouchbaseConverter;
}

@Bean
public Couchmove couchmove(Cluster cluster) {
log.debug("Configuring Couchmove");
Expand Down Expand Up @@ -291,4 +299,17 @@ public class DatabaseConfiguration extends AbstractCouchbaseConfiguration {

}

public enum StringToObjectConverter implements GenericConverter {
INSTANCE;

@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Object.class));
}

@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,35 @@ import <%= packageName %>.repository.search.SearchCouchbaseRepository;
<%_ } _%>

import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.couchbase.core.query.Query;

import static java.lang.String.format;

/**
* Couchbase specific {@link org.springframework.data.repository.Repository} interface uses N1QL for all requests.
*/
@NoRepositoryBean
public interface N1qlCouchbaseRepository<T, ID> extends CouchbaseRepository<T, ID><% if (searchEngineCouchbase) { %>, SearchCouchbaseRepository<T, ID><% } %> {

static String pageableStatement(Pageable pageable, String prefix) {
Sort sort = Sort.by(
pageable.getSort().stream()
.map(order -> {
String property = order.getProperty();
if ("id".equals(property)) {
return order.withProperty(format("meta(%s).id", prefix));
}
return order.withProperty(format("%s.%s", prefix, property));
})
.collect(Collectors.toList()));
return new Query()
.limit(pageable.getPageSize())
.skip(pageable.getOffset())
.with(sort)
.export();
}

@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
List<T> findAll();

Expand Down

0 comments on commit 06a39c8

Please sign in to comment.