Replace missing query by null in NameToken
This commit is contained in:
parent
c3d4836a11
commit
4fde6c4a48
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,7 +178,7 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
|
||||
|
||||
override val items: Map<NameToken, MetaItem<JsonMeta>> 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
|
||||
*/
|
||||
|
@ -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?> =
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user