Skip to content

Commit 3d78b00

Browse files
committed
Introduce CrudRepositoryWithContextParameters interface, refactor RepositoryProcessor for context parameter support, and update Gradle build with language feature enablement.
1 parent 914ebc1 commit 3d78b00

File tree

5 files changed

+96
-10
lines changed

5 files changed

+96
-10
lines changed

sqlx4k-codegen/src/jvmMain/kotlin/io/github/smyrgeorge/sqlx4k/processor/RepositoryProcessor.kt

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,24 @@ class RepositoryProcessor(
181181
*/
182182
private fun parseRepositoryAnnotation(repo: KSClassDeclaration): Pair<KSClassDeclaration, String> {
183183
fun implementsCrudRepository(repo: KSClassDeclaration): KSClassDeclaration {
184-
// find CrudRepository<T>
184+
val repoTypeName =
185+
if (ENABLE_CONTEXT_PARAMETERS) TypeNames.CRUD_REPOSITORY_WITH_CONTEXT_PARAMETERS
186+
else TypeNames.CRUD_REPOSITORY
187+
val repoSimpleName = repoTypeName.substringAfterLast(".")
188+
// find CrudRepository<T> or CrudRepositoryWithContextParameters<T>
185189
val st = repo.superTypes.map { it.resolve() }
186-
.firstOrNull { it.declaration.qualifiedName() == TypeNames.CRUD_REPOSITORY }
187-
?: error("@Repository interface ${repo.qualifiedName()} must extend ${TypeNames.CRUD_REPOSITORY}<T>")
190+
.firstOrNull { it.declaration.qualifiedName() == repoTypeName }
191+
?: error("@Repository interface ${repo.qualifiedName()} must extend $repoTypeName<T>")
188192
val typeArg = st.arguments.firstOrNull()?.type?.resolve()
189-
?: error("${repo.qualifiedName()} implements CrudRepository without type argument; expected CrudRepository<T>")
193+
?: error("${repo.qualifiedName()} implements $repoSimpleName without type argument; expected $repoSimpleName<T>")
190194
val domainDecl = typeArg.declaration as? KSClassDeclaration
191-
?: error("CrudRepository type argument must be a class on ${repo.qualifiedName()}")
195+
?: error("$repoSimpleName type argument must be a class on ${repo.qualifiedName()}")
192196
// ensure @Table
193197
val hasTable = domainDecl.annotations.any {
194198
val qn = it.qualifiedName()
195199
qn == TypeNames.TABLE_ANNOTATION
196200
}
197-
if (!hasTable) error("CrudRepository generic parameter must be @Table-annotated (${domainDecl.qualifiedName()})")
201+
if (!hasTable) error("$repoSimpleName generic parameter must be @Table-annotated (${domainDecl.qualifiedName()})")
198202
return domainDecl
199203
}
200204

@@ -510,7 +514,11 @@ class RepositoryProcessor(
510514
when (val idQn = idProp.type.resolve().declaration.qualifiedName()) {
511515
TypeNames.KOTLIN_INT, TypeNames.KOTLIN_LONG -> {
512516
val zeroLiteral = if (idQn == TypeNames.KOTLIN_INT) "0" else "0L"
513-
file += " if (entity.$idName == $zeroLiteral) insert(context, entity) else update(context, entity)\n"
517+
file += if (ENABLE_CONTEXT_PARAMETERS) {
518+
" if (entity.$idName == $zeroLiteral) insert(entity) else update(entity)\n"
519+
} else {
520+
" if (entity.$idName == $zeroLiteral) insert(context, entity) else update(context, entity)\n"
521+
}
514522
file += " }\n"
515523
}
516524

sqlx4k-codegen/src/jvmMain/kotlin/io/github/smyrgeorge/sqlx4k/processor/TypeNames.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ object TypeNames {
1313

1414
// Core interfaces/classes
1515
const val CRUD_REPOSITORY = "io.github.smyrgeorge.sqlx4k.CrudRepository"
16+
const val CRUD_REPOSITORY_WITH_CONTEXT_PARAMETERS = "io.github.smyrgeorge.sqlx4k.CrudRepositoryWithContextParameters"
1617
const val QUERY_EXECUTOR = "io.github.smyrgeorge.sqlx4k.QueryExecutor"
1718
const val STATEMENT = "io.github.smyrgeorge.sqlx4k.Statement"
1819

sqlx4k/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ plugins {
77
kotlin {
88
@Suppress("unused")
99
sourceSets {
10+
all {
11+
languageSettings.enableLanguageFeature("ContextParameters")
12+
}
1013
configureEach {
1114
languageSettings.progressiveMode = true
1215
}

sqlx4k/src/commonMain/kotlin/io/github/smyrgeorge/sqlx4k/CrudRepository.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,16 @@ interface CrudRepository<T> {
5353
suspend fun delete(context: QueryExecutor, entity: T): Result<Unit>
5454

5555
/**
56-
* Saves the given entity using the specified driver context.
56+
* Saves the given entity to the data source using the specified driver context.
5757
*
58-
* Performs an insert or an update depending on the value of the `@Id` property.
59-
* Implementations decide whether to insert or update.
58+
* This method determines whether to perform an insert or update operation based on the entity's state.
59+
* If the operation is successful, the result will contain the saved entity.
60+
* In case of failure, the result contains the error details.
61+
*
62+
* @param context The database driver context used to execute the save operation.
63+
* @param entity The entity of type [T] to be saved in the data source.
64+
* @return A [Result] containing the saved entity of type [T] if the operation is successful,
65+
* or an error if the operation fails.
6066
*/
6167
suspend fun save(context: QueryExecutor, entity: T): Result<T>
6268
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package io.github.smyrgeorge.sqlx4k
2+
3+
/**
4+
* Interface defining a contract for basic CRUD (Create, Read, Update, Delete) operations on a data source.
5+
*
6+
* This interface abstracts common operations to be implemented for handling entities of type [T].
7+
* Each operation is asynchronous and returns a [Result], encapsulating either the successful result
8+
* or an error in case of failure.
9+
*
10+
* @param T The type of the entity managed by the repository.
11+
*/
12+
interface CrudRepositoryWithContextParameters<T> {
13+
/**
14+
* Inserts the given entity into the data source using the specified driver context.
15+
*
16+
* This method performs an asynchronous insert operation and returns the result.
17+
* If the operation is successful, the result will contain the inserted entity.
18+
* In case of failure, the result contains the error details.
19+
*
20+
* @param entity The entity of type [T] to be inserted into the data source.
21+
* @return A [Result] containing the inserted entity of type [T] if the operation is successful,
22+
* or an error if the operation fails.
23+
*/
24+
context(context: QueryExecutor)
25+
suspend fun insert(entity: T): Result<T>
26+
27+
/**
28+
* Updates the given entity in the data source using the specified driver context.
29+
*
30+
* This method performs an asynchronous update operation and returns the result.
31+
* If the operation is successful, the result will contain the updated entity.
32+
* In case of failure, the result contains the error details.
33+
*
34+
* @param entity The entity of type [T] to be updated in the data source.
35+
* @return A [Result] containing the updated entity of type [T] if the operation is successful,
36+
* or an error if the operation fails.
37+
*/
38+
context(context: QueryExecutor)
39+
suspend fun update(entity: T): Result<T>
40+
41+
/**
42+
* Deletes the given entity from the data source using the specified driver context.
43+
*
44+
* This method performs an asynchronous delete operation and returns the result.
45+
* If the operation is successful, the result will contain a successful unit value.
46+
* In case of failure, the result contains the error details.
47+
*
48+
* @param entity The entity of type [T] to be deleted from the data source.
49+
* @return A [Result] containing a [Unit] value if the operation is successful,
50+
* or an error if the operation fails.
51+
*/
52+
context(context: QueryExecutor)
53+
suspend fun delete(entity: T): Result<Unit>
54+
55+
/**
56+
* Saves the given entity to the data source using the specified driver context.
57+
*
58+
* This method determines whether to perform an insert or update operation based on the entity's state.
59+
* If the operation is successful, the result will contain the saved entity.
60+
* In case of failure, the result contains the error details.
61+
*
62+
* @param entity The entity of type [T] to be saved in the data source.
63+
* @return A [Result] containing the saved entity of type [T] if the operation is successful,
64+
* or an error if the operation fails.
65+
*/
66+
context(context: QueryExecutor)
67+
suspend fun save(entity: T): Result<T>
68+
}

0 commit comments

Comments
 (0)