Skip to content

Commit 6d9bd89

Browse files
authored
Fix Reference filter (#56)
* Fix Reference filter * Fix Reference filter Co-authored-by: hfhbd <[email protected]>
1 parent 9a8cef1 commit 6d9bd89

File tree

7 files changed

+160
-40
lines changed

7 files changed

+160
-40
lines changed

cloudkitclient-core/api/cloudkitclient-core.api

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,13 +1374,14 @@ public final class app/softwork/cloudkitclient/values/Value$Location$Companion {
13741374

13751375
public final class app/softwork/cloudkitclient/values/Value$Reference : app/softwork/cloudkitclient/values/Value {
13761376
public static final field Companion Lapp/softwork/cloudkitclient/values/Value$Reference$Companion;
1377-
public synthetic fun <init> (ILapp/softwork/cloudkitclient/types/Reference;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
1378-
public fun <init> (Lapp/softwork/cloudkitclient/types/Reference;)V
1379-
public final fun component1 ()Lapp/softwork/cloudkitclient/types/Reference;
1380-
public final fun copy (Lapp/softwork/cloudkitclient/types/Reference;)Lapp/softwork/cloudkitclient/values/Value$Reference;
1381-
public static synthetic fun copy$default (Lapp/softwork/cloudkitclient/values/Value$Reference;Lapp/softwork/cloudkitclient/types/Reference;ILjava/lang/Object;)Lapp/softwork/cloudkitclient/values/Value$Reference;
1377+
public synthetic fun <init> (ILapp/softwork/cloudkitclient/values/Value$Reference$Ref;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
1378+
public fun <init> (Lapp/softwork/cloudkitclient/Record;)V
1379+
public fun <init> (Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;)V
1380+
public final fun component1 ()Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;
1381+
public final fun copy (Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;)Lapp/softwork/cloudkitclient/values/Value$Reference;
1382+
public static synthetic fun copy$default (Lapp/softwork/cloudkitclient/values/Value$Reference;Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;ILjava/lang/Object;)Lapp/softwork/cloudkitclient/values/Value$Reference;
13821383
public fun equals (Ljava/lang/Object;)Z
1383-
public final fun getValue ()Lapp/softwork/cloudkitclient/types/Reference;
1384+
public final fun getValue ()Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;
13841385
public fun hashCode ()I
13851386
public fun toString ()Ljava/lang/String;
13861387
}
@@ -1401,6 +1402,35 @@ public final class app/softwork/cloudkitclient/values/Value$Reference$Companion
14011402
public final fun serializer (Lkotlinx/serialization/KSerializer;Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
14021403
}
14031404

1405+
public final class app/softwork/cloudkitclient/values/Value$Reference$Ref {
1406+
public static final field Companion Lapp/softwork/cloudkitclient/values/Value$Reference$Ref$Companion;
1407+
public synthetic fun <init> (ILjava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
1408+
public fun <init> (Ljava/lang/String;)V
1409+
public final fun component1 ()Ljava/lang/String;
1410+
public final fun copy (Ljava/lang/String;)Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;
1411+
public static synthetic fun copy$default (Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;Ljava/lang/String;ILjava/lang/Object;)Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;
1412+
public fun equals (Ljava/lang/Object;)Z
1413+
public final fun getRecordName ()Ljava/lang/String;
1414+
public fun hashCode ()I
1415+
public fun toString ()Ljava/lang/String;
1416+
}
1417+
1418+
public final class app/softwork/cloudkitclient/values/Value$Reference$Ref$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
1419+
public final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
1420+
public synthetic fun <init> (Lkotlinx/serialization/KSerializer;Lkotlinx/serialization/KSerializer;)V
1421+
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
1422+
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;
1423+
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
1424+
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
1425+
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lapp/softwork/cloudkitclient/values/Value$Reference$Ref;)V
1426+
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
1427+
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
1428+
}
1429+
1430+
public final class app/softwork/cloudkitclient/values/Value$Reference$Ref$Companion {
1431+
public final fun serializer (Lkotlinx/serialization/KSerializer;Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
1432+
}
1433+
14041434
public final class app/softwork/cloudkitclient/values/Value$String : app/softwork/cloudkitclient/values/Value {
14051435
public static final field Companion Lapp/softwork/cloudkitclient/values/Value$String$Companion;
14061436
public synthetic fun <init> (ILjava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V

cloudkitclient-core/src/commonMain/kotlin/app/softwork/cloudkitclient/CKClient.kt

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ public class CKClient(
5858
sortBy = Sort.Builder<F>().apply(sort).build()
5959
)
6060
)
61-
}.toRegularResponse(recordInformation)
61+
}.toResponse(recordInformation) {
62+
when(this) {
63+
is Holder.Success -> response.records
64+
is Holder.Failure -> throw error
65+
}
66+
}
6267

6368
public override suspend fun <F : Fields, R : Record<F>> create(
6469
record: R,
@@ -73,15 +78,20 @@ public class CKClient(
7378
)
7479
) {
7580
OperationsRequest(operations = listOf(Create(record = record)))
76-
}.toRegularResponse(recordInformation).first()
81+
}.toResponse(recordInformation) {
82+
when(this) {
83+
is Holder.Success -> response.records.single()
84+
is Holder.Failure -> throw error
85+
}
86+
}
7787

7888
override suspend fun <F : Fields, R : Record<F>> read(
7989
recordName: String,
8090
recordInformation: Information<F, R>,
8191
zoneID: ZoneID
8292
): R? = request("/records/lookup", Request.RecordLookup.serializer()) {
8393
Request.RecordLookup(listOf(Request.RecordLookup.RecordName(recordName = recordName)), zoneID = zoneID)
84-
}.handleError(recordInformation).run {
94+
}.toResponse(recordInformation) {
8595
when (this) {
8696
is Holder.Success -> response.records.single()
8797
is Holder.Failure -> {
@@ -103,7 +113,12 @@ public class CKClient(
103113
)
104114
) {
105115
OperationsRequest(operations = listOf(Update(record = record)))
106-
}.toRegularResponse(recordInformation).first()
116+
}.toResponse(recordInformation) {
117+
when(this) {
118+
is Holder.Success -> response.records.single()
119+
is Holder.Failure -> throw error
120+
}
121+
}
107122

108123
public override suspend fun <F : Fields, R : Record<F>> delete(
109124
record: R,
@@ -157,49 +172,42 @@ public class CKClient(
157172
resource: String,
158173
serializer: KSerializer<In>,
159174
requestBody: () -> In
160-
): String = client.request {
175+
): String = client.request<String> {
161176
method = HttpMethod.Post
162177

163178
val subPath = "/database/1/$container/$environment/$name$resource"
164179

165180
val date = Clock.System.now().toString().dropLastWhile { it != '.' }.replace('.', 'Z')
166181
val body = json.encodeToString(serializer, requestBody())
167-
182+
println("body: $body")
168183
val bodySignature = sha256(body).encodeBase64
169184
val signature = ecdsa(privateECPrime256v1Key, "$date:$bodySignature:$subPath")
170185

171186
url.takeFrom(subPath)
172187
header("X-Apple-CloudKit-Request-ISO8601Date", date)
173188
header("X-Apple-CloudKit-Request-SignatureV1", signature)
174189
this.body = body
175-
}
176-
177-
private fun <F : Fields, R : Record<F>> String.toRegularResponse(recordInformation: Information<F, R>): List<R> {
178-
val response = json.decodeFromString(
179-
Response.serializer(
180-
recordInformation.fieldsSerializer(),
181-
recordInformation.serializer()
182-
), this
183-
)
184-
return response.records
190+
}.also {
191+
println("response: $it")
185192
}
186193

187194

188-
private fun <F : Fields, R : Record<F>> String.handleError(
189-
recordInformation: Information<F, R>
190-
): Holder<F, R> =
195+
private fun <F : Fields, R : Record<F>, T> String.toResponse(
196+
recordInformation: Information<F, R>,
197+
handler: Holder<F, R>.() -> T
198+
): T =
191199
try {
192200
val response = json.decodeFromString(
193201
Response.serializer(
194202
recordInformation.fieldsSerializer(),
195203
recordInformation.serializer()
196204
), this
197205
)
198-
Holder.Success(response)
206+
Holder.Success(response).handler()
199207
} catch (e: SerializationException) {
200208
try {
201209
val error = json.decodeFromString(Holder.Failure.ReadError.serializer(), this)
202-
Holder.Failure(error.records.first())
210+
Holder.Failure<F, R>(error.records.first()).handler()
203211
} catch (error: SerializationException) {
204212
throw error
205213
}

cloudkitclient-core/src/commonMain/kotlin/app/softwork/cloudkitclient/Filter.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package app.softwork.cloudkitclient
22

3-
import app.softwork.cloudkitclient.types.*
43
import app.softwork.cloudkitclient.values.*
54
import kotlinx.serialization.*
65
import kotlin.reflect.*
@@ -56,8 +55,8 @@ public data class Filter(
5655
public infix fun <TF : Record.Fields, TR : Record<TF>> KProperty1<F, Value.Reference<TF, TR>>.eq(value: TR) {
5756
filters.add(
5857
Filter(
59-
fieldName = name, comparator = Comparator.EQUALS, fieldValue = Value.Reference<TF, TR>(
60-
Reference(value.recordName, action = Reference.Action.None)
58+
fieldName = name, comparator = Comparator.EQUALS, fieldValue = Value.Reference(
59+
Value.Reference.Ref<TF, TR>(value.recordName)
6160
)
6261
)
6362
)

cloudkitclient-core/src/commonMain/kotlin/app/softwork/cloudkitclient/values/Value.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@ public sealed class Value {
4949
@Serializable
5050
@SerialName("REFERENCE")
5151
public data class Reference<F : Record.Fields, TargetRecord : Record<F>>(
52-
val value: app.softwork.cloudkitclient.types.Reference<F, TargetRecord>
53-
) : Value()
52+
val value: Ref<F, TargetRecord>
53+
) : Value() {
54+
public constructor(record: TargetRecord): this(Ref(recordName = record.recordName))
55+
56+
@Serializable
57+
public data class Ref<F : Record.Fields, TargetRecord : Record<F>>(val recordName: kotlin.String)
58+
}
5459

5560

5661
@Serializable
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package app.softwork.cloudkitclient
2+
3+
import app.softwork.cloudkitclient.Record.*
4+
import app.softwork.cloudkitclient.values.*
5+
import kotlinx.serialization.*
6+
import kotlin.reflect.*
7+
8+
data class TodoList(val name: String, val changeTag: String? = null)
9+
10+
@Serializable
11+
data class TodoListRecord(
12+
override val recordName: String,
13+
override val fields: Fields = TodoListRecord.Fields(),
14+
15+
override var created: TimeInformation? = null,
16+
override var modified: TimeInformation? = null,
17+
override var deleted: Boolean? = null,
18+
override val pluginFields: PluginFields = PluginFields(),
19+
override var recordChangeTag: String? = null,
20+
override val zoneID: ZoneID = ZoneID.default
21+
) : Record<TodoListRecord.Fields> {
22+
override val recordType: String = Companion.recordType
23+
24+
fun toDomain() = TodoList(
25+
name = recordName,
26+
changeTag = recordChangeTag
27+
)
28+
29+
constructor(list: TodoList) : this(
30+
list.name,
31+
fields = Fields(),
32+
recordChangeTag = list.changeTag
33+
)
34+
35+
companion object : Information<Fields, TodoListRecord> {
36+
override val recordType: String = "TodoList"
37+
38+
override fun fields(): List<KProperty1<Fields, Value?>> = listOf()
39+
40+
override fun fieldsSerializer() = Fields.serializer()
41+
}
42+
43+
@Serializable
44+
class Fields: Record.Fields
45+
}

integrationTest/src/commonMain/kotlin/app/softwork/cloudkitclient/TodoRecord.kt

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import app.softwork.cloudkitclient.values.*
66
import kotlinx.serialization.*
77
import kotlinx.uuid.*
88

9-
data class Todo(val id: UUID, val subtitle: String, val asset: Asset?, val changeTag: String? = null)
9+
data class Todo(
10+
val id: UUID,
11+
val subtitle: String, val asset: Asset?,
12+
val listID: String,
13+
val changeTag: String? = null
14+
)
1015

1116
@Serializable
1217
data class TodoRecord(
@@ -26,23 +31,31 @@ data class TodoRecord(
2631
id = recordName.toUUID(),
2732
subtitle = fields.subtitle.value,
2833
asset = fields.asset?.value,
29-
changeTag = recordChangeTag
34+
changeTag = recordChangeTag,
35+
listID = fields.list.value.recordName
3036
)
3137

3238
constructor(todo: Todo) : this(
3339
todo.id.toString(),
34-
fields = Fields(subtitle = Value.String(todo.subtitle), asset = todo.asset?.let { Value.Asset(it) }),
40+
fields = Fields(
41+
subtitle = Value.String(todo.subtitle),
42+
asset = todo.asset?.let { Value.Asset(it) },
43+
list = Value.Reference(value = Value.Reference.Ref(todo.listID))),
3544
recordChangeTag = todo.changeTag
3645
)
3746

3847
companion object : Information<Fields, TodoRecord> {
3948
override val recordType: String = "Todo"
4049

41-
override fun fields() = listOf(Fields::subtitle)
50+
override fun fields() = listOf(Fields::subtitle, Fields::asset, Fields::list)
4251

4352
override fun fieldsSerializer() = Fields.serializer()
4453
}
4554

4655
@Serializable
47-
data class Fields(val subtitle: Value.String, val asset: Value.Asset? = null) : Record.Fields
56+
data class Fields(
57+
val subtitle: Value.String,
58+
val asset: Value.Asset? = null,
59+
val list: Value.Reference<TodoListRecord.Fields, TodoListRecord>
60+
) : Record.Fields
4861
}

integrationTest/src/commonTest/kotlin/app/softwork/cloudkitclient/TodoClientTest.kt

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,61 @@ class TodoClientTest {
1111

1212
@Test
1313
fun createTodo() = runTest(clients) { client ->
14+
val list = client.publicDB.create(TodoListRecord("MainList"), TodoListRecord)
15+
1416
val todo = client.publicDB.create(
1517
TodoRecord(
1618
UUID().toString(),
17-
TodoRecord.Fields(subtitle = Value.String("Hello World"))
19+
TodoRecord.Fields(subtitle = Value.String("Hello World"), list = Value.Reference(list))
1820
), TodoRecord
1921
)
2022
delay(timeMillis = client.timeout)
2123
val todos = client.publicDB.query(TodoRecord)
2224
assertEquals(1, todos.size)
25+
26+
val todosOfList = client.publicDB.query(TodoRecord) {
27+
TodoRecord.Fields::list eq list
28+
}
29+
assertEquals(1, todosOfList.size)
30+
2331
client.publicDB.delete(todo, TodoRecord)
2432
delay(timeMillis = client.timeout)
2533
val todos2 = client.publicDB.query(TodoRecord)
2634
assertEquals(0, todos2.size)
35+
client.publicDB.delete(list, TodoListRecord)
2736
}
2837

2938
@Test
3039
fun createTodoDomain() = runTest(clients) { client ->
31-
val todo = client.publicDB.create(TodoRecord(Todo(UUID(), "Hello World", asset = null)), TodoRecord).toDomain()
40+
val list = client.publicDB.create(TodoListRecord("MainList"), TodoListRecord)
41+
val todo = client.publicDB.create(
42+
TodoRecord(Todo(UUID(), "Hello World", asset = null, listID = "MainList")),
43+
TodoRecord
44+
).toDomain()
3245
delay(timeMillis = client.timeout)
3346
val todos = client.publicDB.query(TodoRecord).map { it.toDomain() }
3447
assertEquals(1, todos.size)
3548
client.publicDB.delete(TodoRecord(todo), TodoRecord)
3649
delay(timeMillis = client.timeout)
3750
val todos2 = client.publicDB.query(TodoRecord).map { it.toDomain() }
3851
assertEquals(0, todos2.size)
52+
client.publicDB.delete(list, TodoListRecord)
3953
}
4054

4155
@Test
4256
fun uploadAndDownloadAsset() = runTest(clients) { client ->
4357
val assetContent = "Hello Asset".encodeToByteArray()
4458
val asset = client.publicDB.upload(assetContent, TodoRecord, TodoRecord.Fields::asset, recordName = "TestAsset")
4559

60+
val list = client.publicDB.create(TodoListRecord("MainList"), TodoListRecord)
61+
4662
client.publicDB.create(
4763
TodoRecord(
4864
UUID().toString(),
49-
TodoRecord.Fields(subtitle = Value.String("Hello World"))
65+
TodoRecord.Fields(
66+
subtitle = Value.String("Hello World"),
67+
list = Value.Reference(Value.Reference.Ref("MainList"))
68+
)
5069
), TodoRecord
5170
)
5271
delay(timeMillis = client.timeout)
@@ -60,6 +79,7 @@ class TodoClientTest {
6079
client.publicDB.update(updatedTodo.copy(fields = todo.fields.copy(asset = null)), TodoRecord)
6180
assertNull(todoDeletedAsset.fields.asset)
6281
client.publicDB.delete(todoDeletedAsset, TodoRecord)
82+
client.publicDB.delete(list, TodoListRecord)
6383
}
6484

6585
@Test

0 commit comments

Comments
 (0)