Skip to content
This repository has been archived by the owner on Aug 17, 2023. It is now read-only.
/ etg-model-generator Public archive

Annotation processor for generating reactive models

License

Notifications You must be signed in to change notification settings

dimsuz/etg-model-generator

Repository files navigation

Reactive Model Generator

Given

@GenerateReducingImplementation(
  baseClass = SerialReactiveModel::class, 
  lceState = LceState::class
)
interface SampleModel {
  fun fetchMovieList(userId: String)
  fun fetchMovieListState(): Observable<LceState<List<Movie>>>

  fun saveMovieRating(userId: String, movieId: String)
  fun saveMovieRatingState(): Observable<LceState<Unit>>

  fun movieGenreList(): Observable<List<Genre>>
}

this processor will generate this model implementation. It will be based on an interface SampleModelOperations which is also generated for you to implement:

// Generated by processor
interface SampleModelOperations {
  fun createFetchMovieListOperation(userId: String, state: SampleModelImpl.State): Single<LceState<List<Movie>>>

  fun createSaveMovieRating(userId: String, movieId: String, state: SampleModelImpl.State): Completable

  fun movieGenreList(): Observable<List<Genre>>
}

Reactive properties are recognized based on the returned LCE state type. To tell the processor about this type you'll need to provide it with a factory which knows how to create instances of LCE state:

data class LceState<C>(
  val isLoading: Boolean,
  val content: C?,
  val error: Throwable?
)

class LceStateFactoryImpl : LceStateFactory<LceState<*>> {
  override fun createLceContent(content: Any): LceState<*> {
    return LceState(isLoading = false, content = content, error = null)
  }

  override fun createLceError(error: Any): LceState<*> {
    return LceState(isLoading = false, content = null, error = error as Throwable)
  }

  override fun createLceLoading(): LceState<*> {
    return LceState(isLoading = true, content = content, error = null)
  }

}

After processor knows about LCE state type, it will search for reactive getters — functions with return type Observable<LceState<*>>, and then attempt to find matching "request"-functions by removing State suffix from getter name. For example: getter saveMovieRatingState should have request named saveMovieRating to be found by processor.

All methods of the model interface which are not recognized as reactive getters/requests will be copied to generated operations-interface without any changes (see movieGenreList() in the above example)

To create an instance of the model which uses the generated implementation call:

val operationsImpl = object : SampleModelOperations {
   // Tyour implementation
}
val lceStateFactory = LceStateFactoryImpl()
val model = ModelGenerator.createModel(operationsImpl, lceStateFactory)
model.fetchMovieListState().subscribe({ println("Got list $it") })
model.fetchMovieList("my-user-id")

Download

Add a Gradle dependency:

apply plugin: 'kotlin-kapt'

implementation 'com.github.dimsuz:etg-model-generator-runtime:1.0.0-RC5'
kapt 'com.github.dimsuz:etg-model-generator-processor:1.0.0-RC5'

License

   Copyright 2019 Dmitry Suzdalev

   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.

About

Annotation processor for generating reactive models

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages