Replace missing query by null in NameToken
This commit is contained in:
parent
c3d4836a11
commit
4fde6c4a48
@ -21,7 +21,7 @@ class MetaSerializerTest {
|
|||||||
fun testMetaSerialization() {
|
fun testMetaSerialization() {
|
||||||
val string = JSON_PRETTY.stringify(MetaSerializer, meta)
|
val string = JSON_PRETTY.stringify(MetaSerializer, meta)
|
||||||
val restored = JSON_PLAIN.parse(MetaSerializer, string)
|
val restored = JSON_PLAIN.parse(MetaSerializer, string)
|
||||||
assertEquals(restored, meta)
|
assertEquals(meta, restored)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -29,7 +29,7 @@ class MetaSerializerTest {
|
|||||||
val bytes = Cbor.dump(MetaSerializer, meta)
|
val bytes = Cbor.dump(MetaSerializer, meta)
|
||||||
println(bytes.contentToString())
|
println(bytes.contentToString())
|
||||||
val restored = Cbor.load(MetaSerializer, bytes)
|
val restored = Cbor.load(MetaSerializer, bytes)
|
||||||
assertEquals(restored, meta)
|
assertEquals(meta, restored)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -37,7 +37,7 @@ class MetaSerializerTest {
|
|||||||
val name = "a.b.c".toName()
|
val name = "a.b.c".toName()
|
||||||
val string = JSON_PRETTY.stringify(Name.serializer(), name)
|
val string = JSON_PRETTY.stringify(Name.serializer(), name)
|
||||||
val restored = JSON_PLAIN.parse(Name.serializer(), string)
|
val restored = JSON_PLAIN.parse(Name.serializer(), string)
|
||||||
assertEquals(restored, name)
|
assertEquals(name, restored)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -26,7 +26,7 @@ interface Configurable : Described, MutableItemProvider {
|
|||||||
fun getDefaultItem(name: Name): MetaItem<*>? = null
|
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 {
|
fun validateItem(name: Name, item: MetaItem<*>?): Boolean {
|
||||||
val descriptor = descriptor?.get(name)
|
val descriptor = descriptor?.get(name)
|
||||||
|
@ -8,7 +8,7 @@ import kotlin.properties.ReadOnlyProperty
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
/* Meta delegates */
|
/* Meta delegates */
|
||||||
|
//TODO to be replaced in 1.4 by interfaces
|
||||||
open class ItemDelegate(
|
open class ItemDelegate(
|
||||||
open val owner: ItemProvider,
|
open val owner: ItemProvider,
|
||||||
val key: Name? = null,
|
val key: Name? = null,
|
||||||
|
@ -52,7 +52,7 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
|
|||||||
fun addElement(key: String) {
|
fun addElement(key: String) {
|
||||||
val itemDescriptor = descriptor?.items?.get(key)
|
val itemDescriptor = descriptor?.items?.get(key)
|
||||||
val jsonKey = key.toJsonKey(itemDescriptor)
|
val jsonKey = key.toJsonKey(itemDescriptor)
|
||||||
val items: Map<String, MetaItem<*>> = getIndexed(key)
|
val items: Map<String?, MetaItem<*>> = getIndexed(key)
|
||||||
when (items.size) {
|
when (items.size) {
|
||||||
0 -> {
|
0 -> {
|
||||||
//do nothing
|
//do nothing
|
||||||
@ -94,7 +94,11 @@ fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
|
|||||||
true -> True
|
true -> True
|
||||||
false -> False
|
false -> False
|
||||||
is Number -> NumberValue(body as Number)
|
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)
|
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
|
* 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) } })
|
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(
|
fun <T> MutableItemProvider.item(
|
||||||
default: T? = null,
|
default: T? = null,
|
||||||
key: Name? = null,
|
key: Name? = null,
|
||||||
@ -85,20 +86,6 @@ fun <T> MutableItemProvider.item(
|
|||||||
fun Configurable.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
fun Configurable.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
|
||||||
item(key).convert(MetaConverter.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*/
|
/* Number delegates*/
|
||||||
|
|
||||||
fun MutableItemProvider.int(key: Name? = null): ReadWriteProperty<Any?, Int?> =
|
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?) {
|
fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
|
||||||
require(!name.isEmpty()) { "Name could not be empty for append operation" }
|
require(!name.isEmpty()) { "Name could not be empty for append operation" }
|
||||||
val newIndex = name.last()!!.index
|
val newIndex = name.last()!!.index
|
||||||
if (newIndex.isNotEmpty()) {
|
if (newIndex != null) {
|
||||||
set(name, value)
|
set(name, value)
|
||||||
} else {
|
} else {
|
||||||
val index = (getIndexed(name).keys.mapNotNull { it.toIntOrNull() }.max() ?: -1) + 1
|
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],
|
* 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.
|
* 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) {
|
val root = when (name.length) {
|
||||||
0 -> error("Can't use empty name for 'getIndexed'")
|
0 -> error("Can't use empty name for 'getIndexed'")
|
||||||
1 -> this
|
1 -> this
|
||||||
else -> this[name.cutLast()].node
|
else -> this[name.cutLast()].node ?: return emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
val (body, index) = name.last()!!
|
val (body, index) = name.last()!!
|
||||||
val regex = index.toRegex()
|
return if (index == null) {
|
||||||
|
root.items.filter { it.key.body == body }.mapKeys { it.key.index }
|
||||||
return root?.items
|
} else {
|
||||||
?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) }
|
val regex = index.toRegex()
|
||||||
?.mapKeys { it.key.index }
|
root.items
|
||||||
?: emptyMap()
|
.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.
|
* 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*
|
* A name token could have appendix in square brackets called *index*
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class NameToken(val body: String, val index: String = "") {
|
data class NameToken(val body: String, val index: String? = null) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (body.isEmpty()) error("Syntax error: Name token body is empty")
|
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()
|
body.escape()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasIndex() = index.isNotEmpty()
|
fun hasIndex() = index != null
|
||||||
|
|
||||||
@Serializer(NameToken::class)
|
@Serializer(NameToken::class)
|
||||||
companion object : KSerializer<NameToken> {
|
companion object : KSerializer<NameToken> {
|
||||||
@ -150,7 +150,8 @@ fun String.toName(): Name {
|
|||||||
}
|
}
|
||||||
else -> when (it) {
|
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()
|
bodyBuilder = StringBuilder()
|
||||||
queryBuilder = 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())
|
return Name(tokens.toList())
|
||||||
}
|
}
|
||||||
@ -206,7 +208,7 @@ fun Name.withIndex(index: String): Name {
|
|||||||
/**
|
/**
|
||||||
* Fast [String]-based accessor for item map
|
* 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> Map<Name, T>.get(name: String) = get(name.toName())
|
||||||
operator fun <T> MutableMap<Name, T>.set(name: String, value: T) = set(name.toName(), value)
|
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
|
@ExperimentalIoApi
|
||||||
fun TextRows.Companion.readEnvelope(envelope: Envelope): TextRows {
|
fun TextRows.Companion.readEnvelope(envelope: Envelope): TextRows {
|
||||||
val header = envelope.meta.getIndexed("column")
|
val header = envelope.meta.getIndexed("column")
|
||||||
.entries.sortedBy { it.key.toInt() }
|
.entries.sortedBy { it.key?.toInt() }
|
||||||
.map { (_, item) ->
|
.map { (_, item) ->
|
||||||
SimpleColumnHeader(item.node["name"].string!!, Value::class, item.node["meta"].node ?: Meta.EMPTY)
|
SimpleColumnHeader(item.node["name"].string!!, Value::class, item.node["meta"].node ?: Meta.EMPTY)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user