DATACOUCH-146 - Reactive repositories support

- Adds experimental support for reactor types in reactive CRUD and Sorting
  repositories using RxJava1Template
- Refactor configuration and query classes to be reusable by reactive repositories

Original pull request: #130.
This commit is contained in:
Subhashni Balakrishnan
2017-01-11 14:55:13 -08:00
parent 56b3842ac1
commit d62f4bbe8c
54 changed files with 4721 additions and 670 deletions

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.core;
import org.springframework.data.annotation.Id;
import com.couchbase.client.java.repository.annotation.Field;
/**
* Test class for persisting and loading from {@link ReactiveCouchbaseTemplate}.
*
* @author Subhashni Balakrishnan
*/
public class ReactiveBeer {
@Id
private final String id;
private String name;
@Field("is_active")
private boolean active = true;
@Field("desc")
private String description;
public ReactiveBeer(String id, String name, Boolean active, String description) {
this.id = id;
this.name = name;
this.active = active;
this.description = description;
}
@Override
public String toString() {
return "Beer [id=" + id + ", name=" + name + ", active=" + active + ", description=" + description + "]";
}
public ReactiveBeer setName(String name) {
this.name = name;
return this;
}
public String getName() {
return name;
}
public ReactiveBeer setActive(boolean active) {
this.active = active;
return this;
}
public boolean getActive() {
return active;
}
public ReactiveBeer setDescription(String description) {
this.description = description;
return this;
}
public String getDescription() {
return description;
}
public String getId() {
return id;
}
}

View File

@@ -76,7 +76,7 @@ public class PartTreeN1qBasedQueryTest {
PartTreeN1qlBasedQuery query = new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations);
Statement statement = query.getCount(accessor, new Object[] { "value", pr });
assertEquals("SELECT COUNT(*) AS count FROM `default` WHERE name = \"value\" "
assertEquals("SELECT COUNT(*) AS count FROM `default` WHERE (name = \"value\") "
+ "AND `_class` = \"org.springframework.data.couchbase.core.Beer\"", statement.toString());
}
@@ -119,7 +119,7 @@ public class PartTreeN1qBasedQueryTest {
PartTreeN1qlBasedQuery query = new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations);
Statement statement = query.getCount(accessor, new Object[] { "value", pr });
assertEquals("SELECT COUNT(*) AS count FROM `default` WHERE name = \"value\" "
assertEquals("SELECT COUNT(*) AS count FROM `default` WHERE (name = \"value\") "
+ "AND `_class` = \"org.springframework.data.couchbase.core.Beer\"", statement.toString());
}

View File

