All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dailystudio.devbricksx.ksp.processors.step.data.RoomCompanionDaoStep.kt Maven / Gradle / Ivy

package com.dailystudio.devbricksx.ksp.processors.step.data

import androidx.room.*
import com.dailystudio.devbricksx.annotations.data.Page
import com.dailystudio.devbricksx.annotations.data.RoomCompanion
import com.dailystudio.devbricksx.ksp.helper.*
import com.dailystudio.devbricksx.ksp.processors.BaseSymbolProcessor
import com.dailystudio.devbricksx.ksp.processors.GeneratedClassResult
import com.dailystudio.devbricksx.ksp.processors.GeneratedResult
import com.dailystudio.devbricksx.ksp.processors.step.SingleSymbolProcessStep
import com.dailystudio.devbricksx.ksp.utils.*
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ksp.toClassName

class RoomCompanionDaoStep (processor: BaseSymbolProcessor)
    : SingleSymbolProcessStep(RoomCompanion::class, processor) {

    override fun processSymbol(resolver: Resolver, symbol: KSClassDeclaration): List {
        val typeName = symbol.typeName()
        val packageName = symbol.packageName()

        val typeNameToGenerate = GeneratedNames.getRoomCompanionDaoName(typeName)

        val primaryKeys = RoomCompanionUtils.findPrimaryKeys(symbol)

        val roomCompanion = symbol.getAnnotation(RoomCompanion::class) ?: return emptyResult
        val roomCompanionKS =
            symbol.getKSAnnotation(RoomCompanion::class, resolver) ?: return emptyResult

        val typeOfDaoExtension = roomCompanionKS
            .findArgument("extension")
            .toClassName()
        warn("type of daoExtension: $typeOfDaoExtension")

        var pageSize: Int = roomCompanion.pageSize
        if (pageSize <= 0) {
            error("page size must be positive. set to default")

            pageSize = Page.DEFAULT_PAGE_SIZE
        }

        val typeOfObject = TypeNameUtils.typeOfObject(packageName, typeName)
        val typeOfCompanion = TypeNameUtils.typeOfCompanion(packageName, typeName)
        val typeOfListOfObjects = TypeNameUtils.typeOfListOf(typeOfObject)
        val typeOfListOfCompanions = TypeNameUtils.typeOfListOf(typeOfCompanion)
        val typeOfDataSourceFactoryOfCompanion =
            TypeNameUtils.typeOfDataSourceFactoryOf(typeOfCompanion)
        val typeOfPagingSourceOfObject =
            TypeNameUtils.typeOfPagingSourceOf(typeOfObject)
        val typeOfLiveDataOfObject = TypeNameUtils.typeOfLiveDataOf(typeOfObject)
        val typeOfLiveDataOfNullableObject = TypeNameUtils.typeOfLiveDataOf(typeOfObject.copy(nullable = true))
        val typeOfFlowOfNullableObject = TypeNameUtils.typeOfFlowOf(typeOfObject.copy(nullable = true))
        val typeOfLiveDataOfCompanion = TypeNameUtils.typeOfLiveDataOf(typeOfCompanion)
        val typeOfLiveDataOfNullableCompanion = TypeNameUtils.typeOfLiveDataOf(typeOfCompanion.copy(nullable = true))
        val typeOfFlowOfNullableCompanion = TypeNameUtils.typeOfFlowOf(typeOfCompanion.copy(nullable = true))
        val typeOfLiveDataOfListOfCompanions =
            TypeNameUtils.typeOfLiveDataOf(typeOfListOfCompanions)
        val typeOfLiveDataOfListOfObjects =
            TypeNameUtils.typeOfLiveDataOf(typeOfListOfObjects)
        val typeOfFlowOfListOfCompanions =
            TypeNameUtils.typeOfFlowOf(typeOfListOfCompanions)
        val typeOfFlowOfListOfObjects =
            TypeNameUtils.typeOfFlowOf(typeOfListOfObjects)
        val typeOfLiveDataOfPagedListOfObjects =
            TypeNameUtils.typeOfLiveDataOf(TypeNameUtils.typeOfPagedListOf(typeOfObject))
        val typeOfListOfLong = TypeNameUtils.typeOfListOf(LONG)
        val nameOfObject = typeName.toVariableOrParamName()
        val nameOfObjects = typeName.toVariableOrParamNameOfCollection()

        val tableName = GeneratedNames.getTableName(typeName)
        val whereClauseForGetOneMethods  =
            RoomCompanionUtils.primaryKeysToSQLiteWhereClause(primaryKeys)
        val getOneMethodCallParameters: String =
            RoomCompanionUtils.primaryKeysToFuncCallParameters(primaryKeys)

        val classBuilder = TypeSpec.classBuilder(typeNameToGenerate)
            .addAnnotation(Dao::class)
            .addModifiers(KModifier.ABSTRACT)

        if (typeOfDaoExtension != UNIT) {
            val packageNameOfDaoExtension = typeOfDaoExtension.packageName
            val typeNameOfDaoExtension = typeOfDaoExtension.simpleName
            classBuilder.superclass(
                ClassName(packageNameOfDaoExtension,
                    GeneratedNames.getDaoExtensionCompanionName(typeNameOfDaoExtension))
            )
        }

        val methodGetOneBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ONE.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfCompanion.copy(nullable = true))
        RoomCompanionUtils.attachPrimaryKeysToMethodParameters(methodGetOneBuilder, primaryKeys)

        methodGetOneBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName` $whereClauseForGetOneMethods")
                .build()
        )

        classBuilder.addFunction(methodGetOneBuilder.build())

        val methodGetOneLiveBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ONE_LIVE.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfLiveDataOfNullableCompanion)
        RoomCompanionUtils.attachPrimaryKeysToMethodParameters(methodGetOneLiveBuilder, primaryKeys)

        methodGetOneLiveBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName` $whereClauseForGetOneMethods")
                .build()
        )

        classBuilder.addFunction(methodGetOneLiveBuilder.build())

        val methodGetOneFlowBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ONE_FLOW.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfFlowOfNullableCompanion)
        RoomCompanionUtils.attachPrimaryKeysToMethodParameters(methodGetOneFlowBuilder, primaryKeys)

        methodGetOneFlowBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName` $whereClauseForGetOneMethods")
                .build()
        )

        classBuilder.addFunction(methodGetOneFlowBuilder.build())

        val methodGetAllBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ALL.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfListOfCompanions)

        methodGetAllBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName`")
                .build()
        )

        classBuilder.addFunction(methodGetAllBuilder.build())

        val methodGetAllLiveBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ALL_LIVE.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfLiveDataOfListOfCompanions)

        methodGetAllLiveBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName`")
                .build()
        )

        classBuilder.addFunction(methodGetAllLiveBuilder.build())

        val methodGetAllDataSourceFactoryBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ALL_DATA_SOURCE.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfDataSourceFactoryOfCompanion)

        methodGetAllDataSourceFactoryBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName`")
                .build()
        )

        classBuilder.addFunction(methodGetAllDataSourceFactoryBuilder.build())

        val methodGetAllFlowBuilder: FunSpec.Builder =
            FunSpec.builder(FunctionNames.GET_ALL_FLOW.nameOfFuncForCompanion())
                .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
                .returns(typeOfFlowOfListOfCompanions)

        methodGetAllFlowBuilder.addAnnotation(
            AnnotationSpec.builder(Query::class)
                .addMember("value = %S", "SELECT * FROM `$tableName`")
                .build()
        )

        classBuilder.addFunction(methodGetAllFlowBuilder.build())

        val methodInsertOneBuilder = FunSpec.builder(FunctionNames.INSERT.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
            .addParameter(nameOfObject, typeOfCompanion)
            .returns(LONG)

        methodInsertOneBuilder.addAnnotation(
            AnnotationSpec.builder(Insert::class)
                .addMember("onConflict = %L", OnConflictStrategy.IGNORE)
                .build()
        )

        classBuilder.addFunction(methodInsertOneBuilder.build())

        val methodInsertAllBuilder = FunSpec.builder(FunctionNames.INSERT.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
            .addParameter(nameOfObjects, typeOfListOfCompanions)
            .returns(typeOfListOfLong)

        methodInsertAllBuilder.addAnnotation(
            AnnotationSpec.builder(Insert::class)
                .addMember("onConflict = %L", OnConflictStrategy.IGNORE)
                .build()
        )

        classBuilder.addFunction(methodInsertAllBuilder.build())

        val methodUpdateOneBuilder = FunSpec.builder(FunctionNames.UPDATE.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
            .addParameter(nameOfObject, typeOfCompanion)
            .addAnnotation(Update::class)

        classBuilder.addFunction(methodUpdateOneBuilder.build())

        val methodUpdateAllBuilder = FunSpec.builder(FunctionNames.UPDATE.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
            .addParameter(nameOfObjects, typeOfListOfCompanions)
            .addAnnotation(Update::class)

        classBuilder.addFunction(methodUpdateAllBuilder.build())

        val methodInsertOrUpdateOneBuilder = FunSpec.builder(
            FunctionNames.INSERT_OR_UPDATE.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.OPEN)
            .addParameter(nameOfObject, typeOfCompanion)
            .addAnnotation(Transaction::class)
            .addStatement("val id = %N(%N)", FunctionNames.INSERT.nameOfFuncForCompanion(), nameOfObject)
            .beginControlFlow("if (id == -1L)")
            .addStatement("%N(%N)", FunctionNames.UPDATE.nameOfFuncForCompanion(), nameOfObject)
            .endControlFlow()

        classBuilder.addFunction(methodInsertOrUpdateOneBuilder.build())

        val methodInsertOrUpdateAllBuilder = FunSpec.builder(FunctionNames.INSERT_OR_UPDATE.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.OPEN)
            .addParameter(nameOfObjects, typeOfListOfCompanions)
            .addAnnotation(Transaction::class)
            .addStatement("val insertResults = %N(%N)",
                FunctionNames.INSERT.nameOfFuncForCompanion(), nameOfObjects)
            .addStatement("val toUpdate = mutableListOf<%T>()",
                typeOfCompanion)
            .beginControlFlow("for ((i, result) in insertResults.withIndex())")
            .beginControlFlow("if (result == -1L)")
            .addStatement("toUpdate.add(%N[i])", nameOfObjects)
            .endControlFlow()
            .endControlFlow()
            .addStatement("toUpdate.forEach { %N(it) }", FunctionNames.UPDATE.nameOfFuncForCompanion())

        classBuilder.addFunction(methodInsertOrUpdateAllBuilder.build())

        val methodDeleteOneBuilder = FunSpec.builder(FunctionNames.DELETE.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
            .addParameter(nameOfObject, typeOfCompanion)
            .addAnnotation(Delete::class)

        classBuilder.addFunction(methodDeleteOneBuilder.build())

        val methodDeleteAllBuilder = FunSpec.builder(FunctionNames.DELETE.nameOfFuncForCompanion())
            .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT)
            .addParameter(nameOfObjects, typeOfListOfCompanions)
            .addAnnotation(Delete::class)

        classBuilder.addFunction(methodDeleteAllBuilder.build())

        val methodWrapperOfGetOneBuilder = FunSpec.builder(
            FunctionNames.GET_ONE.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfObject.copy(nullable = true))

        RoomCompanionUtils.attachPrimaryKeysToMethodParameters(
            methodWrapperOfGetOneBuilder, primaryKeys)

        FuncSpecStatementsGenerator.mapOutputToObject(
            methodWrapperOfGetOneBuilder,
            typeOfObject.copy(nullable = true),
            FunctionNames.GET_ONE.nameOfFuncForCompanion(), getOneMethodCallParameters)

        classBuilder.addFunction(methodWrapperOfGetOneBuilder.build())

        val methodWrapperOfGetOneLiveBuilder = FunSpec.builder(
            FunctionNames.GET_ONE_LIVE.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfLiveDataOfNullableObject)

        RoomCompanionUtils.attachPrimaryKeysToMethodParameters(
            methodWrapperOfGetOneLiveBuilder, primaryKeys)

        FuncSpecStatementsGenerator.mapOutputToLiveDataOfObject(
            methodWrapperOfGetOneLiveBuilder,
            typeOfObject,
            typeOfLiveDataOfNullableObject,
            FunctionNames.GET_ONE_LIVE.nameOfFuncForCompanion(), getOneMethodCallParameters)

        classBuilder.addFunction(methodWrapperOfGetOneLiveBuilder.build())

        val methodWrapperOfGetFlowLiveBuilder = FunSpec.builder(
            FunctionNames.GET_ONE_FLOW.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfFlowOfNullableObject)

        RoomCompanionUtils.attachPrimaryKeysToMethodParameters(
            methodWrapperOfGetFlowLiveBuilder, primaryKeys)

        FuncSpecStatementsGenerator.mapOutputToFlowOfObject(
            methodWrapperOfGetFlowLiveBuilder,
            typeOfObject,
            typeOfFlowOfNullableObject,
            FunctionNames.GET_ONE_FLOW.nameOfFuncForCompanion(), getOneMethodCallParameters)

        classBuilder.addFunction(methodWrapperOfGetFlowLiveBuilder.build())

        val methodWrapperOfGetAllBuilder = FunSpec.builder(
            FunctionNames.GET_ALL.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfListOfObjects)

        FuncSpecStatementsGenerator.mapOutputToObjects(methodWrapperOfGetAllBuilder,
            typeOfObject,
            typeOfListOfObjects,
            FunctionNames.GET_ALL.nameOfFuncForCompanion())

        classBuilder.addFunction(methodWrapperOfGetAllBuilder.build())

        val methodWrapperOfGetAllLiveBuilder = FunSpec.builder(
            FunctionNames.GET_ALL_LIVE.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfLiveDataOfListOfObjects)

        FuncSpecStatementsGenerator.mapOutputToLiveDataOfObjects(methodWrapperOfGetAllLiveBuilder,
            typeOfObject,
            typeOfLiveDataOfListOfObjects,
            FunctionNames.GET_ALL_LIVE.nameOfFuncForCompanion())

        classBuilder.addFunction(methodWrapperOfGetAllLiveBuilder.build())

        val methodWrapperOfGetAllFlowBuilder = FunSpec.builder(
            FunctionNames.GET_ALL_FLOW.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfFlowOfListOfObjects)

        FuncSpecStatementsGenerator.mapOutputToFlowOfObjects(methodWrapperOfGetAllFlowBuilder,
            typeOfObject,
            typeOfFlowOfListOfObjects,
            FunctionNames.GET_ALL_FLOW.nameOfFuncForCompanion())

        classBuilder.addFunction(methodWrapperOfGetAllFlowBuilder.build())

        val methodWrapperOfGetAllLivePagedBuilder = FunSpec.builder(
            FunctionNames.GET_ALL_LIVE_PAGED.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfLiveDataOfPagedListOfObjects)

        FuncSpecStatementsGenerator.mapOutputToLiveDataOfPagedListObjects(
            methodWrapperOfGetAllLivePagedBuilder,
            typeOfLiveDataOfPagedListOfObjects,
            pageSize,
            FunctionNames.GET_ALL_DATA_SOURCE.nameOfFuncForCompanion())

        classBuilder.addFunction(methodWrapperOfGetAllLivePagedBuilder.build())

        val methodWrapperOfGetAllPagingSourceBuilder = FunSpec.builder(
            FunctionNames.GET_ALL_PAGING_SOURCE.nameOfFunc())
            .addModifiers(KModifier.PUBLIC)
            .returns(typeOfPagingSourceOfObject)

        FuncSpecStatementsGenerator.mapOutputToPagingSource(
            methodWrapperOfGetAllPagingSourceBuilder,
            typeOfPagingSourceOfObject,
            FunctionNames.GET_ALL_DATA_SOURCE.nameOfFuncForCompanion())

        classBuilder.addFunction(methodWrapperOfGetAllPagingSourceBuilder.build())

        arrayOf(
            Pair(FunctionNames.INSERT, LONG),
            Pair(FunctionNames.UPDATE, UNIT),
            Pair(FunctionNames.INSERT_OR_UPDATE, UNIT),
            Pair(FunctionNames.DELETE, UNIT),
        ).forEach {
            val methodName = it.first
            val returnType = it.second

            val methodWrapperOfActionOnOneBuilder = FunSpec.builder(
                methodName.nameOfFunc())
                .addModifiers(KModifier.PUBLIC)
                .addParameter(nameOfObject, typeOfObject.copy(true))
                .returns(returnType)
                .addStatement(
                    "if (%N == null) return %L".trimIndent(),
                    nameOfObject,
                    when (returnType) {
                        LONG -> 0L
                        else -> ""
                    }

                )
                .addStatement(
                    "return %N(%T.fromObject(%N))",
                    methodName.nameOfFuncForCompanion(), typeOfCompanion, nameOfObject
                )

            classBuilder.addFunction(methodWrapperOfActionOnOneBuilder.build())
        }

        arrayOf(
            Pair(FunctionNames.INSERT, typeOfListOfLong),
            Pair(FunctionNames.UPDATE, UNIT),
            Pair(FunctionNames.INSERT_OR_UPDATE, UNIT),
        ).forEach {
            val methodName = it.first
            val returnType = it.second

            val methodWrapperOfActionOnAllBuilder = FunSpec.builder(
                methodName.nameOfFunc())
                .addModifiers(KModifier.PUBLIC)
                .addParameter(nameOfObjects, typeOfListOfObjects.copy(true))
                .returns(returnType)
                .addStatement(
                    "if (%N.isNullOrEmpty()) return %L",
                    nameOfObjects,
                    when (returnType) {
                        typeOfListOfLong -> "emptyList()"
                        else -> ""
                    }
                )
                .addStatement(
                    """
                        return %N(%N.map({
                            %T.fromObject(it)
                        }))
                    """.trimIndent(),
                    methodName.nameOfFuncForCompanion(), nameOfObjects, typeOfCompanion
                )
            classBuilder.addFunction(methodWrapperOfActionOnAllBuilder.build())
        }

        return singleClassResult(symbol,
            packageName, classBuilder)
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy