Skip to content

Commit

Permalink
Merge pull request #8 from teogor/feature/raw-operation-annotation
Browse files Browse the repository at this point in the history
Introduce Fine-grained Control over Generated Operations
  • Loading branch information
teogor authored Feb 15, 2024
2 parents 19783d2 + 84619ea commit 08648af
Show file tree
Hide file tree
Showing 19 changed files with 252 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import dev.teogor.stitch.RawOperation
import dev.teogor.stitch.core.database.model.SavedGame
import kotlinx.coroutines.flow.Flow

@Dao
interface SavedGameDao {
@RawOperation
@Query("SELECT * FROM saved_games")
fun getAll(): Flow<List<SavedGame>>

Expand Down
30 changes: 12 additions & 18 deletions codegen/api/codegen.api
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,18 @@ public final class dev/teogor/stitch/codegen/facades/Logger$Companion {
}

public final class dev/teogor/stitch/codegen/model/CodeGenConfig {
public fun <init> (ZZLjava/lang/String;)V
public fun <init> (ZZLjava/lang/String;Ldev/teogor/stitch/api/OperationGenerationLevel;)V
public final fun component1 ()Z
public final fun component2 ()Z
public final fun component3 ()Ljava/lang/String;
public final fun copy (ZZLjava/lang/String;)Ldev/teogor/stitch/codegen/model/CodeGenConfig;
public static synthetic fun copy$default (Ldev/teogor/stitch/codegen/model/CodeGenConfig;ZZLjava/lang/String;ILjava/lang/Object;)Ldev/teogor/stitch/codegen/model/CodeGenConfig;
public final fun component4 ()Ldev/teogor/stitch/api/OperationGenerationLevel;
public final fun copy (ZZLjava/lang/String;Ldev/teogor/stitch/api/OperationGenerationLevel;)Ldev/teogor/stitch/codegen/model/CodeGenConfig;
public static synthetic fun copy$default (Ldev/teogor/stitch/codegen/model/CodeGenConfig;ZZLjava/lang/String;Ldev/teogor/stitch/api/OperationGenerationLevel;ILjava/lang/Object;)Ldev/teogor/stitch/codegen/model/CodeGenConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getAddDocumentation ()Z
public final fun getGenerateOperations ()Z
public final fun getEnableOperationGeneration ()Z
public final fun getGeneratedPackageName ()Ljava/lang/String;
public final fun getOperationGenerationLevel ()Ldev/teogor/stitch/api/OperationGenerationLevel;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down Expand Up @@ -102,26 +104,18 @@ public final class dev/teogor/stitch/codegen/model/FieldKind {
public fun toString ()Ljava/lang/String;
}

public final class dev/teogor/stitch/codegen/model/FunctionData {
public fun <init> (Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;)Ldev/teogor/stitch/codegen/model/FunctionData;
public static synthetic fun copy$default (Ldev/teogor/stitch/codegen/model/FunctionData;Ljava/lang/String;ILjava/lang/Object;)Ldev/teogor/stitch/codegen/model/FunctionData;
public fun equals (Ljava/lang/Object;)Z
public final fun getName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class dev/teogor/stitch/codegen/model/FunctionKind {
public fun <init> (Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;)V
public fun <init> (Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;Z)V
public synthetic fun <init> (Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Z
public final fun component3 ()Lcom/squareup/kotlinpoet/TypeName;
public final fun component4 ()Ljava/util/List;
public final fun copy (Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;)Ldev/teogor/stitch/codegen/model/FunctionKind;
public static synthetic fun copy$default (Ldev/teogor/stitch/codegen/model/FunctionKind;Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;ILjava/lang/Object;)Ldev/teogor/stitch/codegen/model/FunctionKind;
public final fun component5 ()Z
public final fun copy (Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;Z)Ldev/teogor/stitch/codegen/model/FunctionKind;
public static synthetic fun copy$default (Ldev/teogor/stitch/codegen/model/FunctionKind;Ljava/lang/String;ZLcom/squareup/kotlinpoet/TypeName;Ljava/util/List;ZILjava/lang/Object;)Ldev/teogor/stitch/codegen/model/FunctionKind;
public fun equals (Ljava/lang/Object;)Z
public final fun getEnableRawOperationGeneration ()Z
public final fun getName ()Ljava/lang/String;
public final fun getParameters ()Ljava/util/List;
public final fun getReturnType ()Lcom/squareup/kotlinpoet/TypeName;
Expand Down
1 change: 1 addition & 0 deletions codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach

dependencies {
api(project(mapOf("path" to ":common")))
api(project(mapOf("path" to ":gradle-plugin-api")))

api(libs.kotlin.poet)
api(libs.kotlin.poet.ksp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class CodeGenerator(

stitchModuleOutputWriter.write(databaseModels, roomModels)

if (codeGenConfig.generateOperations) {
if (codeGenConfig.enableOperationGeneration) {
operationOutputWriter.write(databaseModels, roomModels)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

package dev.teogor.stitch.codegen.model

import dev.teogor.stitch.api.OperationGenerationLevel

data class CodeGenConfig(
val addDocumentation: Boolean,
val generateOperations: Boolean,
val enableOperationGeneration: Boolean,
val generatedPackageName: String?,
val operationGenerationLevel: OperationGenerationLevel,
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package dev.teogor.stitch.codegen.model

import com.squareup.kotlinpoet.TypeName

data class FunctionData(val name: String)

data class DatabaseModel(
val entities: List<TypeName>,
val type: TypeName,
Expand All @@ -45,6 +43,7 @@ data class FunctionKind(
val isSuspend: Boolean,
val returnType: TypeName,
val parameters: List<ParameterKind>,
val enableRawOperationGeneration: Boolean = false,
)

data class ParameterKind(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal interface ServiceLocatorAccessor {
}

abstract class OutputWriter(
private val codeGenConfig: CodeGenConfig,
internal val codeGenConfig: CodeGenConfig,
) {

fun RoomModel.getPackageName() = codeGenConfig.generatedPackageName ?: packageName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.UNIT
import dev.teogor.stitch.Operation
import dev.teogor.stitch.OperationSignature
import dev.teogor.stitch.api.OperationGenerationLevel
import dev.teogor.stitch.codegen.commons.JAVAX_INJECT
import dev.teogor.stitch.codegen.commons.fileBuilder
import dev.teogor.stitch.codegen.commons.titleCase
Expand All @@ -46,7 +47,19 @@ class OperationOutputWriter(
roomModels.forEach { room ->
val generatedClasses = mutableMapOf<String, MutableList<FunSpec>>()

room.functions.forEach { function ->
val filteredFunctions = when (codeGenConfig.operationGenerationLevel) {
OperationGenerationLevel.ALL -> room.functions
OperationGenerationLevel.EXPLICIT -> room.functions.filter {
it.enableRawOperationGeneration
}

OperationGenerationLevel.AUTOMATIC -> room.functions.filter {
it.enableRawOperationGeneration
}

OperationGenerationLevel.DISABLED -> emptyList()
}
filteredFunctions.forEach { function ->
val existingFunctions = generatedClasses.getOrDefault(
function.name,
mutableListOf(),
Expand Down
4 changes: 4 additions & 0 deletions common/api/common.api
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ public abstract interface annotation class dev/teogor/stitch/Operation : java/la
public abstract interface annotation class dev/teogor/stitch/OperationSignature : java/lang/annotation/Annotation {
}

public abstract interface annotation class dev/teogor/stitch/RawOperation : java/lang/annotation/Annotation {
public abstract fun generate ()Z
}

38 changes: 38 additions & 0 deletions common/src/main/kotlin/dev/teogor/stitch/RawOperation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2024 teogor (Teodor Grigor)
*
* 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
*
* https://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 dev.teogor.stitch

/**
* An annotation for marking DAO methods that should be generated as raw
* operations.
*
* This annotation instructs the Stitch plugin to generate separate operation
* classes for annotated methods in your DAOs. These operation classes provide
* a convenient way to invoke and manage the corresponding database queries
* directly.
*
* @param generate [Boolean] (default: `true`) Whether to generate the operation
* class for this method.
*
* @see Operation
* @see OperationSignature
*/
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class RawOperation(
val generate: Boolean = true,
)
20 changes: 18 additions & 2 deletions gradle-plugin-api/api/gradle-plugin-api.api
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
public final class dev/teogor/stitch/api/OperationGenerationLevel : java/lang/Enum {
public static final field ALL Ldev/teogor/stitch/api/OperationGenerationLevel;
public static final field AUTOMATIC Ldev/teogor/stitch/api/OperationGenerationLevel;
public static final field Companion Ldev/teogor/stitch/api/OperationGenerationLevel$Companion;
public static final field DISABLED Ldev/teogor/stitch/api/OperationGenerationLevel;
public static final field EXPLICIT Ldev/teogor/stitch/api/OperationGenerationLevel;
public static fun valueOf (Ljava/lang/String;)Ldev/teogor/stitch/api/OperationGenerationLevel;
public static fun values ()[Ldev/teogor/stitch/api/OperationGenerationLevel;
}

public final class dev/teogor/stitch/api/OperationGenerationLevel$Companion {
public final fun from (Ljava/lang/String;)Ldev/teogor/stitch/api/OperationGenerationLevel;
}

public abstract interface class dev/teogor/stitch/api/StitchExtension {
public abstract fun getAddDocumentation ()Z
public abstract fun getGenerateOperations ()Z
public abstract fun getEnableOperationGeneration ()Z
public abstract fun getGeneratedPackageName ()Ljava/lang/String;
public abstract fun getOperationGenerationLevel ()Ldev/teogor/stitch/api/OperationGenerationLevel;
public abstract fun setAddDocumentation (Z)V
public abstract fun setGenerateOperations (Z)V
public abstract fun setEnableOperationGeneration (Z)V
public abstract fun setGeneratedPackageName (Ljava/lang/String;)V
public abstract fun setOperationGenerationLevel (Ldev/teogor/stitch/api/OperationGenerationLevel;)V
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2024 teogor (Teodor Grigor)
*
* 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
*
* https://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 dev.teogor.stitch.api

/**
* Defines the level of generation for Stitch operation classes.
*
* This enum controls how the plugin generates operation classes from DAO
* methods.
* You can configure the desired level through plugin options or environment
* variables.
*
* @see dev.teogor.stitch.RawOperation
*
* @property ALL Generate operations for all methods in DAOs.
* @property EXPLICIT Generate operations only for methods annotated with
* [dev.teogor.stitch.RawOperation].
* @property AUTOMATIC Automatically choose whether to generate based on heuristics
* or rules.
* @property DISABLED Do not generate any operation classes, even for annotated
* methods.
*/
enum class OperationGenerationLevel {
ALL,
EXPLICIT,
AUTOMATIC,
DISABLED,
;

companion object {
/**
* Converts a string representation to the corresponding [OperationGenerationLevel].
*
* This function supports case-insensitive matching and throws an exception for invalid input.
*
* @param string The string to convert.
* @return The corresponding [OperationGenerationLevel] or throws an [IllegalArgumentException].
*/
fun from(string: String): OperationGenerationLevel {
return values().firstOrNull { it.name.lowercase() == string.lowercase() }
?: throw IllegalArgumentException("Invalid OperationGenerationLevel: $string")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,66 @@
package dev.teogor.stitch.api

/**
* Interface for configuring Stitch's behavior and features.
* Defines configuration options for Stitch code generation within your project.
*
* This interface allows you to:
* This interface provides properties that control various aspects of the generation
* process. You can extend this interface and implement it in your plugin to customize Stitch
* functionalities.
*
* - Enable or disable documentation generation.
* - Control the generation of operations (plugins or similar functionality).
* - Set the base package name for generated code or artifacts.
* @see dev.teogor.stitch.Plugin
*/
interface StitchExtension {
/**
* Enables or disables the generation of documentation.
* Controls whether to generate documentation comments in the generated code.
*
* Set to `true` to generate documentation, `false` to disable it.
* By default, this is set to `true`. Setting it to `false` will disable documentation
* generation.
*
* @return `true` if documentation is generated, `false` otherwise.
*/
var addDocumentation: Boolean

/**
* Enables or disables the generation of operations.
* Controls the overall generation of operation classes for DAO methods.
*
* Use this property to enable or disable operation generation entirely.
* By default, this is set to `true`. Setting it to `false` will disable operation generation
* even for methods annotated with [dev.teogor.stitch.RawOperation].
*
* For more granular control over operation generation, consider using the
* [operationGenerationLevel] property.
*
* Set to `true` to generate operations, `false` to disable it.
* @return `true` to enable operation generation, `false` to disable it.
*/
var generateOperations: Boolean
var enableOperationGeneration: Boolean

/**
* Defines the level of generation for Stitch operation classes.
*
* This property offers more fine-grained control over how operation classes are generated.
* You can choose from the following options:
*
* - **[OperationGenerationLevel.ALL]:** Generate operations for all methods in DAOs.
* - **[OperationGenerationLevel.EXPLICIT]:** Generate operations only for methods annotated
* with [dev.teogor.stitch.RawOperation].
* - **[OperationGenerationLevel.AUTOMATIC]:** Use heuristics or rules to automatically choose
* whether to generate for each method.
* - **[OperationGenerationLevel.DISABLED]:** Do not generate any operation classes, even for
* annotated methods.
*
* By default, this is set to [OperationGenerationLevel.EXPLICIT].
*
* @return The desired level of operation generation.
*/
var operationGenerationLevel: OperationGenerationLevel

/**
* Specifies the base package name for generated code or artifacts.
*
* Ensure this matches your project's package structure.
* This property defines the root package where your Stitch-generated code will be placed.
* Ensure it aligns with your project's package structure to avoid conflicts.
*
* @return The base package name for generated code.
*/
var generatedPackageName: String
}
8 changes: 5 additions & 3 deletions gradle-plugin/api/gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ public final class dev/teogor/stitch/Plugin$apply$1$1$inlined$sam$i$org_gradle_a
public abstract class dev/teogor/stitch/StitchExtensionImpl : dev/teogor/stitch/api/StitchExtension {
public fun <init> ()V
public fun getAddDocumentation ()Z
public fun getGenerateOperations ()Z
public fun getEnableOperationGeneration ()Z
public fun getGeneratedPackageName ()Ljava/lang/String;
public fun getOperationGenerationLevel ()Ldev/teogor/stitch/api/OperationGenerationLevel;
public fun setAddDocumentation (Z)V
public fun setGenerateOperations (Z)V
public fun setEnableOperationGeneration (Z)V
public fun setGeneratedPackageName (Ljava/lang/String;)V
public fun setOperationGenerationLevel (Ldev/teogor/stitch/api/OperationGenerationLevel;)V
}

public final class dev/teogor/stitch/StitchSchemaArgProvider : org/gradle/process/CommandLineArgumentProvider {
public static final field Companion Ldev/teogor/stitch/StitchSchemaArgProvider$Companion;
public fun <init> (ZZLjava/lang/String;)V
public fun <init> (ZZLjava/lang/String;Ldev/teogor/stitch/api/OperationGenerationLevel;)V
public synthetic fun asArguments ()Ljava/lang/Iterable;
public fun asArguments ()Ljava/util/List;
}
Expand Down
Loading

0 comments on commit 08648af

Please sign in to comment.