Skip to content

Commit 9b2cc56

Browse files
authored
fix: add unique ids for queries (#25)
Close #24
1 parent 7404e5e commit 9b2cc56

File tree

11 files changed

+314
-120
lines changed

11 files changed

+314
-120
lines changed

.github/workflows/test.yml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
inputs:
10+
logLevel:
11+
description: 'Log Level'
12+
required: false
13+
default: 'warning'
14+
type: choice
15+
options:
16+
- info
17+
- warning
18+
- debug
19+
20+
concurrency:
21+
cancel-in-progress: true
22+
group: ${{ github.workflow }}-${{ github.ref }}
23+
24+
permissions:
25+
contents: read
26+
checks: write
27+
id-token: write
28+
29+
jobs:
30+
test-library:
31+
name: Run Library Tests
32+
runs-on: macos-latest
33+
steps:
34+
- name: Check out code
35+
uses: actions/checkout@v2
36+
- name: Set up JDK 17
37+
uses: actions/setup-java@v2
38+
with:
39+
distribution: adopt
40+
java-version: 17
41+
- name: Run Compiler Tests
42+
run: ./gradlew library:compiler:allTests
43+
- name: Publish Test Results
44+
uses: mikepenz/action-junit-report@v4
45+
if: success() || failure()
46+
with:
47+
report_paths: '**/build/test-results/**/TEST-*.xml'
48+
include_passed: true
49+
fail_on_failure: true
50+
annotate_notice: true
51+
follow_symlink: true

convention/multiplatform/build.gradle.kts

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ plugins {
33
id(libs.plugins.java.gradle.plugin.get().pluginId)
44
}
55

6+
kotlin {
7+
jvmToolchain(17)
8+
}
9+
610
gradlePlugin {
711
plugins.create("multiplatform") {
812
id = "com.attafitamim.kabin.multiplatform"

convention/publishing/build.gradle.kts

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ plugins {
33
id(libs.plugins.java.gradle.plugin.get().pluginId)
44
}
55

6+
kotlin {
7+
jvmToolchain(17)
8+
}
9+
610
gradlePlugin {
711
plugins.create("publish") {
812
id = "com.attafitamim.kabin.publish"

convention/publishing/src/main/kotlin/com/attafitamim/kabin/publish/PublishConventions.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.gradle.api.publish.maven.MavenPomScm
1010

1111
class PublishConventions : Plugin<Project> {
1212

13-
private val version = "0.1.0-alpha10"
13+
private val version = "0.1.0-alpha11"
1414
private val group = "com.attafitamim.kabin"
1515

1616
override fun apply(project: Project) {

library/compiler/build.gradle.kts

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ kotlin {
2121
implementation(libs.kotlin.ksp)
2222
implementation(libs.sqldelight.runtime)
2323
}
24+
25+
jvmTest.dependencies {
26+
implementation(libs.junit)
27+
}
2428
}
2529

2630
java {

library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/generator/dao/DaoGenerator.kt

+34-13
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,15 @@ class DaoGenerator(
514514
val entityColumnAccess = entitySpec
515515
.getColumnAccessChain(compoundRelationSpec.relation.entityColumn)
516516

517-
val functionName = entitySpec.getQueryByColumnsName(
518-
entityColumnAccess.last(),
517+
val directEntityColumn = entityColumnAccess.last()
518+
519+
val entityQuery = getSelectSQLQuery(
520+
entitySpec,
521+
directEntityColumn
522+
)
523+
524+
val functionName = entitySpec.getQueryFunctionName(
525+
entityQuery,
519526
isNullable = false,
520527
parent = null
521528
)
@@ -524,20 +531,26 @@ class DaoGenerator(
524531
if (junctionSpec != null) {
525532
val junctionParentAccess = junctionSpec.entitySpec
526533
.getColumnAccessChain(junctionSpec.parentColumn)
534+
.last()
535+
536+
val junctionQuery = getSelectSQLQuery(
537+
junctionSpec.entitySpec,
538+
junctionParentAccess
539+
)
540+
527541
val junctionEntityAccess = junctionSpec.entitySpec
528542
.getColumnAccessChain(junctionSpec.entityColumn)
529543

530544
val awaitFunction = "awaitAsOneNotNullIO"
531545
val directJunctionColumn = junctionEntityAccess.last()
532-
val directEntityColumn = entityColumnAccess.last()
533546
val adapter = directJunctionColumn
534547
.getAdapterReference(directEntityColumn)
535548

536549
adapter?.let(adapters::add)
537550

538551
val junctionElement = "junction"
539-
val junctionFunctionName = junctionSpec.entitySpec.getQueryByColumnsName(
540-
junctionParentAccess.last(),
552+
val junctionFunctionName = junctionSpec.entitySpec.getQueryFunctionName(
553+
junctionQuery,
541554
isNullable = false,
542555
parent = null
543556
)
@@ -561,7 +574,6 @@ class DaoGenerator(
561574
val awaitFunction = property.dataTypeSpec.getAwaitFunction()
562575

563576
val directParentColumn = parentColumnAccess.last()
564-
val directEntityColumn = entityColumnAccess.last()
565577
val adapter = directParentColumn
566578
.getAdapterReference(directEntityColumn)
567579

@@ -689,15 +701,19 @@ class DaoGenerator(
689701
val directEntityColumn = entityColumnAccess.last()
690702
val directEntityColumnName = directEntityColumn.declaration.simpleNameString
691703
if (junctionSpec != null) {
692-
val junctionParentColumn = junctionSpec.entitySpec
704+
val junctionColumn = junctionSpec.entitySpec
693705
.getColumnAccessChain(junctionSpec.parentColumn)
706+
.last()
694707

695708
actualFunctionName = junctionSpec.entitySpec.getQueryByColumnsName(
696-
junctionParentColumn.toSortedSet(),
709+
junctionColumn,
697710
isNullable = false,
698711
parent = null
699712
)
700713

714+
val junctionParentColumn = junctionSpec.entitySpec
715+
.getColumnAccessChain(junctionSpec.parentColumn)
716+
701717
val directJunctionParentColumn = junctionParentColumn.last()
702718
val directJunctionParentColumnName = directJunctionParentColumn.declaration.simpleNameString
703719
parameterReference = ParameterReference(
@@ -710,10 +726,9 @@ class DaoGenerator(
710726
directEntityColumn.declaration.type.toTypeName()
711727
)
712728

713-
714729
actualFunctionName = if (relationSpec.property.dataTypeSpec.dataType is DataTypeSpec.DataType.Collection) {
715730
val functionName = compoundSpec.declaration.getQueryByColumnsName(
716-
entityColumnAccess.toSortedSet(),
731+
entityColumnAccess,
717732
isNullable = false,
718733
parent = null
719734
)
@@ -723,7 +738,7 @@ class DaoGenerator(
723738
}
724739
} else {
725740
compoundReturnType.getQueryByColumnsName(
726-
entityColumnAccess.toSortedSet(),
741+
entityColumnAccess,
727742
parent = null
728743
)
729744
}
@@ -747,6 +762,12 @@ class DaoGenerator(
747762
if (junctionSpec != null) {
748763
val junctionParentAccess = junctionSpec.entitySpec
749764
.getColumnAccessChain(junctionSpec.parentColumn)
765+
.last()
766+
767+
val junctionQuery = getSelectSQLQuery(
768+
junctionSpec.entitySpec,
769+
junctionParentAccess
770+
)
750771

751772
val junctionEntityAccess = junctionSpec.entitySpec
752773
.getColumnAccessChain(junctionSpec.entityColumn)
@@ -758,8 +779,8 @@ class DaoGenerator(
758779
adapter?.let(adapters::add)
759780

760781
val junctionElement = "junction"
761-
val junctionFunctionName = junctionSpec.entitySpec.getQueryByColumnsName(
762-
junctionParentAccess.last(),
782+
val junctionFunctionName = junctionSpec.entitySpec.getQueryFunctionName(
783+
junctionQuery,
763784
isNullable = false,
764785
parent = null
765786
)

library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/syntax/SQLQuery.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ sealed interface SQLQuery {
1111
data class Parameters(
1212
override val value: String,
1313
override val parametersSize: Int,
14-
val queryParameters: Collection<QueryParameter>,
14+
val queryParameters: List<QueryParameter>,
1515
val mutatedKeys: Set<String>,
1616
override val queriedKeys: Set<String>
1717
): SQLQuery {

library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/sqldelight/PoetSqlDelightUtils.kt

+74-27
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,53 @@ import com.attafitamim.kabin.specs.dao.DataTypeSpec
55
import com.squareup.kotlinpoet.CodeBlock
66
import com.squareup.kotlinpoet.FunSpec
77

8+
89
const val EXECUTE_FUNCTION = "execute"
910
const val EXECUTE_QUERY_FUNCTION = "executeQuery"
1011

12+
private val generatedIds = HashMap<String, Int>()
13+
private val generatedHashCodes = HashMap<Int, String>()
14+
15+
private const val MAX_UNIQUE_CYCLES = 100
16+
private const val CYCLES_START_INDEX = 0
17+
private const val HASH_CODE_INTERVAL = 31
18+
19+
fun SQLQuery.getQueryIdentifier(): Int? = when (this) {
20+
is SQLQuery.Columns -> value.getUniqueQueryIdentifier()
21+
is SQLQuery.Parameters -> value.getUniqueQueryIdentifier()
22+
is SQLQuery.Raw -> null
23+
}
24+
25+
// TODO: optimize this
26+
fun String.getUniqueQueryIdentifier(): Int? {
27+
val generatedId = generatedIds[this]
28+
if (generatedId != null) {
29+
return generatedId
30+
}
31+
32+
var cycle = CYCLES_START_INDEX
33+
while (cycle <= MAX_UNIQUE_CYCLES) {
34+
val originalHashCode = hashCode()
35+
val hashCode = if (cycle == CYCLES_START_INDEX) {
36+
originalHashCode
37+
} else {
38+
originalHashCode * (cycle * HASH_CODE_INTERVAL)
39+
}
40+
41+
val valueLinkedToHashCode = generatedHashCodes[hashCode]
42+
if (valueLinkedToHashCode == null || valueLinkedToHashCode == this) {
43+
generatedIds[this] = hashCode
44+
generatedHashCodes[hashCode] = this
45+
return hashCode
46+
}
47+
48+
cycle++
49+
}
50+
51+
return null
52+
}
53+
54+
1155
fun FunSpec.Builder.addDriverQueryCode(
1256
query: SQLQuery,
1357
function: String = EXECUTE_QUERY_FUNCTION,
@@ -56,21 +100,22 @@ fun FunSpec.Builder.addDriverRawQueryCode(
56100
function: String,
57101
binderCode: (CodeBlock.Builder.() -> Unit)? = null
58102
): FunSpec.Builder = apply {
103+
val identifier = query.getQueryIdentifier()
59104
val logic = if (function == EXECUTE_QUERY_FUNCTION) {
60105
"""
61106
|val result = driver.executeQuery(
62-
| null,
63-
| %L,
64-
| mapper,
65-
| 0
107+
| identifier = $identifier,
108+
| sql = %L,
109+
| mapper = mapper,
110+
| parameters = 0
66111
|)
67112
""".trimMargin()
68113
} else {
69114
"""
70115
|driver.execute(
71-
| null,
72-
| %L,
73-
| 0
116+
| identifier = $identifier,
117+
| sql = %L,
118+
| parameters = 0
74119
|)
75120
""".trimMargin()
76121
}
@@ -142,30 +187,31 @@ fun FunSpec.Builder.addDriverQueryCode(
142187

143188
sizeExpression.append(simpleParametersSize)
144189
val codeBlockBuilder = CodeBlock.builder()
145-
.addStatement("val kabinQuery = %P", query.value)
146-
.addStatement("val kabinParametersCount = $sizeExpression")
190+
.addStatement("val internalQuerySql = %P", query.value)
191+
.addStatement("val internalQueryParametersCount = $sizeExpression")
147192

193+
val originalIdentifier = query.getQueryIdentifier()
148194
val identifier = if (addedConstants.isEmpty()) {
149-
query.value.hashCode()
195+
originalIdentifier
150196
} else {
151-
"kabinQuery.hashCode()"
197+
null
152198
}
153199

154200
val logic = if (function == "executeQuery") {
155201
"""
156202
|val result = driver.executeQuery(
157-
| $identifier,
158-
| kabinQuery,
159-
| mapper,
160-
| kabinParametersCount
203+
| identifier = $identifier,
204+
| sql = internalQuerySql,
205+
| mapper = mapper,
206+
| parameters = internalQueryParametersCount
161207
|)
162208
""".trimMargin()
163209
} else {
164210
"""
165211
|driver.execute(
166-
| $identifier,
167-
| kabinQuery,
168-
| kabinParametersCount
212+
| identifier = $identifier,
213+
| sql = internalQuerySql,
214+
| parameters = internalQueryParametersCount
169215
|)
170216
""".trimMargin()
171217
}
@@ -177,7 +223,8 @@ fun FunSpec.Builder.addDriverQueryCode(
177223
}
178224

179225
if (query.mutatedKeys.isNotEmpty()) {
180-
codeBlockBuilder.beginControlFlow("notifyQueries($identifier) { emit ->")
226+
val notifyIdentifier = identifier ?: -1
227+
codeBlockBuilder.beginControlFlow("notifyQueries($notifyIdentifier) { emit ->")
181228

182229
query.mutatedKeys.forEach { key ->
183230
codeBlockBuilder.addStatement("emit(%S)", key)
@@ -200,22 +247,22 @@ fun FunSpec.Builder.addDriverQueryCode(
200247
) = apply {
201248
val codeBlockBuilder = CodeBlock.builder()
202249

203-
val identifier = query.hashCode()
250+
val identifier = query.getQueryIdentifier()
204251
val logic = if (function == EXECUTE_QUERY_FUNCTION) {
205252
"""
206253
|val result = driver.executeQuery(
207-
| $identifier,
208-
| %P,
209-
| mapper,
210-
| ${query.parametersSize}
254+
| identifier = $identifier,
255+
| sql = %P,
256+
| mapper = mapper,
257+
| parameters = ${query.parametersSize}
211258
|)
212259
""".trimMargin()
213260
} else {
214261
"""
215262
|driver.execute(
216-
| $identifier,
217-
| %P,
218-
| ${query.parametersSize}
263+
| identifier = $identifier,
264+
| sql = %P,
265+
| parameters = ${query.parametersSize}
219266
|)
220267
""".trimMargin()
221268
}

0 commit comments

Comments
 (0)