override protected[database] def put()

in common/scala/src/main/scala/org/apache/openwhisk/core/database/cosmosdb/CosmosDBArtifactStore.scala [99:155]


  override protected[database] def put(d: DocumentAbstraction)(implicit transid: TransactionId): Future[DocInfo] = {
    val asJson = d.toDocumentRecord

    val (doc, docSize) = toCosmosDoc(asJson)
    val id = doc.getId
    val docinfoStr = s"id: $id, rev: ${doc.getETag}"
    val start = transid.started(this, LoggingMarkers.DATABASE_SAVE, s"[PUT] '$collName' saving document: '$docinfoStr'")

    val o = if (isNewDocument(doc)) {
      client.createDocument(collection.getSelfLink, doc, newRequestOption(id), true)
    } else {
      client.replaceDocument(doc, matchRevOption(id, doc.getETag))
    }

    val f = o
      .head()
      .recoverWith {
        case e: DocumentClientException if isConflict(e) && isNewDocument(doc) =>
          val docId = DocId(asJson.fields(_id).convertTo[String])
          //Fetch existing document and check if its deleted
          getRaw(docId).flatMap {
            case Some(js) =>
              if (isSoftDeleted(js)) {
                //Existing document is soft deleted. So can be replaced. Use the etag of document
                //and replace it with document we are trying to add
                val etag = js.fields(Properties.E_TAG).convertTo[String]
                client.replaceDocument(doc, matchRevOption(id, etag)).head()
              } else {
                //Trying to create a new document and found an existing
                //Document which is valid (not soft delete) then conflict is a valid outcome
                throw e
              }
            case None =>
              //Document not found. Should not happen unless someone else removed
              //Propagate existing exception
              throw e
          }
      }
      .transform(
        { r =>
          docSizeToken.histogram.record(docSize)
          transid.finished(
            this,
            start,
            s"[PUT] '$collName' completed document: '$docinfoStr', size=$docSize, ru=${r.getRequestCharge}${extraLogs(r)}",
            InfoLevel)
          collectMetrics(putToken, r.getRequestCharge)
          toDocInfo(r.getResource)
        }, {
          case e: DocumentClientException if isConflict(e) =>
            transid.finished(this, start, s"[PUT] '$collName', document: '$docinfoStr'; conflict.")
            DocumentConflictException("conflict on 'put'")
          case e => e
        })

    reportFailure(f, start, failure => s"[PUT] '$collName' internal error, failure: '${failure.getMessage}'")
  }