@@ -655,6 +655,10 @@ private class TransactionalBulkWriter
655655 }
656656
657657 override def scheduleWrite (partitionKeyValue : PartitionKey , objectNode : ObjectNode ): Unit = {
658+ scheduleWrite(partitionKeyValue, objectNode, None )
659+ }
660+
661+ override def scheduleWrite (partitionKeyValue : PartitionKey , objectNode : ObjectNode , operationType : Option [String ]): Unit = {
658662 Preconditions .checkState(! closed.get())
659663 throwIfCapturedExceptionExists()
660664
@@ -664,7 +668,9 @@ private class TransactionalBulkWriter
664668 partitionKeyValue,
665669 getETag(objectNode),
666670 1 ,
667- monotonicOperationCounter.incrementAndGet())
671+ monotonicOperationCounter.incrementAndGet(),
672+ None ,
673+ operationType)
668674 val numberOfIntervalsWithIdenticalActiveOperationSnapshots = new AtomicLong (0 )
669675 // Don't clone the activeOperations for the first iteration
670676 // to reduce perf impact before the Semaphore has been acquired
@@ -739,10 +745,28 @@ private class TransactionalBulkWriter
739745 objectNode : ObjectNode ,
740746 operationContext : OperationContext ): Unit = {
741747
742- val bulkItemOperation = writeConfig.itemWriteStrategy match {
743- case ItemWriteStrategy .ItemOverwrite =>
748+ // Determine the effective operation type from per-row operationType or global strategy
749+ val effectiveOperationType = operationContext.operationType match {
750+ case Some (opType) => opType.toLowerCase
751+ case None => writeConfig.itemWriteStrategy match {
752+ case ItemWriteStrategy .ItemOverwrite => " upsert"
753+ case ItemWriteStrategy .ItemAppend => " create"
754+ case ItemWriteStrategy .ItemDelete | ItemWriteStrategy .ItemDeleteIfNotModified => " delete"
755+ case ItemWriteStrategy .ItemOverwriteIfNotModified => " replace"
756+ case ItemWriteStrategy .ItemTransactionalBatch => " upsert" // Default to upsert for transactional batch
757+ case ItemWriteStrategy .ItemPatch | ItemWriteStrategy .ItemPatchIfExists => " patch"
758+ case _ => throw new RuntimeException (s " ${writeConfig.itemWriteStrategy} not supported for transactional batch " )
759+ }
760+ }
761+
762+ val bulkItemOperation = effectiveOperationType match {
763+ case " create" =>
764+ CosmosBulkOperations .getCreateItemOperation(objectNode, partitionKeyValue, operationContext)
765+
766+ case " upsert" =>
744767 CosmosBulkOperations .getUpsertItemOperation(objectNode, partitionKeyValue, operationContext)
745- case ItemWriteStrategy .ItemOverwriteIfNotModified =>
768+
769+ case " replace" =>
746770 operationContext.eTag match {
747771 case Some (eTag) =>
748772 CosmosBulkOperations .getReplaceItemOperation(
@@ -751,29 +775,41 @@ private class TransactionalBulkWriter
751775 partitionKeyValue,
752776 new CosmosBulkItemRequestOptions ().setIfMatchETag(eTag),
753777 operationContext)
754- case _ => CosmosBulkOperations .getCreateItemOperation(objectNode, partitionKeyValue, operationContext)
778+ case _ =>
779+ CosmosBulkOperations .getReplaceItemOperation(
780+ operationContext.itemId,
781+ objectNode,
782+ partitionKeyValue,
783+ operationContext)
755784 }
756- case ItemWriteStrategy .ItemAppend =>
757- CosmosBulkOperations .getCreateItemOperation(objectNode, partitionKeyValue, operationContext)
758- case ItemWriteStrategy .ItemDelete =>
759- CosmosBulkOperations .getDeleteItemOperation(operationContext.itemId, partitionKeyValue, operationContext)
760- case ItemWriteStrategy .ItemDeleteIfNotModified =>
761- CosmosBulkOperations .getDeleteItemOperation(
785+
786+ case " delete" =>
787+ operationContext.eTag match {
788+ case Some (eTag) =>
789+ CosmosBulkOperations .getDeleteItemOperation(
790+ operationContext.itemId,
791+ partitionKeyValue,
792+ new CosmosBulkItemRequestOptions ().setIfMatchETag(eTag),
793+ operationContext)
794+ case _ =>
795+ CosmosBulkOperations .getDeleteItemOperation(
796+ operationContext.itemId,
797+ partitionKeyValue,
798+ operationContext)
799+ }
800+
801+ case " patch" =>
802+ getPatchItemOperation(
762803 operationContext.itemId,
763804 partitionKeyValue,
764- operationContext.eTag match {
765- case Some (eTag) => new CosmosBulkItemRequestOptions ().setIfMatchETag(eTag)
766- case _ => new CosmosBulkItemRequestOptions ()
767- },
805+ partitionKeyDefinition,
806+ objectNode,
768807 operationContext)
769- case ItemWriteStrategy .ItemPatch | ItemWriteStrategy .ItemPatchIfExists => getPatchItemOperation(
770- operationContext.itemId,
771- partitionKeyValue,
772- partitionKeyDefinition,
773- objectNode,
774- operationContext)
808+
775809 case _ =>
776- throw new RuntimeException (s " ${writeConfig.itemWriteStrategy} not supported " )
810+ throw new IllegalArgumentException (
811+ s " Unsupported operationType ' $effectiveOperationType'. " +
812+ s " Supported types for transactional batch: create, upsert, replace, delete " )
777813 }
778814
779815 this .emitBulkInput(bulkItemOperation)
@@ -1363,9 +1399,10 @@ private class TransactionalBulkWriter
13631399 val attemptNumber : Int ,
13641400 val sequenceNumber : Long ,
13651401 /** starts from 1 * */
1366- sourceItemInput : Option [ObjectNode ] = None ) // for patchBulkUpdate: source item refers to the original objectNode from which SDK constructs the final bulk item operation
1402+ sourceItemInput : Option [ObjectNode ] = None , // for patchBulkUpdate: source item refers to the original objectNode from which SDK constructs the final bulk item operation
1403+ operationTypeInput : Option [String ] = None ) // per-row operation type (create, upsert, replace, delete)
13671404 {
1368- private val ctxCore : OperationContextCore = OperationContextCore (itemIdInput, partitionKeyValueInput, eTagInput, sourceItemInput)
1405+ private val ctxCore : OperationContextCore = OperationContextCore (itemIdInput, partitionKeyValueInput, eTagInput, sourceItemInput, operationTypeInput )
13691406
13701407 override def equals (obj : Any ): Boolean = ctxCore.equals(obj)
13711408
@@ -1382,14 +1419,17 @@ private class TransactionalBulkWriter
13821419 def eTag : Option [String ] = ctxCore.eTag
13831420
13841421 def sourceItem : Option [ObjectNode ] = ctxCore.sourceItem
1422+
1423+ def operationType : Option [String ] = ctxCore.operationType
13851424 }
13861425
13871426 private case class OperationContextCore
13881427 (
13891428 itemId : String ,
13901429 partitionKeyValue : PartitionKey ,
13911430 eTag : Option [String ],
1392- sourceItem : Option [ObjectNode ] = None ) // for patchBulkUpdate: source item refers to the original objectNode from which SDK constructs the final bulk item operation
1431+ sourceItem : Option [ObjectNode ] = None , // for patchBulkUpdate: source item refers to the original objectNode from which SDK constructs the final bulk item operation
1432+ operationType : Option [String ] = None ) // per-row operation type (create, upsert, replace, delete)
13931433 {
13941434 override def productPrefix : String = " OperationContext"
13951435 }
0 commit comments