Skip to content

Commit

Permalink
Allow to store JsonNumber in Record (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
BoD authored Sep 11, 2024
1 parent f0e64bc commit f43915d
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Record(
* - Map (for custom scalars)
* - null
*/
val fields: Map<String, Any?>,
val fields: Map<String, RecordValue>,
val mutationId: Uuid? = null,
) : Map<String, Any?> by fields {

Expand Down Expand Up @@ -126,3 +126,15 @@ fun Record.receivedDate(field: String) = metadata[field]?.get(ApolloCacheHeaders

@ApolloInternal
fun Record.expirationDate(field: String) = metadata[field]?.get(ApolloCacheHeaders.EXPIRATION_DATE) as? Long


/**
* A typealias for a type-unsafe Kotlin representation of a Record value. This typealias is
* mainly for internal documentation purposes and low-level manipulations and should
* generally be avoided in application code.
*
* [RecordValue] can be any of:
* - [com.apollographql.apollo.api.json.ApolloJsonElement]
* - [CacheKey]
*/
typealias RecordValue = Any?
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.apollographql.cache.normalized.api.internal

import com.apollographql.apollo.annotations.ApolloInternal
import com.apollographql.apollo.api.json.JsonNumber
import com.apollographql.cache.normalized.api.CacheKey
import com.apollographql.cache.normalized.api.Record
import okio.Buffer
Expand Down Expand Up @@ -94,7 +95,12 @@ object BlobRecordSerializer {

is Double -> {
buffer.writeByte(DOUBLE)
buffer.writeString(value.toString())
buffer.writeLong(value.toBits())
}

is JsonNumber -> {
buffer.writeByte(JSON_NUMBER)
buffer.writeString(value.value)
}

is Boolean -> {
Expand Down Expand Up @@ -139,7 +145,8 @@ object BlobRecordSerializer {
STRING -> readString()
INT -> readInt()
LONG -> readLong()
DOUBLE -> readString().toDouble()
DOUBLE -> Double.fromBits(readLong())
JSON_NUMBER -> JsonNumber(readString())
BOOLEAN -> readByte() > 0
CACHE_KEY -> {
CacheKey(readString())
Expand Down Expand Up @@ -169,8 +176,9 @@ object BlobRecordSerializer {
private const val LONG = 2
private const val BOOLEAN = 3
private const val DOUBLE = 4
private const val LIST = 5
private const val MAP = 6
private const val CACHE_KEY = 7
private const val NULL = 8
private const val JSON_NUMBER = 5
private const val LIST = 6
private const val MAP = 7
private const val CACHE_KEY = 8
private const val NULL = 9
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.apollographql.apollo.api.CompiledSelection
import com.apollographql.apollo.api.CompiledType
import com.apollographql.apollo.api.Executable
import com.apollographql.apollo.api.isComposite
import com.apollographql.apollo.api.json.ApolloJsonElement
import com.apollographql.cache.normalized.api.CacheKey
import com.apollographql.cache.normalized.api.CacheKeyGenerator
import com.apollographql.cache.normalized.api.CacheKeyGeneratorContext
Expand All @@ -34,7 +35,11 @@ internal class Normalizer(
) {
private val records = mutableMapOf<String, Record>()

fun normalize(map: Map<String, Any?>, selections: List<CompiledSelection>, parentType: CompiledNamedType): Map<String, Record> {
fun normalize(
map: Map<String, ApolloJsonElement>,
selections: List<CompiledSelection>,
parentType: CompiledNamedType,
): Map<String, Record> {
buildRecord(map, rootKey, selections, parentType)

return records
Expand Down Expand Up @@ -114,7 +119,7 @@ internal class Normalizer(
* @return the CacheKey if this object has a CacheKey or the new Map if the object was embedded
*/
private fun buildRecord(
obj: Map<String, Any?>,
obj: Map<String, ApolloJsonElement>,
key: String,
selections: List<CompiledSelection>,
parentType: CompiledNamedType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.apollographql.cache.normalized.api.internal

import com.apollographql.apollo.api.json.JsonNumber
import com.apollographql.cache.normalized.api.CacheKey
import com.apollographql.cache.normalized.api.Record
import com.apollographql.cache.normalized.api.RecordValue
import okio.internal.commonAsUtf8ToByteArray
import kotlin.jvm.JvmStatic

internal object RecordWeigher {
Expand Down Expand Up @@ -30,28 +33,30 @@ internal object RecordWeigher {
return size
}

private fun weighField(field: Any?): Int {
private fun weighField(field: RecordValue): Int {
return when (field) {
null -> SIZE_OF_NULL
is String -> field.length
is String -> field.commonAsUtf8ToByteArray().size
is Boolean -> SIZE_OF_BOOLEAN
is Int -> SIZE_OF_INT
is Long -> SIZE_OF_LONG // Might happen with LongDataAdapter
is Double -> SIZE_OF_DOUBLE
is List<*> -> {
SIZE_OF_ARRAY_OVERHEAD + field.sumOf { weighField(it) }
}

is CacheKey -> {
SIZE_OF_CACHE_KEY_OVERHEAD + field.key.length
}
is JsonNumber -> field.value.commonAsUtf8ToByteArray().size + SIZE_OF_LONG
/**
* Custom scalars with a json object representation are stored directly in the record
*/
is Map<*, *> -> {
SIZE_OF_MAP_OVERHEAD + field.keys.sumOf { weighField(it) } + field.values.sumOf { weighField(it) }
}

is List<*> -> {
SIZE_OF_ARRAY_OVERHEAD + field.sumOf { weighField(it) }
}

is CacheKey -> {
SIZE_OF_CACHE_KEY_OVERHEAD + field.key.commonAsUtf8ToByteArray().size
}

else -> error("Unknown field type in Record: '$field'")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.apollographql.cache.normalized

import com.apollographql.apollo.api.json.JsonNumber
import com.apollographql.cache.normalized.api.CacheKey
import com.apollographql.cache.normalized.api.Record
import kotlin.test.Test
Expand All @@ -13,6 +14,7 @@ class RecordWeigherTest {
val expectedLongValue = Long.MAX_VALUE
val expectedStringValue = "StringValue"
val expectedBooleanValue = true
val expectedNumberValue = JsonNumber("10")
val expectedCacheKey = CacheKey("foo")
val expectedCacheKeyList = listOf(CacheKey("bar"), CacheKey("baz"))
val expectedScalarList = listOf("scalarOne", "scalarTwo")
Expand All @@ -23,13 +25,14 @@ class RecordWeigherTest {
"string" to expectedStringValue,
"boolean" to expectedBooleanValue,
"long" to expectedLongValue,
"number" to expectedNumberValue,
"cacheReference" to expectedCacheKey,
"scalarList" to expectedScalarList,
"referenceList" to expectedCacheKeyList,
)
)

assertTrue(record.sizeInBytes <= 248)
assertTrue(record.sizeInBytes >= 242) // JS takes less space, maybe for strings?
assertTrue(record.sizeInBytes <= 284)
assertTrue(record.sizeInBytes >= 258) // JS takes less space, maybe for strings?
}
}

0 comments on commit f43915d

Please sign in to comment.