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

tech.ytsaurus.spyt.wrapper.cypress.YtCypressUtils.scala Maven / Gradle / Ivy

The newest version!
package tech.ytsaurus.spyt.wrapper.cypress

import org.slf4j.LoggerFactory
import tech.ytsaurus.spyt.wrapper.YtWrapper
import tech.ytsaurus.spyt.wrapper.YtWrapper.RichLogger
import tech.ytsaurus.spyt.wrapper.transaction.YtTransactionUtils
import tech.ytsaurus.client.CompoundClient
import tech.ytsaurus.client.request._
import tech.ytsaurus.core.GUID
import tech.ytsaurus.core.cypress.{CypressNodeType, YPath}
import tech.ytsaurus.core.request.LockMode
import tech.ytsaurus.ysontree.{YTree, YTreeNode}

import scala.annotation.tailrec
import scala.collection.JavaConverters._
import scala.util.control.NonFatal

trait YtCypressUtils {
  self: YtTransactionUtils =>

  private val log = LoggerFactory.getLogger(getClass)

  def correctSlashes(path: String, count: Int): String = {
    if (path.startsWith("/")) {
      "/".repeat(count) + path.dropWhile(_ == '/')
    } else {
      path
    }
  }

  @tailrec
  final def formatPath(path: String): String = {
    log.debugLazy(s"Formatting path $path")
    if (!path.startsWith("/")) {
      if (path.contains(":/")) {
        formatPath(path.split(":", 2).last)
      } else {
        throw new IllegalArgumentException(s"Relative paths are not allowed: $path")
      }
    } else {
      correctSlashes(path, 2)
    }
  }

  def escape(s: String): String = s.replaceAll("([\\\\/@&*\\[{])", "\\\\$1")

  def getNodeType(path: String, transaction: Option[String] = None)
                 (implicit yt: CompoundClient): Option[CypressNodeType] = {
    getNodeType(YPath.simple(formatPath(path)), transaction)
  }

  def getNodeType(path: YPath, transaction: Option[String])
                 (implicit yt: CompoundClient): Option[CypressNodeType] = {
    val fp = path.justPath().attribute("type")
    if (yt.existsNode(ExistsNode.builder().setPath(fp).optionalTransaction(transaction).build()).join()) {
      val nt = yt.getNode(GetNode.builder().setPath(fp).optionalTransaction(transaction).build())
        .join()
        .stringValue()
      Some(CypressNodeType.R.fromName(nt))
    } else
      None
  }

  def isDir(path: String, transaction: Option[String] = None)(implicit yt: CompoundClient): Boolean = {
    isDir(YPath.simple(formatPath(path)), transaction)
  }

  def isDir(path: YPath, transaction: Option[String])(implicit yt: CompoundClient): Boolean =
    try {
      getNodeType(path, transaction).contains(CypressNodeType.MAP)
    } catch {
      case NonFatal(e) =>
        log.debug(s"Cannot get node type: ${e.getMessage}", e)
        false
    }

  def createLink(sourcePath: String, destPath: String, transaction: Option[String] = None,
                 ignoreExisting: Boolean = false)(implicit yt: CompoundClient): Unit = {
    log.debug(s"Creating link $sourcePath -> $destPath, transaction $transaction")
    yt.createNode(
      CreateNode.builder()
      .setPath(YPath.simple(formatPath(destPath)))
      .setType(CypressNodeType.LINK)
      .optionalTransaction(transaction)
      .setAttributes(Map[String, YTreeNode]("target_path" -> YTree.stringNode(sourcePath)).asJava)
      .setIgnoreExisting(ignoreExisting)
      .setRecursive(true)
      .build()
    ).join()
  }

  def createDir(path: String, transaction: Option[String] = None, ignoreExisting: Boolean = false)
               (implicit yt: CompoundClient): Unit = {
    createDir(YPath.simple(formatPath(path)), transaction, ignoreExisting)
  }

  def createDir(path: YPath, transaction: Option[String], ignoreExisting: Boolean)
               (implicit yt: CompoundClient): Unit = {
    log.debug(s"Create new directory: $path, transaction $transaction")
    if (!ignoreExisting || !isDir(path, transaction)) {
      yt.createNode(
        CreateNode.builder()
          .setPath(path)
          .setType(CypressNodeType.MAP)
          .setRecursive(true)
          .setIgnoreExisting(ignoreExisting)
          .optionalTransaction(transaction)
          .build()
      ).join()
    }
  }

