diff --git a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt index dc8e5016..ef301710 100644 --- a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt +++ b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt @@ -21,7 +21,7 @@ class MetaSerializerTest { fun testMetaSerialization() { val string = JSON_PRETTY.stringify(MetaSerializer, meta) val restored = JSON_PLAIN.parse(MetaSerializer, string) - assertEquals(restored, meta) + assertEquals(meta, restored) } @Test @@ -29,7 +29,7 @@ class MetaSerializerTest { val bytes = Cbor.dump(MetaSerializer, meta) println(bytes.contentToString()) val restored = Cbor.load(MetaSerializer, bytes) - assertEquals(restored, meta) + assertEquals(meta, restored) } @Test @@ -37,7 +37,7 @@ class MetaSerializerTest { val name = "a.b.c".toName() val string = JSON_PRETTY.stringify(Name.serializer(), name) val restored = JSON_PLAIN.parse(Name.serializer(), string) - assertEquals(restored, name) + assertEquals(name, restored) } @Test diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt index 0f880110..a984b897 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt @@ -26,7 +26,7 @@ interface Configurable : Described, MutableItemProvider { fun getDefaultItem(name: Name): MetaItem<*>? = null /** - * Check if property with given [name] could be assigned to [value] + * Check if property with given [name] could be assigned to [item] */ fun validateItem(name: Name, item: MetaItem<*>?): Boolean { val descriptor = descriptor?.get(name) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemDelegate.kt index b710735e..cffedd82 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemDelegate.kt @@ -8,7 +8,7 @@ import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty /* Meta delegates */ - +//TODO to be replaced in 1.4 by interfaces open class ItemDelegate( open val owner: ItemProvider, val key: Name? = null, diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt index 221b040d..debe3080 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt @@ -52,7 +52,7 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String fun addElement(key: String) { val itemDescriptor = descriptor?.items?.get(key) val jsonKey = key.toJsonKey(itemDescriptor) - val items: Map> = getIndexed(key) + val items: Map> = getIndexed(key) when (items.size) { 0 -> { //do nothing @@ -94,7 +94,11 @@ fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value { true -> True false -> False is Number -> NumberValue(body as Number) - else -> StringValue(content) + else -> if (isString) { + StringValue(content) + } else { + content.parseValue() + } } } } @@ -174,7 +178,7 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M override val items: Map> by lazy(::buildItems) - companion object{ + companion object { /** * A key representing top-level json array of nodes, which could not be directly represented by a meta node */ diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableItemDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableItemDelegate.kt index 3885b809..163408e1 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableItemDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableItemDelegate.kt @@ -71,6 +71,7 @@ inline fun > M.node(key: Name? = null): ReadWriteProp item(key).convert(reader = { it?.let { it.node as M } }, writer = { it?.let { MetaItem.NodeItem(it) } }) +@Deprecated("To be replaced by a converter") fun MutableItemProvider.item( default: T? = null, key: Name? = null, @@ -85,20 +86,6 @@ fun MutableItemProvider.item( fun Configurable.value(key: Name? = null): ReadWriteProperty = item(key).convert(MetaConverter.value) -fun MutableItemProvider.value( - default: T? = null, - key: Name? = null, - writer: (T) -> Value? = { Value.of(it) }, - reader: (Value?) -> T -): ReadWriteProperty = MutableItemDelegate( - this, - key, - default?.let { MetaItem.of(it) } -).convert( - reader = { reader(it.value) }, - writer = { value -> writer(value)?.let { MetaItem.ValueItem(it) } } -) - /* Number delegates*/ fun MutableItemProvider.int(key: Name? = null): ReadWriteProperty = diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt index 03245b00..13965505 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt @@ -160,7 +160,7 @@ operator fun MutableMeta<*>.set(name: String, metas: Iterable): Unit = set fun > M.append(name: Name, value: Any?) { require(!name.isEmpty()) { "Name could not be empty for append operation" } val newIndex = name.last()!!.index - if (newIndex.isNotEmpty()) { + if (newIndex != null) { set(name, value) } else { val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1 diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt index f2f747db..26dc009c 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/metaMatcher.kt @@ -7,23 +7,25 @@ import hep.dataforge.names.toName * Get all items matching given name. The index of the last element, if present is used as a [Regex], * against which indexes of elements are matched. */ -fun Meta.getIndexed(name: Name): Map> { +fun Meta.getIndexed(name: Name): Map> { val root = when (name.length) { 0 -> error("Can't use empty name for 'getIndexed'") 1 -> this - else -> this[name.cutLast()].node + else -> this[name.cutLast()].node ?: return emptyMap() } val (body, index) = name.last()!! - val regex = index.toRegex() - - return root?.items - ?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) } - ?.mapKeys { it.key.index } - ?: emptyMap() + return if (index == null) { + root.items.filter { it.key.body == body }.mapKeys { it.key.index } + } else { + val regex = index.toRegex() + root.items + .filter { it.key.body == body && (regex.matches(it.key.index ?: "")) } + .mapKeys { it.key.index } + } } -fun Meta.getIndexed(name: String): Map> = this@getIndexed.getIndexed(name.toName()) +fun Meta.getIndexed(name: String): Map> = this@getIndexed.getIndexed(name.toName()) /** * Get all items matching given name. diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt index b3f8231a..5ed2ff81 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt @@ -78,7 +78,7 @@ class Name(val tokens: List) { * A name token could have appendix in square brackets called *index* */ @Serializable -data class NameToken(val body: String, val index: String = "") { +data class NameToken(val body: String, val index: String? = null) { init { if (body.isEmpty()) error("Syntax error: Name token body is empty") @@ -96,7 +96,7 @@ data class NameToken(val body: String, val index: String = "") { body.escape() } - fun hasIndex() = index.isNotEmpty() + fun hasIndex() = index != null @Serializer(NameToken::class) companion object : KSerializer { @@ -150,7 +150,8 @@ fun String.toName(): Name { } else -> when (it) { '.' -> { - yield(NameToken(bodyBuilder.toString(), queryBuilder.toString())) + val query = if(queryBuilder.isEmpty()) null else queryBuilder.toString() + yield(NameToken(bodyBuilder.toString(), query)) bodyBuilder = StringBuilder() queryBuilder = StringBuilder() } @@ -163,7 +164,8 @@ fun String.toName(): Name { } } } - yield(NameToken(bodyBuilder.toString(), queryBuilder.toString())) + val query = if(queryBuilder.isEmpty()) null else queryBuilder.toString() + yield(NameToken(bodyBuilder.toString(), query)) } return Name(tokens.toList()) } @@ -206,7 +208,7 @@ fun Name.withIndex(index: String): Name { /** * Fast [String]-based accessor for item map */ -operator fun Map.get(body: String, query: String = ""): T? = get(NameToken(body, query)) +operator fun Map.get(body: String, query: String? = null): T? = get(NameToken(body, query)) operator fun Map.get(name: String) = get(name.toName()) operator fun MutableMap.set(name: String, value: T) = set(name.toName(), value) diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/io/textTableEnvelope.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/io/textTableEnvelope.kt index e634346c..10c9b3fc 100644 --- a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/io/textTableEnvelope.kt +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/io/textTableEnvelope.kt @@ -34,7 +34,7 @@ suspend fun Table.wrap(): Envelope = Envelope { @ExperimentalIoApi fun TextRows.Companion.readEnvelope(envelope: Envelope): TextRows { val header = envelope.meta.getIndexed("column") - .entries.sortedBy { it.key.toInt() } + .entries.sortedBy { it.key?.toInt() } .map { (_, item) -> SimpleColumnHeader(item.node["name"].string!!, Value::class, item.node["meta"].node ?: Meta.EMPTY) }