Pure Kotlin SDK

Hello guys, I saw you have reveal recently ParseSwift, great job done there! I was inspired to start a pure Kotlin SDK following the ParseSwift techniques because you guys are more into the core and how everything is structured, queries building etc. The documentation is not quite full on how to build all kind of queries so the JS SDK is a good friend there.

Unfortunately I’m pretty out of free time and decide to share with you my initial work in order to push it a little bit to a some working state. If there’s somebody interested giving feedback or even help me with the Kotlin SDK is more than welcome!

Current state is there’s basic auth, parse object and some queries. It uses coroutines and Kotlin Serialization for the ParseObject. I cannot decide what to do with the storage, but my idea is to provide some kind of interface/adapter and one or more implementations. As the same way of the ParseSwift I introduced encrypted storage for the user, installation and more later on…

Best regards,
Asen

3 Likes

From skimming it, looks like a great start! I don’t know much about Kotlin, so I won’t be much help with coding directly. As far of where to start and what to work on next, I can assist there with the hurdles I’ve seen so far with Parse-Swift.

The documentation has been updated recently, most of the basics are there and can help you in some areas. With respect to queries, the JS SDK can only do a couple more things (aggregate, distinct) that ParseSwift cannot. Of course, the JS SDK is more battle tested. All of these functions can be used as QueryConstraints. With respect to overall functionality, the the JS and Objc-SDK definitely win there as there is a lot of heavy lifting that occurs on the SDK side that will take time to implement.

One thing I didn’t see in your SDK is CI (I may not know where to look), but if you don’t have them, I strongly encourage adding them next as you may end up having to rewrite a lot of code due to bugs. Also, this will help other contributors to program better when adding to the SDK, along with ensuring they don’t break code you know already works.

1 Like

Thanks for the quick response!

Indeed, my idea is to setup CI as soon as possible once I finish the initial architecture let say and implement the basics. I’m wondering what approach you are taking for the local storage and working queries offline. I believe this is big pain for the Android SDK and I’m trying to find a good alternative or to address this in the Kotlin SDK.

I’m pretty sure you have discussed the pain points of the Parse mobile SDKs. Can you share how you address them in the Swift SDK.

Can you help me understanding how complex queries are build as a JSON for the request. I’m referring ‘or’, ‘nor’, ‘and’ etc.
Is there somewhere a good explanation how the JSON structure of complex queries are build?
Can we nest them? And all info around building them will help.

Thanks!

Indeed, my idea is to setup CI as soon as possible once I finish the initial architecture let say and implement the basics. I’m wondering what approach you are taking for the local storage and working queries offline. I believe this is big pain for the Android SDK and I’m trying to find a good alternative or to address this in the Kotlin SDK.

The short answer from me is I’ve been avoiding local storage. Mainly because (this is my opinion) you have to have a way to sync data that isn’t dependent on a wall clock. Personally, when I need local storage with Parse, I usually add my own local storage (e.g. CoreData) and add a “Clock” Class to Parse that uses vector clocks to keep data in sync. Basically, I rely on 3rd party to sync local data with the Parse Server. We have had a couple of discussions about local storage:

One of the other committers, pranjalsatija, is interested in implementing a protocol based local storage, but I’m not sure of his status on that part. I do believe a protocol can work and allows developers to choose their favorite option to sync data. I’ve focused my energy on other areas as I didn’t feel local storage is as important as the others (plus I personally don’t need the Parse SDK for local storage). When it comes to ParseUser.current and ParseInstallation.current, local storage is very important. So Parse-Swift stores this in the keychain and only persists updates to either if it can save them to the parse-server, otherwise the changes wait in memory (or are discarded). You can see details about this in the first link above (the updates in the PR weren’t merged because it would have broken this).

Can you help me understanding how complex queries are build as a JSON for the request. I’m referring ‘or’, ‘nor’, ‘and’ etc.
Is there somewhere a good explanation how the JSON structure of complex queries are build?
Can we nest them? And all info around building them will help.

I didn’t find a good explanation, I took a lot of time to look through the Obj-c SDK code to figure these out (some were in the SDK before I started working on it and just needed some tweaking). The best way to figure this out (IMO) is to create the test cases and test on a local parse-server (I do this with swift playgrounds). The test cases to look at are:

You should be able to rely on the expected JSON generation in the test file above as I pulled them from reliable SDKs and tested almost all of them on a local parse-server

1 Like

cbaker6 thanks again for the guidelines.

Now I have tested all the queries and introduce some GitHub Actions building KDoc which currently is incomplete.

I have another question now, but lets describe the case first: I’m sticking with pointers, relations and mostly operations over the ParseObject.

@Serializable
    @ParseClassName("GameScore")
    class GameScore(var score: Int) : ParseClass() {
        lateinit var type: ParsePointer
        val types by ParseRelationDelegate()
        companion object : ParseClassCompanion()
    }

I go for ParsePointer to be a wrapped object where you can check if data is available and fetch if necessary. But for the relation I go for delegated property which unfortunately is not directly serializable . This delegated property is needed to pass the current ParseObject instance and handle add, remove operations over the relation. But we loose the typing and I’m starting to introduce wrapping objects :slightly_frowning_face:

How do you handle this pointers relations and operations in Swift?
I want to keep the types and the ParseObjects as POKOs as possible but it turns out that similar approach like used into the current Android SDK should be better with setter and getters by key.

Parse-Swift doesn’t support Relations yet and I haven’t looked much into how to implement it.

For Pointers in ParseSwift, they can be decoded as their original types since all Pointers contain an objectId and className. The part that was tricky to implement is ensuring child objects are saved before their patients and creating pointers to the children. The iOS and JS SDKs both have a process for doing this, but I took a different since Swift is strongly typed and I couldn’t come up with a way to directly translate either of those implementations, I leveraged the fact that Parse-Swift has a custom JSONEncoder (ParseEncoder). As long the whole ParseObject always conforms to the Encodable protocol it can always be sent to the parse-server. As long as child objects always conform to Objectable they can be turned into Pointers and still represent their respective ParseObject.

  1. Checking/Saving child objects
  2. Checking/replacing child objects with Pointers inside the custom encoder