  def listDir(path: String, transaction: Option[String] = None)(implicit yt: CompoundClient): Array[String] = {
    listDir(YPath.simple(formatPath(path)), transaction)
  }

  def listDir(path: YPath, transaction: Option[String])(implicit yt: CompoundClient): Array[String] = {
    log.debug(s"List directory: $path, transaction $transaction")
    import scala.collection.JavaConverters._
    val request = ListNode.builder().setPath(path).optionalTransaction(transaction).build()
    val response = yt.listNode(request).join().asList()
    response.asScala.view.map(_.stringValue()).toArray
  }

  def copy(src: String, dst: String, transaction: Option[String] = None, force: Boolean = false)
          (implicit yt: CompoundClient): Unit = {
    log.debug(s"Copy: $src -> $dst, transaction $transaction, force: $force")
    yt.copyNode(
      CopyNode.builder()
        .setSource(formatPath(src))
        .setDestination(formatPath(dst))
        .setForce(force)
        .optionalTransaction(transaction)
        .build()
    ).join()
  }

  def move(src: String, dst: String, transaction: Option[String] = None, force: Boolean = false)
          (implicit yt: CompoundClient): Unit = {
    log.debug(s"Move: $src -> $dst, transaction $transaction, force: $force")
    yt.moveNode(
      MoveNode.builder()
        .setSource(formatPath(src))
        .setDestination(formatPath(dst))
        .setForce(force)
        .optionalTransaction(transaction)
        .build()
    ).join()
  }

  def remove(path: String, transaction: Option[String] = None)(implicit yt: CompoundClient): Unit = {
    log.debug(s"Remove: $path, transaction $transaction")
    val request = RemoveNode.builder()
      .setPath(YPath.simple(formatPath(path)))
      .setRecursive(true)
      .optionalTransaction(transaction)
      .build()
    yt.removeNode(request).join()
  }

  def removeDir(path: String, recursive: Boolean, force: Boolean = false, transaction: Option[String] = None)
               (implicit yt: CompoundClient): Unit = {
    log.debug(s"Remove directory: $path, transaction $transaction")
    val request = RemoveNode.builder()
      .setPath(YPath.simple(formatPath(path)))
      .setRecursive(true)
      .setForce(force)
      .optionalTransaction(transaction)
      .build()
    yt.removeNode(request).join()
  }

  def removeIfExists(path: String, transaction: Option[String] = None)(implicit yt: CompoundClient): Unit = {
    if (exists(path)) {
      remove(path, transaction)
    }
  }

  def removeDirIfExists(path: String, recursive: Boolean, force: Boolean = false, transaction: Option[String] = None)
                       (implicit yt: CompoundClient): Unit = {
    if (exists(path)) {
      removeDir(path, recursive, force, transaction)
    }
  }

  def pathType(path: YPath, transaction: Option[String] = None)(implicit yt: CompoundClient): PathType = {
    val objectType = attribute(path, YtAttributes.`type`, transaction).stringValue()
    PathType.fromString(objectType)
  }

  def pathType(path: String, transaction: Option[String])(implicit yt: CompoundClient): PathType = {
    pathType(YPath.simple(formatPath(path)), transaction)
  }

  def pathType(attrs: Map[String, YTreeNode]): PathType = {
    PathType.fromString(attrs(YtAttributes.`type`).stringValue())
  }

  def exists(path: String)(implicit yt: CompoundClient): Boolean = exists(path, None)

  def exists(path: String, transaction: Option[String])(implicit yt: CompoundClient): Boolean = {
    exists(YPath.simple(formatPath(path)), transaction)
  }

  def exists(path: YPath, transaction: Option[String] = None)(implicit yt: CompoundClient): Boolean = {
    log.debug(s"Exists: $path, transaction $transaction")
    val request = ExistsNode.builder().setPath(path.allAttributes()).optionalTransaction(transaction).build()
    yt.existsNode(request).join().booleanValue()
  }

  def attribute(path: YPath, attrName: String, transaction: Option[String])
               (implicit yt: CompoundClient): YTreeNode = {
    log.debug(s"Get attribute: $path/@$attrName, transaction $transaction")
    val request = GetNode.builder().setPath(path.attribute(attrName)).optionalTransaction(transaction).build()
    yt.getNode(request).join()
  }

  def attribute(path: String, attrName: String, transaction: Option[String] = None)
               (implicit yt: CompoundClient): YTreeNode = {
    attribute(YPath.simple(formatPath(path)), attrName, transaction)
  }

