Skip to content

Commit

Permalink
Merge pull request #2 from sergeypdev/master
Browse files Browse the repository at this point in the history
Add InstantPocketbase type with custom Serializable
  • Loading branch information
agrevster authored Jun 17, 2024
2 parents 9c19a2c + b8a346b commit 1ba226a
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package io.github.agrevster.pocketbaseKotlin

import io.github.agrevster.pocketbaseKotlin.models.utils.BaseModel
import io.github.agrevster.pocketbaseKotlin.models.utils.parsePocketbase
import io.github.agrevster.pocketbaseKotlin.models.utils.toStringPocketbase
import io.ktor.client.call.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.datetime.Instant
import kotlinx.datetime.toInstant
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -91,9 +92,9 @@ public fun Boolean?.toJsonPrimitiveOrNull(): JsonPrimitive = JsonPrimitive(this)
public fun Number.toJsonPrimitive(): JsonPrimitive = JsonPrimitive(this)

public fun Instant?.toJsonPrimitive(): JsonPrimitive? =
if (this.toString() != "null") JsonPrimitive(this.toString().replace("T", " ")) else null
if (this != null) JsonPrimitive(this.toStringPocketbase()) else null

public fun JsonPrimitive.toInstant(): Instant = this.toString().replace(" ", "T").removeSurrounding("\"").toInstant()
public fun JsonPrimitive.toInstant(): Instant = Instant.parsePocketbase(this.toString().removeSurrounding("\""))

public fun JsonPrimitive.toNumber(): Double = this.toString().toDouble()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,26 @@
package io.github.agrevster.pocketbaseKotlin.models.utils

import io.github.agrevster.pocketbaseKotlin.PocketKtInternal
import kotlinx.datetime.Instant
import kotlinx.datetime.toInstant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

@Serializable
/**
* The base class used for all [Pocketbase](https://pocketbase.io) models used
*
* @property [id] The unique ID of the model
* @property [initialCreated] the raw created field from the model formatted in the GO timestamp format.
* Use [created] to access the type of [Instant]
* @property [initialUpdated] the raw updated field from the model formatted in the GO timestamp format.
* Use [updated] to access the type of [Instant]
* @property [created] the created field from the model.
* @property [updated] the updated field from the model.
*
*/
public open class BaseModel(public open val id: String? = null) {

public val created: InstantPocketbase? = null

@SerialName("created")
@PocketKtInternal
public val initialCreated: String? = null

@SerialName("updated")
@PocketKtInternal
public val initialUpdated: String? = null

@OptIn(PocketKtInternal::class)
@Transient
public val created: Instant? = initialCreated?.replace(" ", "T")?.toInstant()

@OptIn(PocketKtInternal::class)
@Transient
public val updated: Instant? = initialUpdated?.replace(" ", "T")?.toInstant()

public val updated: InstantPocketbase? = null

@OptIn(PocketKtInternal::class)
override fun toString(): String {
return "BaseModel(id=$id, created=$initialCreated, updated=$initialUpdated)"
return "BaseModel(id=$id, created=$created, updated=$updated)"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.github.agrevster.pocketbaseKotlin.models.utils

import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

public typealias InstantPocketbase = @Serializable(InstantPocketbaseSerializer::class) Instant

internal fun Int.padded(length: Int): String {
return this.toString().padStart(length, '0')
}

public fun Instant.toStringPocketbase(): String {
val dt = this.toLocalDateTime(TimeZone.UTC)

return "${dt.year}-${dt.monthNumber.padded(2)}-${dt.dayOfMonth.padded(2)} ${dt.hour.padded(2)}:${dt.minute.padded(2)}:${dt.second.padded(2)}.${dt.nanosecond / 1_000_000}Z"
}

public fun Instant.Companion.parsePocketbase(string: String): InstantPocketbase {
return parse(string.replace(' ', 'T'))
}

public object InstantPocketbaseSerializer : KSerializer<Instant> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING)

override fun deserialize(decoder: Decoder): Instant {
val dateStr = decoder.decodeString()
return Instant.parsePocketbase(dateStr)
}

override fun serialize(encoder: Encoder, value: Instant) {
encoder.encodeString(value.toStringPocketbase())
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,17 @@ import io.github.agrevster.pocketbaseKotlin.dsl.query.Filter
import io.github.agrevster.pocketbaseKotlin.dsl.query.ShowFields
import io.github.agrevster.pocketbaseKotlin.dsl.query.SortFields
import io.github.agrevster.pocketbaseKotlin.models.LogRequest
import io.github.agrevster.pocketbaseKotlin.models.utils.InstantPocketbase
import io.github.agrevster.pocketbaseKotlin.models.utils.ListResult
import io.github.agrevster.pocketbaseKotlin.services.utils.BaseService
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.http.*
import kotlinx.datetime.Instant
import kotlinx.datetime.toInstant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

public class LogService(client: io.github.agrevster.pocketbaseKotlin.PocketbaseClient) : BaseService(client) {
@Serializable
public data class HourlyStats(val total: Int, @SerialName("date") val initialDate: String) {
@Transient
val date: Instant = initialDate.replace(" ", "T").toInstant()
}
public data class HourlyStats(val total: Int, val date: InstantPocketbase)

/**
* Returns a paginated request logs list.
Expand Down
35 changes: 35 additions & 0 deletions src/commonTest/kotlin/models/utils/InstantPocketbase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package models.utils

import TestingUtils
import io.github.agrevster.pocketbaseKotlin.models.utils.InstantPocketbase
import io.github.agrevster.pocketbaseKotlin.models.utils.InstantPocketbaseSerializer
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.contextual
import kotlin.test.Test
import kotlin.test.assertEquals

class InstantPocketbaseTest : TestingUtils() {
@Test
fun testSerializeDeserialize(): Unit {
@Serializable
data class TestSerializable(val instant: InstantPocketbase)

val original = TestSerializable(Instant.parse("2023-10-24T01:02:03.123Z"))

val encoded = Json.encodeToString(original)
assertEquals(
expected = "{\"instant\":\"2023-10-24 01:02:03.123Z\"}",
actual = encoded,
)
val decoded: TestSerializable = Json.decodeFromString(encoded)
assertEquals(
expected = original,
actual = decoded,
)
}
}

0 comments on commit 1ba226a

Please sign in to comment.