Skip to content

Commit 696af29

Browse files
danielsanfrJawnnypoo
authored andcommitted
Feature kotlin delegates (#892)
* Implement generic delegate for attributes Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for boolean Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for double Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for float Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for int Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for long Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for string Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for bytes Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for map Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for list Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for JsonArray Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for JsonObject Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for ParseRelation Signed-off-by: Daniel San <[email protected]> * Implement specialized property delegation for Enum Signed-off-by: Daniel San <[email protected]> * Implement generic delegate for attributes with some checks Signed-off-by: Daniel San <[email protected]> * Small fix on ParseDelegate set property type Signed-off-by: Daniel San <[email protected]> * Add basic documentation to all delegate classes Signed-off-by: Daniel San <[email protected]> * Add property delegation documentation on README.md Signed-off-by: Daniel San <[email protected]> * Update kotlin version Signed-off-by: Daniel San <[email protected]>
1 parent ff97db3 commit 696af29

17 files changed

+484
-1
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
buildscript {
2-
ext.kotlin_version = '1.2.51'
2+
ext.kotlin_version = '1.2.71'
33
repositories {
44
jcenter()
55
google()

ktx/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,44 @@ class Cat : ParseObject() {
3737

3838
```
3939

40+
## Property Delegation
41+
42+
> "There are certain common kinds of properties, that, though we can implement them manually every time we need them, would be very nice to implement once and for all, and put into a library."
43+
44+
The text quoted above is the best explanation anyone could pass us, we use property delegation for the properties of our ParseObject, this prevents us having to write very much boilerplate.
45+
46+
### Without property delegation:
47+
48+
```kotlin
49+
@ParseClassName("Cat")
50+
class Cat : ParseObject() {
51+
52+
companion object {
53+
const val KEY_NAME = "name"
54+
}
55+
56+
var name: String
57+
get = getString(KEY_NAME)
58+
set(value) = putString(KEY_NAME, value)
59+
60+
}
61+
```
62+
63+
### With property delegation:
64+
65+
```kotlin
66+
@ParseClassName("Cat")
67+
class Cat : ParseObject() {
68+
69+
var name: String by stringAttribute() // That's it
70+
71+
}
72+
```
73+
74+
The `stringAttribute` is a property delegate, and we have many other specialized types and also for generic types.
75+
76+
This causes us to not have to write get/set and besides, it removed the get/put boilerplate which is a must to map our classes with the Parse collections.
77+
4078
## Contributing
4179
When contributing to the `ktx` module, please first consider if the extension function you are wanting to add would potentially be better suited in the main `parse` module. If it is something specific to Kotlin users or only useful in a Kotlin project, feel free to make a PR adding it to this module. Otherwise, consider adding the addition to the `parse` module itself, so that it is still usable in Java.
4280

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import kotlin.reflect.KProperty
7+
8+
/**
9+
* A [Boolean] property delegation for [ParseObject].
10+
*/
11+
class BooleanParseDelegate {
12+
13+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): Boolean {
14+
return parseObject.getBoolean(property.name)
15+
}
16+
17+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: Boolean) {
18+
parseObject.put(property.name, value)
19+
}
20+
21+
}
22+
23+
/**
24+
* Returns a [Boolean] property delegate for [ParseObject]s. This uses [ParseObject.getBoolean]
25+
* and [ParseObject.put].
26+
*/
27+
inline fun booleanAttribute() = BooleanParseDelegate()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import com.parse.ktx.putOrIgnore
7+
import kotlin.reflect.KProperty
8+
9+
/**
10+
* A [ByteArray] property delegation for [ParseObject].
11+
*/
12+
class BytesParseDelegate {
13+
14+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): ByteArray? {
15+
return parseObject.getBytes(property.name)
16+
}
17+
18+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: ByteArray?) {
19+
parseObject.putOrIgnore(property.name, value)
20+
}
21+
22+
}
23+
24+
/**
25+
* Returns a [ByteArray] property delegate for [ParseObject]s. This uses [ParseObject.getBytes]
26+
* and [ParseObject.putOrIgnore].
27+
*/
28+
inline fun bytesAttribute() = BytesParseDelegate()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import kotlin.reflect.KProperty
7+
8+
/**
9+
* A [Double] property delegation for [ParseObject].
10+
*/
11+
class DoubleParseDelegate {
12+
13+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): Double {
14+
return parseObject.getDouble(property.name)
15+
}
16+
17+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: Double) {
18+
parseObject.put(property.name, value)
19+
}
20+
21+
}
22+
23+
/**
24+
* Returns a [Double] property delegate for [ParseObject]s. This uses [ParseObject.getDouble]
25+
* and [ParseObject.put].
26+
*/
27+
inline fun doubleAttribute() = DoubleParseDelegate()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@file:Suppress("unused")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import kotlin.reflect.KProperty
7+
8+
/**
9+
* A [Enum] property delegation for [ParseObject].
10+
*
11+
* This implementation save enum's name in lower case on parse-server and when try retrieve it
12+
* convert again to upper case to find correspondent local enum.
13+
*/
14+
class EnumParseDelegate<T : Enum<T>>(private val default: T?, private val enumClass: Class<T>) {
15+
16+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): T {
17+
return try {
18+
java.lang.Enum.valueOf(enumClass, parseObject.getString(property.name)!!.toUpperCase())
19+
} catch (e: Exception) {
20+
default ?: throw e
21+
}
22+
}
23+
24+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, t: T) {
25+
parseObject.put(property.name, t.name.toLowerCase())
26+
}
27+
28+
}
29+
30+
/**
31+
* Returns a [Enum] property delegate for [ParseObject]s. This uses custom implementation for get
32+
* to retrieve a local version of the your enum and [ParseObject.put].
33+
*/
34+
inline fun <reified T : Enum<T>> enumAttribute(default: T? = null) = EnumParseDelegate(default, T::class.java)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import kotlin.reflect.KProperty
7+
8+
/**
9+
* A [Float] property delegation for [ParseObject].
10+
*/
11+
class FloatParseDelegate {
12+
13+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): Float {
14+
return parseObject.getDouble(property.name).toFloat()
15+
}
16+
17+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: Float) {
18+
parseObject.put(property.name, value)
19+
}
20+
21+
}
22+
23+
/**
24+
* Returns a [Float] property delegate for [ParseObject]s. This uses a custom implementation for get
25+
* and [ParseObject.put].
26+
*/
27+
inline fun floatAttribute() = FloatParseDelegate()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import kotlin.reflect.KProperty
7+
8+
/**
9+
* A [Int] property delegation for [ParseObject].
10+
*/
11+
class IntParseDelegate {
12+
13+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): Int {
14+
return parseObject.getInt(property.name)
15+
}
16+
17+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: Int) {
18+
parseObject.put(property.name, value)
19+
}
20+
21+
}
22+
23+
/**
24+
* Returns a [Int] property delegate for [ParseObject]s. This uses [ParseObject.getInt]
25+
* and [ParseObject.put].
26+
*/
27+
inline fun intAttribute() = IntParseDelegate()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import com.parse.ktx.putOrIgnore
7+
import org.json.JSONArray
8+
import kotlin.reflect.KProperty
9+
10+
/**
11+
* A [JSONArray] property delegation for [ParseObject].
12+
*/
13+
class JsonArrayParseDelegate {
14+
15+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): JSONArray? {
16+
return parseObject.getJSONArray(property.name)
17+
}
18+
19+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: JSONArray?) {
20+
parseObject.putOrIgnore(property.name, value)
21+
}
22+
23+
}
24+
25+
/**
26+
* Returns a [JSONArray] property delegate for [ParseObject]s. This uses [ParseObject.getDouble]
27+
* and [ParseObject.putOrIgnore].
28+
*/
29+
inline fun jsonArrayAttribute() = JsonArrayParseDelegate()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@file:Suppress("unused", "NOTHING_TO_INLINE")
2+
3+
package com.parse.ktx.delegates
4+
5+
import com.parse.ParseObject
6+
import com.parse.ktx.putOrIgnore
7+
import org.json.JSONObject
8+
import kotlin.reflect.KProperty
9+
10+
/**
11+
* A [JSONObject] property delegation for [ParseObject].
12+
*/
13+
class JsonObjectParseDelegate {
14+
15+
operator fun getValue(parseObject: ParseObject, property: KProperty<*>): JSONObject? {
16+
return parseObject.getJSONObject(property.name)
17+
}
18+
19+
operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: JSONObject?) {
20+
parseObject.putOrIgnore(property.name, value)
21+
}
22+
23+
}
24+
25+
/**
26+
* Returns a [JSONObject] property delegate for [ParseObject]s. This uses [ParseObject.getJSONObject]
27+
* and [ParseObject.putOrIgnore].
28+
*/
29+
fun jsonObjectAttribute() = JsonObjectParseDelegate()

0 commit comments

Comments
 (0)