Skip to content

Commit 291c8ac

Browse files
new binding syntax(#8)
1 parent 8b2eabf commit 291c8ac

File tree

8 files changed

+164
-169
lines changed

8 files changed

+164
-169
lines changed

ktorm-core/src/main/kotlin/me/liuwj/ktorm/entity/EntityDml.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private fun EntityImplementation.findChangedColumns(fromTable: Table<*>): Map<Co
111111
var anyChanged = false
112112
var curr: Any? = this
113113

114-
for ((i, prop) in binding.withIndex()) {
114+
for ((i, prop) in binding.properties.withIndex()) {
115115
if (curr is Entity<*>) {
116116
curr = curr.implementation
117117
}
@@ -124,7 +124,7 @@ private fun EntityImplementation.findChangedColumns(fromTable: Table<*>): Map<Co
124124
check(curr != null)
125125

126126
if (curr.fromTable != null && curr.getRoot() != this) {
127-
val propPath = binding.subList(0, i + 1).joinToString(separator = ".", prefix = "this.") { it.name }
127+
val propPath = binding.properties.subList(0, i + 1).joinToString(separator = ".", prefix = "this.") { it.name }
128128
throw IllegalStateException("$propPath may be unexpectedly discarded after flushChanges, please save it to database first.")
129129
}
130130
}
@@ -165,7 +165,7 @@ internal fun EntityImplementation.doDiscardChanges() {
165165
is NestedBinding -> {
166166
var curr: Any? = this
167167

168-
for (prop in binding) {
168+
for (prop in binding.properties) {
169169
if (curr == null) {
170170
break
171171
}

ktorm-core/src/main/kotlin/me/liuwj/ktorm/entity/EntityExtensions.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ internal fun EntityImplementation.getColumnValue(column: Column<*>): Any? {
1919
}
2020
is NestedBinding -> {
2121
var curr: EntityImplementation? = this
22-
for ((i, prop) in binding.withIndex()) {
23-
if (i != binding.lastIndex) {
22+
for ((i, prop) in binding.properties.withIndex()) {
23+
if (i != binding.properties.lastIndex) {
2424
val child = curr?.getProperty(prop.name) as Entity<*>?
2525
curr = child?.implementation
2626
}
2727
}
28-
return curr?.getProperty(binding.last().name)
28+
return curr?.getProperty(binding.properties.last().name)
2929
}
3030
}
3131
}
@@ -50,8 +50,8 @@ internal fun EntityImplementation.setColumnValue(column: Column<*>, value: Any?)
5050
}
5151
is NestedBinding -> {
5252
var curr: EntityImplementation = this
53-
for ((i, prop) in binding.withIndex()) {
54-
if (i != binding.lastIndex) {
53+
for ((i, prop) in binding.properties.withIndex()) {
54+
if (i != binding.properties.lastIndex) {
5555
var child = curr.getProperty(prop.name) as Entity<*>?
5656
if (child == null) {
5757
child = Entity.create(prop.returnType.classifier as KClass<*>, parent = curr)
@@ -62,7 +62,7 @@ internal fun EntityImplementation.setColumnValue(column: Column<*>, value: Any?)
6262
}
6363
}
6464

65-
curr.setProperty(binding.last().name, value)
65+
curr.setProperty(binding.properties.last().name, value)
6666
}
6767
}
6868
}
@@ -87,8 +87,8 @@ internal fun EntityImplementation.forceSetColumnValue(column: Column<*>, value:
8787
}
8888
is NestedBinding -> {
8989
var curr: EntityImplementation = this
90-
for ((i, prop) in binding.withIndex()) {
91-
if (i != binding.lastIndex) {
90+
for ((i, prop) in binding.properties.withIndex()) {
91+
if (i != binding.properties.lastIndex) {
9292
var child = curr.getProperty(prop.name) as Entity<*>?
9393
if (child == null) {
9494
child = Entity.create(prop.returnType.classifier as KClass<*>, parent = curr)
@@ -99,7 +99,7 @@ internal fun EntityImplementation.forceSetColumnValue(column: Column<*>, value:
9999
}
100100
}
101101

102-
curr.setProperty(binding.last().name, value, forceSet = true)
102+
curr.setProperty(binding.properties.last().name, value, forceSet = true)
103103
}
104104
}
105105
}
@@ -130,7 +130,7 @@ internal fun EntityImplementation.isPrimaryKey(name: String): Boolean {
130130
}
131131

132132
for ((i, possibleFields) in namesPath.withIndex()) {
133-
if (binding[i].name !in possibleFields) {
133+
if (binding.properties[i].name !in possibleFields) {
134134
return false
135135
}
136136
}

ktorm-core/src/main/kotlin/me/liuwj/ktorm/schema/Column.kt

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,7 @@ sealed class ColumnBinding
1515
/**
1616
* Bind the column to nested properties, eg. employee.manager.department.id
1717
*/
18-
sealed class NestedBinding(vararg properties: KProperty1<*, *>) : ColumnBinding(), List<KProperty1<*, *>> by properties.asList()
19-
20-
/**
21-
* Bind the column to a simple property.
22-
*/
23-
data class NestedBinding1(
24-
val property: KProperty1<*, *>
25-
) : NestedBinding(property)
26-
27-
/**
28-
* Bind the column to double nested properties.
29-
*/
30-
data class NestedBinding2(
31-
val property1: KProperty1<*, *>,
32-
val property2: KProperty1<*, *>
33-
) : NestedBinding(property1, property2)
34-
35-
/**
36-
* Bind the column to triple nested properties
37-
*/
38-
data class NestedBinding3(
39-
val property1: KProperty1<*, *>,
40-
val property2: KProperty1<*, *>,
41-
val property3: KProperty1<*, *>
42-
) : NestedBinding(property1, property2, property3)
43-
44-
/**
45-
* Bind the column to 4 levels of nested properties
46-
*/
47-
data class NestedBinding4(
48-
val property1: KProperty1<*, *>,
49-
val property2: KProperty1<*, *>,
50-
val property3: KProperty1<*, *>,
51-
val property4: KProperty1<*, *>
52-
) : NestedBinding(property1, property2, property3, property4)
18+
data class NestedBinding(val properties: List<KProperty1<*, *>>) : ColumnBinding()
5319

5420
/**
5521
* Bind the column to a reference table, equivalent to a foreign key in relational databases.
@@ -58,10 +24,7 @@ data class NestedBinding4(
5824
* @see me.liuwj.ktorm.entity.joinReferencesAndSelect
5925
* @see me.liuwj.ktorm.entity.createEntity
6026
*/
61-
data class ReferenceBinding(
62-
val referenceTable: Table<*>,
63-
val onProperty: KProperty1<*, *>
64-
) : ColumnBinding()
27+
data class ReferenceBinding(val referenceTable: Table<*>, val onProperty: KProperty1<*, *>) : ColumnBinding()
6528

6629
/**
6730
* 列声明
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package me.liuwj.ktorm.schema
2+
3+
import me.liuwj.ktorm.entity.Entity
4+
import java.lang.reflect.InvocationHandler
5+
import java.lang.reflect.Method
6+
import java.lang.reflect.Proxy
7+
import kotlin.reflect.KClass
8+
import kotlin.reflect.KProperty1
9+
import kotlin.reflect.full.isSubclassOf
10+
11+
/* internal */
12+
class ColumnBindingHandler(val properties: MutableList<KProperty1<*, *>>) : InvocationHandler {
13+
14+
override fun invoke(proxy: Any, method: Method, args: Array<out Any>?): Any? {
15+
when (method.declaringClass.kotlin) {
16+
Any::class, Entity::class -> {
17+
throw UnsupportedOperationException("Unsupported method: $method")
18+
}
19+
else -> {
20+
val (prop, isGetter) = method.kotlinProperty ?: throw UnsupportedOperationException("Unsupported method: $method")
21+
if (!prop.isAbstract) {
22+
throw UnsupportedOperationException("Cannot bind a column to a non-abstract property: $prop")
23+
}
24+
if (!isGetter) {
25+
throw UnsupportedOperationException("Cannot modify a property while we are binding a column to it, property: $prop")
26+
}
27+
28+
properties += prop
29+
30+
val returnType = prop.returnType.classifier as KClass<*>
31+
return when {
32+
returnType.isSubclassOf(Entity::class) -> createProxy(returnType, properties)
33+
returnType.java.isPrimitive -> returnType.defaultValue
34+
else -> null
35+
}
36+
}
37+
}
38+
}
39+
40+
companion object {
41+
42+
fun createProxy(entityClass: KClass<*>, properties: MutableList<KProperty1<*, *>>): Entity<*> {
43+
val classLoader = Thread.currentThread().contextClassLoader
44+
val handler = ColumnBindingHandler(properties)
45+
return Proxy.newProxyInstance(classLoader, arrayOf(entityClass.java), handler) as Entity<*>
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)