@@ -1,58 +1,17 @@
package org.springframework.data.couchbase.repository.query;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.data.couchbase.repository.query.StringN1qlBasedQuery.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.springframework.data.couchbase.repository.query.StringBasedN1qlQueryParser.*;
public class StringN1QlBasedQueryTest {
private static final SpelExpressionParser SPEL_PARSER = new SpelExpressionParser();
private static final EvaluationContext SPEL_EVALUATION_CONTEXT = new StandardEvaluationContext();
private StringN1qlBasedQuery mockStringUnderscoreClass;
private StringN1qlBasedQuery mockStringAtClass;
@Before
public void initMock() {
N1qlSpelValues contextStringUnderscoreClass = StringN1qlBasedQuery.createN1qlSpelValues("B", "_class", String.class, false);
N1qlSpelValues contextCountStringUnderscoreClass = StringN1qlBasedQuery.createN1qlSpelValues("B", "_class", String.class, true);
N1qlSpelValues contextStringAtClass = StringN1qlBasedQuery.createN1qlSpelValues("B", "@class", String.class, false);
N1qlSpelValues contextCountStringAtClass = StringN1qlBasedQuery.createN1qlSpelValues("B", "@class", String.class, true);
mockStringUnderscoreClass = mock(StringN1qlBasedQuery.class);
when(mockStringUnderscoreClass.parseSpel(anyString(), anyBoolean(), any(Object[].class)))
.thenAnswer(mockSpelEvaluation(contextStringUnderscoreClass, contextCountStringUnderscoreClass));
mockStringAtClass = mock(StringN1qlBasedQuery.class);
when(mockStringAtClass.parseSpel(anyString(),anyBoolean(), any(Object[].class)))
.thenAnswer(mockSpelEvaluation(contextStringAtClass, contextCountStringAtClass));
}
private static Answer<?> mockSpelEvaluation(final N1qlSpelValues spelValues, final N1qlSpelValues countSpelValues) {
return new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
String statement = (String) invocation.getArguments()[0];
boolean isCount = (Boolean) invocation.getArguments()[1];
if (isCount)
return doParse(statement, SPEL_PARSER, SPEL_EVALUATION_CONTEXT, countSpelValues);
else
return doParse(statement, SPEL_PARSER, SPEL_EVALUATION_CONTEXT, spelValues);
}
};
}
private static String spel(String expression) {
return "#{" + expression + "}";
}
@@ -60,7 +19,8 @@ public class StringN1QlBasedQueryTest {
@Test
public void testReplaceAllFullSelectPlaceholder() throws Exception {
String statement = spel(SPEL_SELECT_FROM_CLAUSE) + " where " + spel(SPEL_SELECT_FROM_CLAUSE);
String parsed = mockStringUnderscoreClass.parseSpel(statement, false, new Object[0]);
String parsed = new StringBasedN1qlQueryParser(statement, null, "B", "_class", String.class)
.doParse(SPEL_PARSER, SPEL_EVALUATION_CONTEXT, false);
assertEquals("SELECT META(`B`).id AS _ID, META(`B`).cas AS _CAS, `B`.* FROM `B` where "
+ "SELECT META(`B`).id AS _ID, META(`B`).cas AS _CAS, `B`.* FROM `B`", parsed);
@@ -69,7 +29,8 @@ public class StringN1QlBasedQueryTest {
@Test
public void testReplaceAllBucketPlaceholder() throws Exception {
String statement = "SELECT * FROM " + spel(SPEL_BUCKET) + " WHERE " + spel(SPEL_BUCKET) + ".test = 1";
String parsed = mockStringUnderscoreClass.parseSpel(statement, false, new Object[0]);
String parsed = new StringBasedN1qlQueryParser(statement, null, "B", "_class", String.class)
.doParse(SPEL_PARSER, SPEL_EVALUATION_CONTEXT, false);
assertEquals("SELECT * FROM `B` WHERE `B`.test = 1", parsed);
}
@@ -77,7 +38,8 @@ public class StringN1QlBasedQueryTest {
@Test
public void testReplaceAllEntityPlaceholder() throws Exception {
String statement = "SELECT " + spel(SPEL_ENTITY) + " FROM a where a.test = 1 and " + spel(SPEL_ENTITY);
String parsed = mockStringUnderscoreClass.parseSpel(statement, false, new Object[0]);
String parsed = new StringBasedN1qlQueryParser(statement, null, "B", "_class", String.class)
.doParse(SPEL_PARSER, SPEL_EVALUATION_CONTEXT, false);
assertEquals("SELECT META(`B`).id AS _ID, META(`B`).cas AS _CAS FROM a where a.test = 1 and "
+ "META(`B`).id AS _ID, META(`B`).cas AS _CAS", parsed);
@@ -86,7 +48,8 @@ public class StringN1QlBasedQueryTest {
@Test
public void testReplaceTypePlaceholder() throws Exception {
String statement = "SELECT " + spel(SPEL_ENTITY) + " FROM a WHERE a.test = 1 AND " + spel(SPEL_FILTER);
String parsed = mockStringAtClass.parseSpel(statement, false, new Object[0]);
String parsed = new StringBasedN1qlQueryParser(statement, null, "B", "@class", String.class)
.doParse(SPEL_PARSER, SPEL_EVALUATION_CONTEXT, false);
assertEquals("SELECT META(`B`).id AS _ID, META(`B`).cas AS _CAS FROM a WHERE a.test = 1 AND `@class` = "
+ "\"java.lang.String\"", parsed);
@@ -95,7 +58,8 @@ public class StringN1QlBasedQueryTest {
@Test
public void testReplaceSelectFromPlaceholderWithCountIfCountTrue() {
String statement = spel(SPEL_SELECT_FROM_CLAUSE) + " WHERE true";
String parsed = mockStringUnderscoreClass.parseSpel(statement, true, new Object[0]);
String parsed = new StringBasedN1qlQueryParser(statement, null, "B", "_class", String.class)
.doParse(SPEL_PARSER, SPEL_EVALUATION_CONTEXT, true);
assertEquals("SELECT COUNT(*) AS " + CountFragment.COUNT_ALIAS + " FROM `B` WHERE true", parsed);
}