All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.app.softwork.cloudkitclient.TestStorage.kt Maven / Gradle / Ivy

The newest version!
package app.softwork.cloudkitclient

import app.softwork.cloudkitclient.values.*
import kotlinx.datetime.*
import kotlin.reflect.*
import kotlin.uuid.*

@OptIn(ExperimentalUuidApi::class)
public class TestStorage(
    private val initUser: UserRecord,
    private val assets: MutableMap>,
    private val clock: Clock
) : Storage {

    private val storage: MutableMap> = mutableMapOf()

    init {
        create(initUser, UserRecord)
    }

    public override fun randomChangeTag(): String = Uuid.random().toString().take(8)

    public override fun now(
        userRecordName: String,
        deviceID: String
    ): TimeInformation = TimeInformation(
        timestamp = clock.now(),
        userRecordName = userRecordName,
        deviceID = deviceID
    )

    public override fun > create(
        record: R,
        recordInformation: Record.Information
    ): R {
        val changeTag = randomChangeTag()
        val now = now(initUser.recordName)
        record.recordChangeTag = changeTag
        record.created = now
        record.modified = now
        storage[record.recordName] = record
        return record
    }

    public override fun > get(
        recordName: String,
        recordInformation: Record.Information
    ): R? {
        return storage[recordName]?.let {
            @Suppress("UNCHECKED_CAST")
            it as R
        }
    }

    public override fun > delete(
        record: R,
        recordInformation: Record.Information
    ) {
        val key = record.recordName
        val oldRecord = storage[key]
        requireNotNull(oldRecord)
        require(oldRecord.recordChangeTag == record.recordChangeTag)
        storage.remove(key)
    }

    public override fun > update(
        record: R,
        recordInformation: Record.Information
    ): R {
        val oldRecord = storage[record.recordName]
        requireNotNull(oldRecord)
        require(oldRecord.recordChangeTag == record.recordChangeTag)
        val changeTag = randomChangeTag()
        val now = now(initUser.recordName)
        record.recordChangeTag = changeTag
        record.modified = now
        storage[record.recordName] = record
        return record
    }

    public override fun > upload(
        content: ByteArray,
        recordInformation: Record.Information,
        field: KProperty1,
        recordName: String?
    ): app.softwork.cloudkitclient.types.Asset {
        val download = Uuid.random()
        val asset = app.softwork.cloudkitclient.types.Asset(
            fileChecksum = "",
            size = content.size,
            receipt = "",
            downloadURL = download.toString()
        )
        assets[download] = asset to content

        return asset
    }

    public override fun > query(
        recordInformation: Record.Information,
        filters: List,
        sorts: List
    ): List = storage.values.filter { value ->
        value.recordType == recordInformation.recordType
    }.map {
        @Suppress("UNCHECKED_CAST")
        it as R
    }.filter { record ->
        val properties = recordInformation.fields()
        filters.all { filter ->
            val value = properties.value(record.fields, filter)
            value.check(filter)
        }
    }.let {
        if (sorts.isNotEmpty()) {
            val properties = recordInformation.fields()
            var comparator = compareBy { record ->
                val sort = sorts.first()
                properties.sort(sort, record)
            }

            for (sort in sorts.subList(1, sorts.size)) {
                comparator = if (sort.ascending) {
                    comparator.thenBy { record ->
                        properties.sort(sort, record)
                    }
                } else {
                    comparator.thenByDescending { record ->
                        properties.sort(sort, record)
                    }
                }
            }
            it.sortedWith(comparator)
        } else it
    }

    private fun > List>.sort(
        sort: Sort,
        record: R
    ): Comparable? = single {
        it.name == sort.fieldName
    }.get(record.fields)?.asComparable()

    private fun Value.asComparable(): Comparable {
        return when (this) {
            is Value.Double -> comparable {
                require(it is Value.Double)
                value.compareTo(it.value)
            }

            is Value.String -> comparable {
                require(it is Value.String)
                value.compareTo(it.value)
            }

            is Value.DateTime -> comparable {
                require(it is Value.DateTime)
                value.compareTo(it.value)
            }

            else -> error("Not comparable")
        }
    }

    private fun  T.comparable(comparing: T.(T) -> Int): Comparable = object : Comparable {
        override fun compareTo(other: T): Int = comparing(other)
    }

    private fun  List>.value(
        fields: F,
        filter: Filter
    ): Value {
        val property: KProperty1 = single { prop ->
            prop.name == filter.fieldName
        }
        return property.get(fields) ?: error("property with filterName ${filter.fieldName} was null")
    }

    private fun Value.check(filter: Filter): Boolean {
        val otherValue = filter.fieldValue
        val comparator = filter.comparator
        return when (this) {
            is Value.Asset -> error("Not comparable")
            is Value.Byte -> error("Not comparable")
            is Value.DateTime -> {
                require(otherValue is Value.DateTime)
                when (comparator) {
                    Filter.Comparator.EQUALS -> value == otherValue.value
                    Filter.Comparator.NOT_EQUALS -> value != otherValue.value
                    Filter.Comparator.LESS_THAN -> value < otherValue.value
                    Filter.Comparator.LESS_THAN_OR_EQUALS -> value <= otherValue.value
                    Filter.Comparator.GREATER_THAN -> value > otherValue.value
                    Filter.Comparator.GREATER_THAN_OR_EQUALS -> value >= otherValue.value
                    else -> error("Not supported")
                }
            }

            is Value.Double -> {
                val other = when (otherValue) {
                    is Value.Double -> otherValue.value
                    is Value.Number -> otherValue.value.toDouble()
                    else -> error("Not comparable")
                }
                when (comparator) {
                    Filter.Comparator.EQUALS -> value == other
                    Filter.Comparator.NOT_EQUALS -> value != other
                    Filter.Comparator.LESS_THAN -> value < other
                    Filter.Comparator.LESS_THAN_OR_EQUALS -> value <= other
                    Filter.Comparator.GREATER_THAN -> value > other
                    Filter.Comparator.GREATER_THAN_OR_EQUALS -> value >= other
                    else -> error("Not supported")
                }
            }

            is Value.Number -> {
                val other = when (otherValue) {
                    is Value.Double -> otherValue.value.toLong()
                    is Value.Number -> otherValue.value
                    else -> error("Not comparable")
                }
                when (comparator) {
                    Filter.Comparator.EQUALS -> value == other
                    Filter.Comparator.NOT_EQUALS -> value != other
                    Filter.Comparator.LESS_THAN -> value < other
                    Filter.Comparator.LESS_THAN_OR_EQUALS -> value <= other
                    Filter.Comparator.GREATER_THAN -> value > other
                    Filter.Comparator.GREATER_THAN_OR_EQUALS -> value >= other
                    else -> error("Not supported")
                }
            }

            is Value.Location -> TODO()
            is Value.Reference<*, *> -> {
                require(otherValue is Value.Reference<*, *>)
                when (comparator) {
                    Filter.Comparator.EQUALS -> value.recordName == otherValue.value.recordName
                    Filter.Comparator.NOT_EQUALS -> value.recordName != otherValue.value.recordName
                    Filter.Comparator.LESS_THAN -> TODO()
                    Filter.Comparator.LESS_THAN_OR_EQUALS -> TODO()
                    Filter.Comparator.GREATER_THAN -> TODO()
                    Filter.Comparator.GREATER_THAN_OR_EQUALS -> TODO()
                    Filter.Comparator.NEAR -> TODO()
                    Filter.Comparator.CONTAINS_ALL_TOKENS -> TODO()
                    Filter.Comparator.CONTAINS_ANY_TOKENS -> TODO()
                    Filter.Comparator.IN -> TODO()
                    Filter.Comparator.NOT_IN -> TODO()
                    Filter.Comparator.LIST_CONTAINS -> TODO()
                    Filter.Comparator.NOT_LIST_CONTAINS -> TODO()
                    Filter.Comparator.NOT_LIST_CONTAINS_ANY -> TODO()
                    Filter.Comparator.BEGINS_WITH -> TODO()
                    Filter.Comparator.NOT_BEGINS_WITH -> TODO()
                    Filter.Comparator.LIST_MEMBER_BEGINS_WITH -> TODO()
                    Filter.Comparator.NOT_LIST_MEMBER_BEGINS_WITH -> TODO()
                    Filter.Comparator.LIST_CONTAINS_ALL -> TODO()
                    Filter.Comparator.NOT_LIST_CONTAINS_ALL -> TODO()
                }
            }

            is Value.String -> {
                val other = when (otherValue) {
                    is Value.String -> otherValue.value
                    is Value.Double -> otherValue.value.toString()
                    is Value.Number -> otherValue.value.toString()
                    else -> error("Not comparable")
                }
                when (comparator) {
                    Filter.Comparator.EQUALS -> value == other
                    Filter.Comparator.NOT_EQUALS -> value != other
                    Filter.Comparator.LESS_THAN -> value < other
                    Filter.Comparator.LESS_THAN_OR_EQUALS -> value <= other
                    Filter.Comparator.GREATER_THAN -> value > other
                    Filter.Comparator.GREATER_THAN_OR_EQUALS -> value >= other
                    Filter.Comparator.CONTAINS_ALL_TOKENS -> value.split(" ").all { it == other }
                    Filter.Comparator.CONTAINS_ANY_TOKENS -> value.split(" ").any { it == other }
                    else -> error("Not supported")
                }
            }

            is Value.List -> {
                when (otherValue) {
                    is Value.String -> otherValue.value
                    is Value.Double -> otherValue.value.toString()
                    is Value.Number -> otherValue.value.toString()
                    else -> error("Not comparable")
                }
                when (comparator) {
                    // Filter.Comparator.LIST_CONTAINS -> value.contains(other)
                    Filter.Comparator.NOT_LIST_CONTAINS -> TODO()
                    Filter.Comparator.NOT_LIST_CONTAINS_ANY -> TODO()
                    Filter.Comparator.BEGINS_WITH -> TODO()
                    Filter.Comparator.NOT_BEGINS_WITH -> TODO()
                    Filter.Comparator.LIST_MEMBER_BEGINS_WITH -> TODO()
                    Filter.Comparator.NOT_LIST_MEMBER_BEGINS_WITH -> TODO()
                    Filter.Comparator.LIST_CONTAINS_ALL -> TODO()
                    Filter.Comparator.NOT_LIST_CONTAINS_ALL -> TODO()
                    else -> error("Not supported")
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy