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

molecule.datalog.datomic.transaction.Insert_datomic.scala Maven / Gradle / Ivy

There is a newer version: 0.12.1
Show newest version
package molecule.datalog.datomic.transaction

import java.time._
import java.util.{ArrayList => jArrayList, List => jList}
import molecule.base.ast._
import molecule.boilerplate.ast.Model._
import molecule.boilerplate.util.MoleculeLogging
import molecule.core.transaction.ops.InsertOps
import molecule.core.transaction.{InsertResolvers_, ResolveInsert}
import molecule.core.util.ModelUtils

trait Insert_datomic
  extends DatomicBase_JVM
    with InsertOps
    with DatomicDataType_JVM
    with ModelUtils
    with MoleculeLogging { self: ResolveInsert with InsertResolvers_ =>

  def getStmts(
    nsMap: Map[String, MetaNs],
    elements: List[Element],
    tpls: Seq[Product],
    idIndex: Int = 0,
    debug: Boolean = true
  ): Data = {
    initTxBase(elements, idIndex)
    val row2stmts = getResolver(nsMap, elements)
    tpls.foreach { tpl =>
      e = newId
      e0 = e
      // populate stmts
      row2stmts(tpl)
    }

    // Remove orphan ref ids
    val stmts1 = if (unusedRefIds.isEmpty) stmts else {
      val stmts1 = new jArrayList[jList[AnyRef]](stmts.size())
      stmts.forEach { stmt =>
        if (!unusedRefIds.contains(stmt.get(3))) {
          stmts1.add(stmt)
        }
      }
      stmts1
    }

    if (debug) {
      val insertStrs = "INSERT:" +: elements :+ "" :+ stmts1.toArray().mkString("\n")
      logger.debug(insertStrs.mkString("\n").trim)
    }

    val lastIndex = stmts1.size - 1
    val stmts2    = if (lastIndex != -1
      && stmts1.get(lastIndex).get(3).toString.startsWith("#db/id")) {
      // remove orphan ref datom - can we include this check it in the algorithm above?
      stmts1.remove(lastIndex)
      stmts1
    } else stmts1

    stmts2
  }

  override protected def addOne[T](
    ns: String,
    attr: String,
    tplIndex: Int,
    transformValue: T => Any,
    handleValue: T => Any,
    exts: List[String] = Nil
  ): Product => Unit = {
    val a = kw(ns, attr)
    backRefs = backRefs + (ns -> e)
    (tpl: Product) =>
      unusedRefIds -= e
      usedRefIds += e
      appendStmt(add, e, a,
        transformValue(tpl.productElement(tplIndex).asInstanceOf[T]).asInstanceOf[AnyRef]
      )
  }

  override protected def addOneOpt[T](
    ns: String,
    attr: String,
    tplIndex: Int,
    transformValue: T => Any,
    handleValue: T => Any,
    exts: List[String] = Nil
  ): Product => Unit = {
    val a = kw(ns, attr)
    backRefs = backRefs + (ns -> e)
    (tpl: Product) =>
      tpl.productElement(tplIndex) match {
        case Some(value) =>
          unusedRefIds -= e
          usedRefIds += e
          appendStmt(add, e, a, transformValue(value.asInstanceOf[T]).asInstanceOf[AnyRef])
        case None        =>
          if (!usedRefIds.contains(e)) {
            unusedRefIds += e
          }
          () // no statement to insert
      }
  }

  override protected def addSet[T](
    ns: String,
    attr: String,
    set2array: Set[Any] => Array[AnyRef],
    refNs: Option[String],
    tplIndex: Int,
    transformValue: T => Any,
    exts: List[String] = Nil,
    value2json: (StringBuffer, T) => StringBuffer
  ): Product => Unit = {
    val a = kw(ns, attr)
    backRefs = backRefs + (ns -> e)
    (tpl: Product) =>
      tpl.productElement(tplIndex).asInstanceOf[Set[_]] match {
        case set if set.isEmpty =>
        case set                =>
          unusedRefIds -= e
          usedRefIds += e
          set.foreach { value =>
            appendStmt(add, e, a, transformValue(value.asInstanceOf[T]).asInstanceOf[AnyRef])
          }
      }
  }

  override protected def addSetOpt[T](
    ns: String,
    attr: String,
    set2array: Set[Any] => Array[AnyRef],
    refNs: Option[String],
    tplIndex: Int,
    transformValue: T => Any,
    exts: List[String] = Nil,
    value2json: (StringBuffer, T) => StringBuffer
  ): Product => Unit = {
    val a = kw(ns, attr)
    backRefs = backRefs + (ns -> e)
    (tpl: Product) =>
      tpl.productElement(tplIndex) match {
        case Some(set: Set[_]) =>
          unusedRefIds -= e
          usedRefIds += e
          set.foreach(value =>
            appendStmt(add, e, a, transformValue(value.asInstanceOf[T]).asInstanceOf[AnyRef])
          )
        case None              =>
          if (!usedRefIds.contains(e)) {
            unusedRefIds += e
          }
          () // no statement to insert
      }
  }

  override protected def addRef(
    ns: String,
    refAttr: String,
    refNs: String,
    card: Card,
    owner: Boolean
  ): Product => Unit = {
    val a = kw(ns, refAttr)
    (_: Product) =>
      backRefs = backRefs + (ns -> e)
      unusedRefIds -= e
      usedRefIds += e
      stmt = stmtList
      stmt.add(add)
      stmt.add(e)
      stmt.add(a)
      e = newId
      unusedRefIds += e
      stmt.add(e)
      stmts.add(stmt)
  }

  override protected def addBackRef(backRefNs: String): Product => Unit = {
    (_: Product) =>
      e = backRefs(backRefNs)
  }

  override protected def addNested(
    nsMap: Map[String, MetaNs],
    tplIndex: Int,
    ns: String,
    refAttr: String,
    refNs: String,
    owner: Boolean,
    nestedElements: List[Element]
  ): Product => Unit = {
    // Recursively resolve nested data
    val nested2stmts = getResolver(nsMap, nestedElements)
    val lastIsSet    = nestedElements.last.isInstanceOf[AttrSet]
    countValueAttrs(nestedElements) match {
      case 1 => // Nested arity-1 values
        (tpl: Product) => {
          val values       = tpl.productElement(tplIndex).asInstanceOf[Seq[Any]]
          val nestedBaseId = e
          values.foreach { value =>
            e = nestedBaseId
            val nestedTpl = Tuple1(value)
            addRef(ns, refAttr, refNs, CardOne, owner)(nestedTpl)
            unusedRefIds -= e
            e0 = e
            nested2stmts(nestedTpl)
          }
        }

      // Exclude tuples with empty last Set
      // (to avoid orphan relationships)
      case _ if lastIsSet =>
        val lastTplIndex = nestedElements.collect { case _: Attr => 1 }.sum - 1
        (tpl: Product) => {
          val multiple     = tpl.productArity > 1
          val nestedTpls   = tpl.productElement(tplIndex).asInstanceOf[Seq[Product]]
          val nestedBaseId = e
          nestedTpls.foreach { nestedTpl =>
            def process(): Unit = {
              e = nestedBaseId
              addRef(ns, refAttr, refNs, CardOne, owner)(nestedTpl)
              e0 = e
              nested2stmts(nestedTpl)
            }
            nestedTpl.productElement(lastTplIndex) match {
              case set: Set[_] if set.nonEmpty || multiple => process()
              case _: Option[_]                            => process()
              case _                                       => ()
            }
          }
        }

      case _ =>
        (tpl: Product) => {
          val nestedTpls   = tpl.productElement(tplIndex).asInstanceOf[Seq[Product]]
          val nestedBaseId = e
          nestedTpls.foreach { nestedTpl =>
            e = nestedBaseId
            addRef(ns, refAttr, refNs, CardOne, owner)(nestedTpl)
            unusedRefIds -= e
            e0 = e
            nested2stmts(nestedTpl)
          }
        }
    }
  }

  override protected lazy val transformID             = (v: Any) => v.asInstanceOf[String].toLong
  override protected lazy val transformString         = identity
  override protected lazy val transformInt            = (v: Any) => v.asInstanceOf[Int].toLong
  override protected lazy val transformLong           = identity
  override protected lazy val transformFloat          = identity
  override protected lazy val transformDouble         = identity
  override protected lazy val transformBoolean        = boolean2java
  override protected lazy val transformBigInt         = bigInt2java
  override protected lazy val transformBigDecimal     = bigDec2java
  override protected lazy val transformDate           = identity
  override protected lazy val transformDuration       = (v: Any) => v.asInstanceOf[Duration].toString
  override protected lazy val transformInstant        = (v: Any) => v.asInstanceOf[Instant].toString
  override protected lazy val transformLocalDate      = (v: Any) => v.asInstanceOf[LocalDate].toString
  override protected lazy val transformLocalTime      = (v: Any) => v.asInstanceOf[LocalTime].toString
  override protected lazy val transformLocalDateTime  = (v: Any) => v.asInstanceOf[LocalDateTime].toString
  override protected lazy val transformOffsetTime     = (v: Any) => v.asInstanceOf[OffsetTime].toString
  override protected lazy val transformOffsetDateTime = (v: Any) => v.asInstanceOf[OffsetDateTime].toString
  override protected lazy val transformZonedDateTime  = (v: Any) => v.asInstanceOf[ZonedDateTime].toString
  override protected lazy val transformUUID           = identity
  override protected lazy val transformURI            = identity
  override protected lazy val transformByte           = byte2java
  override protected lazy val transformShort          = short2java
  override protected lazy val transformChar           = char2java
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy