DATACOUCH-154 - Guess design doc as uncapitalized class name.

In the SimpleCouchbaseRepository the guessed design document was lowercase of the entity class, whereas in ViewBasedCouchbaseQuery it is uncapitalized (only first letter is lowercase).

This has been made consistent, using the uncapitalize method. The doc now reflects that and explicitly have examples with camel case classes (UserInfo instead of User).
This commit is contained in:
Simon Baslé
2015-07-30 17:44:53 +02:00
parent f543e2b037
commit 2035a88dba
3 changed files with 44 additions and 43 deletions

View File

@@ -75,27 +75,27 @@ To simplify the creation of data repositories Spring Data Couchbase provides a g
will automatically create a repository proxy for you that adds implementations of finder methods you specify on an
interface.
To create a repository on top of a `User` entity, all you need to write is:
To create a repository on top of a `UserInfo` entity, all you need to write is:
```java
public interface UserRepository extends CrudRepository<User, String> {
public interface UserRepository extends CrudRepository<UserInfo, String> {
/**
* Return all users emitted by the view user/adults
* Return all users emitted by the view userInfo/adults
*/
@View
List<User> findAdults();
List<UserInfo> findAdults();
/**
* Find all users matching the last name.
*/
@View(viewName="lastNames")
List<User> findByLastname(String lastName);
List<UserInfo> findByLastname(String lastName);
/**
* Find all the users whose first name contains the word.
*/
List<User> findByFirstnameContains(String word);
List<UserInfo> findByFirstnameContains(String word);
}
```
@@ -104,7 +104,7 @@ Once you get a reference to that repository bean, you'll find a lot of methods t
entity. In addition to the ones provided through the `CrudRepository`, you can add your own methods as well.
In general, every CRUD method that does not depend on a single key (like `findById`) needs a backing View, `all` on the
server side (the design document is by default expected to be the uncapitalized name of the entity, like `user`).
server side (the design document is by default expected to be the uncapitalized name of the entity, like `userInfo`).
## Custom Repository Methods and Views
Finder methods you define, if annotated with `@View`, also are backed by views. Either you want to return all items from
@@ -112,7 +112,7 @@ these views and you can let the method name reflect the view name (like in `find
`adults` view), or provide simple criteria (you explicitly specify the `viewName` and let the method name determine your
criteria, like in `findByLastname`).
In the example above, it assumes you have a view named `findByLastname` in the `user` design document. You
In the example above, it assumes you have a view named `findByLastname` in the `userInfo` design document. You
can customize the view and design document name through the `@View` annotation. Also make sure you publish them into
production before accessing it.
@@ -120,7 +120,7 @@ This is an example view for the `findByLastname` method:
```javascript
function (doc, meta) {
if(doc._class == "com.example.entity.User" && doc.lastname) {
if(doc._class == "com.example.entity.UserInfo" && doc.lastname) {
emit(doc.lastname, null);
}
}
@@ -134,7 +134,7 @@ function):
```javascript
function (doc, meta) {
if(doc._class == "com.example.entity.User") {
if(doc._class == "com.example.entity.UserInfo") {
emit(null, null);
}
}
@@ -148,13 +148,13 @@ This is the default repository query mechanism, so the associated `@Query` annot
like:
```java
public interface UserRepository extends CrudRepository<User, String> {
public interface UserRepository extends CrudRepository<UserInfo, String> {
/**
* Advanced querying with N1QL derivation
*/
@View
List<User> findByLastnameEqualsIgnoreCaseAndFirstnameStartsWithAndIsAdultTrue(String lastName, String fnamePrefix);
List<UserInfo> findByLastnameEqualsIgnoreCaseAndFirstnameStartsWithAndIsAdultTrue(String lastName, String fnamePrefix);
}
```
@@ -169,7 +169,7 @@ placeholder to make sure all necessary fields and metadata are selected by N1QL:
```java
@Query("$SELECT_ENTITY$ WHERE firstname LIKE "%ck%"
List<User> findPatrickAndJackAmongOthers();
List<UserInfo> findPatrickAndJackAmongOthers();
```
## Using The Repository
@@ -232,12 +232,12 @@ public class MyService {
public void doWork() {
userRepository.deleteAll();
User user = new User();
user.setLastname("Jackson");
UserInfo userInfo = new UserInfo();
UserInfo.setLastname("Jackson");
user = userRepository.save(user);
UserInfo = userRepository.save(userInfo);
List<User> allJacksons = userRepository.findByLastname("Jackson");
List<UserInfo> allJacksons = userRepository.findByLastname("Jackson");
}
}
```

View File

@@ -33,15 +33,15 @@ XML-based configuration is also available:
[[couchbase.repository.usage]]
== Usage
In the simplest case, your repository will extend the `CrudRepository<T, String>`, where T is the entity that you want to expose. Let's look at a repository for a user:
In the simplest case, your repository will extend the `CrudRepository<T, String>`, where T is the entity that you want to expose. Let's look at a repository for a UserInfo:
.A User repository
.A UserInfo repository
====
[source,java]
----
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, String> {
public interface UserRepository extends CrudRepository<UserInfo, String> {
}
----
====
@@ -56,22 +56,22 @@ Now, let's imagine we `@Autowire` the `UserRepository` to a class that makes use
| Method
| Description
| User save(User entity)
| UserInfo save(UserInfo entity)
| Save the given entity.
| Iterable<User> save(Iterable<User> entity)
| Iterable<UserInfo> save(Iterable<UserInfo> entity)
| Save the list of entities.
| User findOne(String id)
| UserInfo findOne(String id)
| Find a entity by its unique id.
| boolean exists(String id)
| Check if a given entity exists by its unique id.
| Iterable<User> findAll() (*)
| Iterable<UserInfo> findAll() (*)
| Find all entities by this type in the bucket.
| Iterable<User> findAll(Iterable<String> ids)
| Iterable<UserInfo> findAll(Iterable<String> ids)
| Find all entities by this type and the given list of ids.
| long count() (*)
@@ -80,10 +80,10 @@ Now, let's imagine we `@Autowire` the `UserRepository` to a class that makes use
| void delete(String id)
| Delete the entity by its id.
| void delete(User entity)
| void delete(UserInfo entity)
| Delete the entity.
| void delete(Iterable<User> entities)
| void delete(Iterable<UserInfo> entities)
| Delete all given entities.
| void deleteAll() (*)
@@ -106,16 +106,16 @@ WARNING: If it is detected at configuration time that the cluster doesn't suppor
Here is an example:
.An extended User repository with N1QL queries
.An extended UserInfo repository with N1QL queries
====
[source,java]
----
public interface UserRepository extends CrudRepository<User, String> {
public interface UserRepository extends CrudRepository<UserInfo, String> {
@Query("$SELECT_ENTITY$ WHERE role = 'admin'")
List<User> findAllAdmins();
List<UserInfo> findAllAdmins();
List<User> findByFirstname(String fname);
List<UserInfo> findByFirstname(String fname);
}
----
====
@@ -174,7 +174,7 @@ IMPORTANT: This is only true for the methods directly defined by the `CrudReposi
To cover the basic CRUD methods from the `CrudRepository`, one view needs to be implemented in Couchbase Server. It basically returns all documents for the specific entity and also adds the optional reduce function `_count`.
Since every view has a design document and view name, by convention we default to `all` as the view name and the lower-cased entity name as the design document name. So if your entity is named `User`, then the code expects the `all` view in the `user` design document. It needs to look like this:
Since every view has a design document and view name, by convention we default to `all` as the view name and the uncapitalized (lowercase first letter) entity name as the design document name. So if your entity is named `UserInfo`, then the code expects the `all` view in the `userInfo` design document. It needs to look like this:
.The all view map function
====
@@ -182,7 +182,7 @@ Since every view has a design document and view name, by convention we default t
----
// do not forget the _count reduce function!
function (doc, meta) {
if (doc._class == "namespace.to.entity.User") {
if (doc._class == "namespace.to.entity.UserInfo") {
emit(null, null);
}
}
@@ -204,29 +204,29 @@ In `2.0`, since N1QL has been introduced as a more powerful concept, view-backed
- View based query derivation is limited to a few keywords and only works on simple keys (not compound keys like `[ age, fname ]`).
- View based query derivation still needs you to include *one* valid property before keywords in the method name.
.An extended User repository with View queries
.An extended UserInfo repository with View queries
====
[source,java]
----
public interface UserRepository extends CrudRepository<User, String> {
public interface UserRepository extends CrudRepository<UserInfo, String> {
@View
List<User> findAllAdmins();
List<UserInfo> findAllAdmins();
@View(viewName="firstNames")
List<User> findByFirstnameStartingWith(String fnamePrefix);
List<UserInfo> findByFirstnameStartingWith(String fnamePrefix);
}
----
====
Implementing your custom repository finder methods also needs backing views. The `findAllAdmins` guesses to use the `allAdmins` view in the `user` design document, by convention. Imagine we have a field on our entity which looks like `boolean isAdmin`. We can write a view like this to expose them (we don't need a reduce function for this one, unless you plan to call one by prefixing your method with `count` instead of `find`!):
Implementing your custom repository finder methods also needs backing views. The `findAllAdmins` guesses to use the `allAdmins` view in the `userInfo` design document, by convention. Imagine we have a field on our entity which looks like `boolean isAdmin`. We can write a view like this to expose them (we don't need a reduce function for this one, unless you plan to call one by prefixing your method with `count` instead of `find`!):
.The allAdmins map function
====
[source,javascript]
----
function (doc, meta) {
if (doc._class == "namespace.to.entity.User" && doc.isAdmin) {
if (doc._class == "namespace.to.entity.UserInfo" && doc.isAdmin) {
emit(null, null);
}
}
@@ -240,14 +240,14 @@ By now, we've never actually customized our view at query time. This is where th
[source,javascript]
----
function (doc, meta) {
if (doc._class == "namespace.to.entity.User") {
if (doc._class == "namespace.to.entity.UserInfo") {
emit(doc.firstname, null);
}
}
----
====
This view not only emits the document id, but also the firstname of every user as the key. We can now run a `ViewQuery` which returns us all users with a firstname of "Michael" or "Michele".
This view not only emits the document id, but also the firstname of every UserInfo as the key. We can now run a `ViewQuery` which returns us all users with a firstname of "Michael" or "Michele".
.Query a repository method with custom params.
====
@@ -257,7 +257,7 @@ This view not only emits the document id, but also the firstname of every user a
UserRepository repo = ctx.getBean(UserRepository.class);
// Find all users with first name starting with "Mich"
List<User> users = repo.findByFirstnameStartingWith("Mich");
List<UserInfo> users = repo.findByFirstnameStartingWith("Mich");
----
====

View File

@@ -30,6 +30,7 @@ import org.springframework.data.couchbase.core.view.View;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Repository base implementation for Couchbase.
@@ -205,7 +206,7 @@ public class SimpleCouchbaseRepository<T, ID extends Serializable> implements Co
* @return ResolvedView containing the designDocument and viewName.
*/
private ResolvedView determineView() {
String designDocument = entityInformation.getJavaType().getSimpleName().toLowerCase();
String designDocument = StringUtils.uncapitalize(entityInformation.getJavaType().getSimpleName());
String viewName = "all";
final View view = viewMetadataProvider.getView();