  def attributes(path: YPath, transaction: Option[String] = None, attrNames: Set[String] = Set.empty)
                (implicit yt: CompoundClient): Map[String, YTreeNode] = {
    import scala.collection.JavaConverters._
    log.debug(s"Get attributes: $path/@$attrNames, transaction $transaction")
    val request = GetNode.builder().setPath(path.allAttributes()).optionalTransaction(transaction).build()
    val map = yt.getNode(request).join().asMap().asScala
    val filteredMap = if (attrNames.nonEmpty) map.filterKeys(attrNames.contains) else map
    filteredMap.toMap
  }

  def attributes(path: String, transaction: Option[String], attrNames: Set[String])
                (implicit yt: CompoundClient): Map[String, YTreeNode] = {
    attributes(YPath.simple(formatPath(path)), transaction, attrNames)
  }

  def setAttribute(path: String, attrName: String, attrValue: YTreeNode, transaction: Option[String] = None)
                  (implicit yt: CompoundClient): Unit = {
    log.debug(s"Set attribute: $path/@$attrName, transaction $transaction")
    val request = SetNode.builder()
      .setPath(YPath.simple(s"${formatPath(path)}/@$attrName"))
      .setValue(attrValue)
      .optionalTransaction(transaction)
      .build()
    yt.setNode(request).join()
  }

  def readDocument(path: String, transaction: Option[String] = None)(implicit yt: CompoundClient): YTreeNode = {
    log.debug(s"Read document: $path, transaction $transaction")
    val request = GetNode.builder()
      .setPath(YPath.simple(formatPath(path)))
      .optionalTransaction(transaction)
      .build()
    yt.getNode(request).join()
  }

  def createEmptyDocument(path: String, transaction: Option[String] = None)
                         (implicit yt: CompoundClient): Unit = {
    log.debug(s"Create document: $path, transaction $transaction")
    val request = CreateNode.builder()
      .setPath(YPath.simple(formatPath(path)))
      .setType(CypressNodeType.DOCUMENT)
      .optionalTransaction(transaction)
      .build()
    yt.createNode(request).join()
  }

  def createDocument[T: YsonWriter](path: String, doc: T, transaction: Option[String] = None)
                                   (implicit yt: CompoundClient): Unit = {
    import YsonSyntax._
    createEmptyDocument(formatPath(path), transaction)
    val request = SetNode.builder()
      .setPath(YPath.simple(formatPath(path)))
      .setValue(doc.toYson)
      .optionalTransaction(transaction)
      .build()
    yt.setNode(request).join()
  }

  def createDocumentFromProduct[T <: Product](path: String, doc: T, transaction: Option[String] = None)
                                             (implicit yt: CompoundClient): Unit = {
    import YsonableProduct._
    createDocument(path, doc, transaction)
  }

  def concatenate(from: Array[String], to: String, transaction: Option[String] = None)
                 (implicit yt: CompoundClient): Unit = {
    import scala.collection.JavaConverters._
    log.debug(s"Concatenate: ${from.mkString(",")} -> $to, transaction $transaction")
    val request = ConcatenateNodes.builder()
      .setSourcePaths(from.map(formatPath).map(YPath.simple).toList.asJava)
      .setDestinationPath(YPath.simple(formatPath(to)))
      .optionalTransaction(transaction)
      .build()
    yt.concatenateNodes(request).join()
  }

  def lockNode(path: String, transaction: String, mode: LockMode)
              (implicit yt: CompoundClient): String = {
    lockNode(YPath.simple(formatPath(path)), transaction, mode)
  }

  def lockNode(path: YPath, transaction: String, mode: LockMode = LockMode.Snapshot)
              (implicit yt: CompoundClient): String = {
    val request = LockNode.builder().setPath(path).setMode(mode).optionalTransaction(Some(transaction)).build()
    yt.lockNode(request).join().nodeId.toString
  }

  def lockCount(path: String)(implicit yt: CompoundClient): Long = {
    attribute(path, "lock_count").longValue()
  }

  def lockCount(path: YPath)(implicit yt: CompoundClient): Long = {
    YtWrapper.attribute(path, "lock_count", None).longValue()
  }

  def objectPath(path: String, transaction: Option[String])
                (implicit yt: CompoundClient): YPath = {
    val nodeId = attribute(path, "id", transaction).stringValue()
    YPath.objectRoot(GUID.valueOf(nodeId))
  }

  def objectPath(path: String, transaction: String)
                (implicit yt: CompoundClient): YPath = {
    objectPath(path, Some(transaction))
  }

  def clusterName()(implicit yt: CompoundClient): String = {
    attribute("//sys", "cluster_name").stringValue()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy