Replace missing query by null in NameToken

This commit is contained in:
Alexander Nozik 2020-07-26 15:00:03 +03:00
parent c3d4836a11
commit 4fde6c4a48
9 changed files with 33 additions and 38 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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<String, MetaItem<*>> = getIndexed(key)
val items: Map<String?, MetaItem<*>> = 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()
}
}
}
}

View File

@ -71,6 +71,7 @@ inline fun <reified M : MutableMeta<M>> 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 <T> MutableItemProvider.item(
default: T? = null,
key: Name? = null,
@ -85,20 +86,6 @@ fun <T> MutableItemProvider.item(
fun Configurable.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
item(key).convert(MetaConverter.value)
fun <T> MutableItemProvider.value(
default: T? = null,
key: Name? = null,
writer: (T) -> Value? = { Value.of(it) },
reader: (Value?) -> T
): ReadWriteProperty<Any?, T> = 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<Any?, Int?> =

View File

@ -160,7 +160,7 @@ operator fun MutableMeta<*>.set(name: String, metas: Iterable<Meta>): Unit = set
fun <M : MutableMeta<M>> 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

View File

@ -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<String, MetaItem<*>> {
fun Meta.getIndexed(name: Name): Map<String?, MetaItem<*>> {
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()!!
return if (index == null) {
root.items.filter { it.key.body == body }.mapKeys { it.key.index }
} else {
val regex = index.toRegex()
return root?.items
?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) }
?.mapKeys { it.key.index }
?: emptyMap()
root.items
.filter { it.key.body == body && (regex.matches(it.key.index ?: "")) }
.mapKeys { it.key.index }
}
}
fun Meta.getIndexed(name: String): Map<String, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
fun Meta.getIndexed(name: String): Map<String?, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
/**
* Get all items matching given name.

View File

@ -78,7 +78,7 @@ class Name(val tokens: List<NameToken>) {
* 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<NameToken> {
@ -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 <T> Map<NameToken, T>.get(body: String, query: String = ""): T? = get(NameToken(body, query))
operator fun <T> Map<NameToken, T>.get(body: String, query: String? = null): T? = get(NameToken(body, query))
operator fun <T> Map<Name, T>.get(name: String) = get(name.toName())
operator fun <T> MutableMap<Name, T>.set(name: String, value: T) = set(name.toName(), value)

View File

@ -34,7 +34,7 @@ suspend fun Table<Value>.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)
}