Skip to content

[2] Entity MapWrapper

Jan Sigrist edited this page Apr 10, 2024 · 4 revisions
  1. Add it in your root build.gradle at the end of repositories:
 buildscript {
    repositories {
        maven { url 'https://jitpack.io' }
    }
  }
  ...
  allprojects {
    repositories {
	maven { url 'https://jitpack.io' }
    }
  }
  1. Add gradle dependency
  implementation 'com.github.Kaufland.andcouchbaseentity:couchbase-entity-api:3.1.0'
  kapt 'com.github.Kaufland.andcouchbaseentity:couchbase-entity:3.1.0'
  1. Optionally, if you use Couchbase 2.x.x (provides already implemented connector)
  implementation 'com.github.Kaufland.andcouchbaseentity:couchbase-entity-connector:3.1.0@aar'

NOTE: For custom connectors see

Connector

Example

  1. Configure library
  • Add the following code in your Application.kt
  @Override
  public void onCreate() {
      super.onCreate();
           PersistenceConfig.configure(object : Couchbase2Connector() {
            override fun getDatabase(name: String): Database {
                if (DB == name) {
                    //for better performance when using queries may consider create some Indexes
                    return database!!
                }
                throw RuntimeException("wrong db name defined!!")
            }
        })
  }

NOTE: For other databases implement your own connector

  • Annotate classes to generate entities (all generated classes have the suffix Entity or Wrapper (used for child entities or map wrapping)
@Entity(database = Application.DB)
@Fields(
        Field(name = "type", type = String::class, defaultValue = "product", readonly = true),
        Field(name = "name", type = String::class),
        Field(name = "comments", type = UserComment::class, list = true),
        Field(name = "image", type = Blob::class),
        Field(name = "identifiers", type = String::class, list = true)
)
@Queries(
        Query(fields = ["type"])
)
open class Product{

    companion object{

        @GenerateAccessor
        fun someComplexQuery(param1 : String){
            //do some heavy logic here
        }
    }
}
  • Use generated classes and be happy :-)

There are two different ways to interact with the entity / mapWrapper

  • Example 1: use fluent API to modify multiple properties.
ProductEntity.create().builder()
                       .setName("Wodka")
                         .setComments(listOf(UserCommentWrapper
                           .create().builder()
                             .setComment("feeling like touch the sky")
                               .exit())).setImage(Blob("image/jpeg", resources.openRawResource(R.raw.ic_kaufland_placeholder)))
                                  .exit().save()
  • Example 2: get / set data via kotlin property syntax
var data = ProductEntity.create()
    data.name = "Tomatoes"
    data.comments = listOf(UserCommentWrapper.create().builder().setComment("don't like there color").exit(),
               UserCommentWrapper.create().builder().setComment("worst experience ever!!").exit())
    data.image = Blob("image/jpeg", resources.openRawResource(R.raw.ic_kaufland_placeholder))
    data.save()

NOTE : To modify child entities it's neccessary to invoke the setter before saving the parent entity

 final List<UserCommentWrapper> data = getParentEntity().getComments();
 data.remove(position);
 try {
     ProductEntity entity = getParentEntity();
     entity.setComments(mComments);
     entity.save();
     } catch (PersistenceException e) {
     Log.e(TAG, "failed to save Entity", e);
     }

Queries

By using the @Query annotation the Framework automatically generates static methods to execute this queries and returns the resulted entities

@Fields(
       Field(name = "type", type = String::class, defaultValue = "product", readonly = true),
       Field(name = "name", type = String::class)
)
@Queries(
       Query(fields = ["type"]),
       Query(fields = ["type", "name"])
)

Above Code generates Methods which can be used like

val resultByType = MyEntity.findByType()
val resultByTypeAndName = MyEntity.findbyTypeAndName("beer")

The Query generation may not fit all needs for this cases you can define a query by yourself and use the @GenerateAccessor annotation to make it available in the GeneratedEntity

@Entity(database = "mydb_db")
//Fields and Queries add them here
open class Product{

   companion object{

       @GenerateAccessor
       fun someComplexQuery(param1 : String){
           //do some heavy logic here
       }
   }
}
ProductEntity.someComplexQuery("Foo")

Schemas

By using the @SchemaClass annotation the Framework automatically generates a class that contains all the fields as properties. The fields are mapped to one of four types, determined by the parameters provided for each field, along with a generic derived from the "type" parameter.

The type is determined based on the following criteria:

  1. CMList: When the "list" parameter is marked as true.
  2. CMObject: If the "type" parameter is assigned to another class that also has the @SchemaClass annotation.
  3. CMObjectList: When both the "list" parameter is true and the "type" parameter is set to a class that is annotated with @SchemaClass.
  4. CMField: When none of the above apply.

If a defaultValue is given, it also creates a default property for this field.

@SchemaClass
@Fields(
        Field(name = "type", type = String::class, defaultValue = "product", readonly = true),
        Field(name = "name", type = String::class)
)
class Product

The Code above generates a class like this:

open class ProductSchema(
    path: String = ""
) : Schema {
    val DEFAULT_TYPE: String = "product"

    val type: CMField<String> = CMField("type", path)

    val name: CMField<String> = CMField("name", path)
}
Clone this wiki locally