fix some tinkerpop logic and add attribute test

This commit is contained in:
2025-04-20 21:20:29 +03:00
parent 8c3b5a2d2b
commit 20dfb48a10
5 changed files with 89 additions and 12 deletions

View File

@@ -26,6 +26,7 @@ public interface ConnectionAttribute : Attribute<NodeConnection>
public interface StateNode : AttributeContainer {
public val id: NodeId
public val type: NodeType

View File

@@ -3,9 +3,11 @@ package center.sciprog.workflow.state
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal
import org.apache.tinkerpop.gremlin.structure.Edge
import org.apache.tinkerpop.gremlin.structure.Element
import org.apache.tinkerpop.gremlin.structure.Vertex
import space.kscience.attributes.Attribute
import space.kscience.attributes.Attributes
import space.kscience.attributes.UnsafeAPI
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__ as TinkerPop
public interface TinkerAttributeAccessor<T> {
/**
@@ -53,7 +55,7 @@ public class SimpleTinkerAttributeAccessor<T>(
override fun Element.readAttribute(): T = this.value<T>(key)
override fun <E : Element> GraphTraversal<*, E>.readAttribute(): GraphTraversal<*, T?> = values<T>(key)
override fun <E : Element> GraphTraversal<*, E>.readAttribute(): GraphTraversal<*, T?> = valueOrNull(key)
override fun <E : Element> GraphTraversal<*, E>.writeAttribute(
attribute: Attribute<T>,
@@ -87,7 +89,7 @@ public interface TinkerConnectionAttributeAccessor<T : NodeConnection> : TinkerA
override fun <E : Element> GraphTraversal<*, E>.writeAttributeFrom(
attributes: Attributes
): GraphTraversal<*, E> = writeAttribute(attribute,attributes[attribute])
): GraphTraversal<*, E> = writeAttribute(attribute, attributes[attribute])
}
public class SimpleTinkerConnectionAttributeAccessor(
@@ -159,3 +161,9 @@ public class TinkerAttributes(
public companion object
}
public fun <E, T> GraphTraversal<E, *>.valueOrNull(propertyKey: String): GraphTraversal<E, T?> = choose<T>(
TinkerPop.has<Vertex>(propertyKey),
TinkerPop.values<Vertex, T>(propertyKey),
TinkerPop.constant(null)
)

View File

@@ -0,0 +1,41 @@
package center.sciprog.workflow.state
import space.kscience.attributes.Attribute
public interface TinkerRegistry {
public fun attributePipeByLabel(label: String): TinkerAttributeAccessor<*>
public fun <T> attributePipeByAttribute(attribute: Attribute<T>): TinkerAttributeAccessor<T>
}
private class SimpleTinkerRegistry(val accessors: Set<TinkerAttributeAccessor<*>>) : TinkerRegistry {
override fun attributePipeByLabel(label: String): TinkerAttributeAccessor<*> = accessors.single { it.key == label }
@Suppress("UNCHECKED_CAST")
override fun <T> attributePipeByAttribute(attribute: Attribute<T>): TinkerAttributeAccessor<T> = accessors.single {
it.attribute == attribute
} as TinkerAttributeAccessor<T>
}
/**
* Constructs a TinkerRegistry with the provided set of attribute accessors.
*
* @param accessors A set of TinkerAttributeAccessor objects that define the mapping
* between graph elements and their corresponding attributes.
* @return A TinkerRegistry instance that maps attributes to their corresponding keys or labels.
*/
public fun TinkerRegistry(
accessors: Set<TinkerAttributeAccessor<*>>
): TinkerRegistry = SimpleTinkerRegistry(accessors)
public fun <T> MutableSet<TinkerAttributeAccessor<*>>.attribute(
key: String,
attribute: Attribute<T>
) {
add(SimpleTinkerAttributeAccessor(key, attribute))
}
public fun TinkerRegistry(
registryBuilder: MutableSet<TinkerAttributeAccessor<*>>.() -> Unit
): TinkerRegistry = TinkerRegistry(buildSet(registryBuilder))

View File

@@ -14,18 +14,12 @@ import space.kscience.attributes.Attributes
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
public interface TinkerRegistry {
public fun attributePipeByLabel(label: String): TinkerAttributeAccessor<*>
public fun <T> attributePipeByAttribute(attribute: Attribute<T>): TinkerAttributeAccessor<T>
}
public class TinkerNode(
private val vertex: Vertex,
private val registry: TinkerRegistry
) : StateNode {
public val id: NodeId get() = vertex.id().toString()
override val id: NodeId get() = vertex.id().toString()
override val type: NodeType get() = vertex.label()
@@ -36,7 +30,7 @@ public class TinkerStateGraph(
private val ts: GraphTraversalSource,
public val registry: TinkerRegistry,
override val clock: Clock = Clock.System,
) : MutableStateGraph {
) : MutableStateGraph, AutoCloseable by ts.graph {
private val sharedEventFlow = MutableSharedFlow<GraphHistoryEvent>()
@@ -97,7 +91,7 @@ public class TinkerStateGraph(
value: T,
time: Instant
): Unit = with(registry.attributePipeByAttribute(attribute)) {
val oldValue = ts.V(nodeId)
val oldValue: T? = ts.V(nodeId)
.readAttribute()
.choose<T>(
P.neq(value),

View File

@@ -1,4 +1,37 @@
package center.sciprog.workflow.state
class AttributesTest {
import kotlinx.coroutines.test.runTest
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory
import space.kscience.attributes.Attribute
import kotlin.test.Test
import kotlin.test.assertEquals
internal class AttributesTest {
object AttributeA : Attribute<Double>
object AttributeB : Attribute<String>
@Test
fun tinkerAttributesWriteRead() = runTest {
val graph = TinkerFactory.createModern()
val registry = TinkerRegistry {
attribute("a", AttributeA)
attribute("b", AttributeB)
}
TinkerStateGraph(graph.traversal(), registry).use { state ->
val node = state.createNode("test")
state.setAttribute(node.id, AttributeA, 1.0)
assertEquals(1.0, node.attributes[AttributeA])
state.removeAttribute(node.id, AttributeA)
assertEquals(null, node.attributes[AttributeA])
}
}
}