All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lspace.structure.Nodes.scala Maven / Gradle / Ivy

package lspace.structure

import lspace.Label
import monix.eval.Task
import monix.reactive.Observable

abstract class Nodes(val graph: Graph) extends RApi[Node] {
  import graph._

  def apply(): Observable[Node] = nodeStore.all()
  def count(): Task[Long]       = nodeStore.count()

  def hasId(id: Long): Task[Option[Node]] = nodeStore.hasId(id)
  def cached = new {
    def hasId(id: Long): Option[Node] =
      nodeStore.cached.hasId(id)
    def dereferenceValue(t: Any): Any = t
  }
  def hasId(id: List[Long]): Observable[Node] = nodeStore.hasId(id)
  override def hasIri(iris: List[String]): Observable[Node] = {
    //    println(s"get nodes $iris")
    val validIris = iris.distinct.filter(_.nonEmpty)
    if (validIris.nonEmpty)
      Observable.fromIterable(validIris).flatMap { iri =>
        nodeStore
          .hasIri(iri)
          .asInstanceOf[Observable[Node]]
      } else Observable[Node]()
  }

  def create(ontology: Ontology*): Task[Node] = {
    for {
      id <- idProvider.next
      node = newNode(id)
      u <- Task.gatherUnordered(ontology.map(node.addLabel))
    } yield node
  }

  def upsert(iri: String, ontologies: Ontology*): Task[Node] = {
    for {
      node <- upsert(iri, Set[String]())
      u    <- Task.gatherUnordered(ontologies.toList map node.addLabel)
    } yield node
  }

  /**
    *
    * @param iri an iri which should all resolve to the same resource as param uris
    * @param iris a set of iri's which should all resolve to the same resource
    * @return all vertices which identify by the uri's, expected to return (in time) only a single vertex due to eventual consistency
    */
  def upsert(iri: String, iris: Set[String]): Task[Node] = {
    hasIri(iri :: iris.toList).toListL
      .flatMap {
        case Nil =>
          for {
            node <- create()
            iriEdge <- if (iri.nonEmpty) node.addOut(Label.P.typed.iriUrlString, iri)
            else if (iris.headOption.exists(_.nonEmpty))
              node.addOut(Label.P.typed.iriUrlString, iris.head)
            else Task.unit
          } yield {
            node
          }
        case List(node) => Task.now(node)
        case nodes =>
          mergeNodes(nodes.toSet)
      }
      .flatMap { node =>
        node.out(lspace.Label.P.`@id`, lspace.Label.P.`@ids`)
        val newIris = ((iris + iri) diff node.iris).toList.filter(_.nonEmpty)
        for {
          iriEdges <- Task.sequence(newIris.map(node.addOut(Label.P.`@ids`, _)))
        } yield node
      }
  }

  def upsert(node: Node): Task[Node] = {
    if (node.graph != thisgraph) { //
      for {
        edges <- node.g.outE().withGraph(node.graph).toListF
        newNode <- if (node.iri.nonEmpty) upsert(node.iri)
        else {
          for {
            newNode <- create()
            u       <- Task.gather(node.labels.map(newNode.addLabel))
            v       <- addMeta(node, newNode)
          } yield newNode
        }
      } yield newNode
    } else {
      Task.now(node)
    }
  }

  /**
    * adds a node to the graph including all edges and (meta) edges on edges as long as edges have edges
    * @param node
    * @return
    */
  def post(node: Node): Task[Node] = node match {
    case node: _Node => //match on GNode does also accept _Node instances from other Graphs???? Why?
      Task.now(node)
    case _ =>
      for {
        newNode <- if (node.iri.nonEmpty) upsert(node.iri, node.iris) else create()
        u       <- Task.gather(node.labels.map(node.addLabel))
        v       <- addMeta(node, newNode)
      } yield node
  }

  final def delete(node: Node): Task[Unit] = node match {
    case node: _Node => deleteNode(node.asInstanceOf[_Node])
    case _           => Task.unit //LOG???
  }

  final def +(label: Ontology): Task[Node] = create(label)

  /**
    * adds a node by reference (iri(s))
    * @param node
    * @return
    */
  final def +(node: Node): Task[Node] = upsert(node)

  /**
    * deletes a node
    * @param node
    */
  final def -(node: Node): Task[Unit] = delete(node)

  /**
    * adds a node by every detail
    * @param node
    * @return
    */
  final def ++(node: Node): Task[Node] = post(node)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy