Skip to content

Add transactional batch support (batch command) - #135

Merged
Mike Krüger (mkrueger) merged 13 commits into
mainfrom
dev/copilot/batch-support
Aug 28, 2026
Merged

Add transactional batch support (batch command)#135
Mike Krüger (mkrueger) merged 13 commits into
mainfrom
dev/copilot/batch-support

Conversation

@mkrueger

@mkrueger Mike Krüger (mkrueger) commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Closes #105.

Adds a batch command for executing Cosmos DB transactional batches — atomic multi-operation transactions scoped to a single partition key.

Design

Supports both a single-shot mode and a stateful mode:

  • Single-shot: batch run <json> --partition-key <pk> executes an array of operations atomically.
  • Stateful: batch beginbatch addbatch execute, with batch cancel, batch status, and batch show for inspection/control.

The partition key is always supplied explicitly via --partition-key (--pk). Operations may be create, upsert, replace, delete, or patch. Input can be piped (e.g. cat batch.json | batch run --pk myPk) or passed inline.

Subcommands

Subcommand Description
run Execute a JSON array of operations atomically in one shot.
begin Start a stateful batch for a partition key.
add Queue an operation onto the active batch.
execute (exec, commit) Commit the queued operations atomically.
cancel (abort) Discard the active batch.
status Print a JSON summary of the active batch (db/container/pk/op count/op kinds).
show Print the queued operations as a JSON array (same shape accepted by run/add).

When a stateful batch is active, the prompt shows a [batch:N] indicator with the queued operation count.

Implementation notes

  • BatchOperationParser parses the operation JSON (array or single object) into BatchOperationSpec records; each spec retains its raw operation JSON so batch show can faithfully round-trip the input.
  • BatchExecutor builds the TransactionalBatch and emits a JSON result summary (success, status code, request charge, per-operation results).
  • Patch operation building was extracted from PatchCommand into a shared PatchOperationFactory reused by both patch and batch.
  • PendingBatchState holds the in-progress stateful batch on ShellInterpreter; it is cleared on connect/disconnect.

Validation

  • Offline parser tests in BatchCommandTests (including raw-operation round-trip).
  • Emulator integration tests in BatchOperationTests (multi-create, create-then-patch, rollback on failure, begin/add/execute, cancel, show, and error paths) using a dedicated /pk-partitioned container.
  • Localization and help-text audits updated and passing.
  • Both projects build clean (0 warnings).

Docs

  • docs/commands.md: full batch section with usage, subcommand table, and examples.
  • README.md: feature bullet.

Workflow:

image

Implements issue #105: a 'batch' command that executes multiple write operations against a single partition key as one atomic Cosmos DB transactional batch.

- Single-shot: 'batch run <json> --partition-key <pk>' (also reads piped input)

- Stateful: 'batch begin/add/execute/cancel/status' with a [batch:N] prompt indicator

- Supports create, upsert, replace, delete, and patch operations

- Extracts shared patch-op building into PatchOperationFactory (reused by patch command)

- Adds en.ftl strings, docs, offline parser tests, and emulator integration tests
Prints the queued operations of the active stateful batch as a JSON array (the same shape accepted by 'batch run'/'batch add'). Each spec now retains its raw operation JSON for faithful round-tripping. Includes docs, localization, and offline + integration tests.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class Cosmos DB transactional batch support to CosmosDBShell via a new batch command, enabling atomic multi-operation writes scoped to a single partition key, with both single-shot and stateful workflows.

Changes:

  • Introduces batch command with subcommands for run/begin/add/execute/cancel/status/show, plus a queued-op prompt indicator ([batch:N]).
  • Adds shared batch parsing/execution components (BatchOperationParser, BatchExecutor) and state tracking (PendingBatchState).
  • Extracts patch sub-operation construction into a reusable PatchOperationFactory, reused by both patch and batch, with unit + integration test coverage.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
README.md Adds batch to the feature list.
docs/commands.md Documents batch usage, schema, output, examples, and errors.
CosmosDBShell/lang/en.ftl Adds localized help text and error/success messages for batch.
CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs Stores/clears the active pending batch on connect/disconnect.
CosmosDBShell/Azure.Data.Cosmos.Shell.Core/PendingBatchState.cs New state object holding db/container/pk and queued operations.
CosmosDBShell/Azure.Data.Cosmos.Shell.Core/CosmosShellPrompt.cs Adds [batch:N] indicator and refresh logic to prompt rendering.
CosmosDBShell/Azure.Data.Cosmos.Shell.Core/BatchOperationSpec.cs New operation model for batch execution + round-trippable raw JSON.
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/PatchOperationFactory.cs New shared builder for patch operations (used by patch + batch).
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/PatchCommand.cs Refactors to use PatchOperationFactory.
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchOperationParser.cs Parses/validates batch operation JSON into specs (incl. patch operations).
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchExecutor.cs Builds/executes TransactionalBatch and emits JSON summary results.
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs New batch CLI command implementation (single-shot + stateful modes).
CosmosDBShell.Tests/Integration/BatchOperationTests.cs Emulator integration coverage for batch success/failure/stateful flows.
CosmosDBShell.Tests/CommandTests/BatchCommandTests.cs Offline unit tests for batch JSON parsing/validation + raw round-trip.

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs
Comment thread docs/commands.md Outdated
…ey docs

batch run now wraps service CosmosExceptions in the localized command-batch-error-execution_failed message, matching batch execute. Docs clarify --partition-key is only required for run and begin.
Copilot AI review requested due to automatic review settings July 9, 2026 09:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Comment thread CosmosDBShell/lang/en.ftl Outdated
PatchOperationFactory.Build now takes an unsupportedOpMessageKey so batch patch entries surface command-batch-error-unsupported_patch_op instead of the patch command usage line. missing_data text now notes a single operation object is also accepted.
Copilot AI review requested due to automatic review settings July 9, 2026 09:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 25, 2026 09:41
@github-code-quality

github-code-quality Bot commented Aug 25, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: C#

C# / code-coverage/dotnet

The overall line coverage in commit 26afe53 in the dev/copilot/batch-su... branch remains at 62%, unchanged from commit 0d21834 in the main branch.

Show a line coverage summary of the most impacted files.
File main 0d21834 dev/copilot/batch-su... 26afe53 +/-
D:\a\CosmosDBSh...olOperations.cs 89% 90% +1%
D:\a\CosmosDBSh...ponseFactory.cs 90% 92% +2%
D:\a\CosmosDBSh...atchExecutor.cs 0% 8% +8%
D:\a\CosmosDBSh...PatchCommand.cs 18% 28% +10%
D:\a\CosmosDBSh...ationFactory.cs 0% 37% +37%
D:\a\CosmosDBSh...BatchCommand.cs 0% 53% +53%
D:\a\CosmosDBSh...ngBatchState.cs 0% 91% +91%
D:\a\CosmosDBSh...rationParser.cs 0% 93% +93%
D:\a\CosmosDBSh...perationSpec.cs 0% 100% +100%
D:\a\CosmosDBSh...CommandState.cs 0% 100% +100%

Updated August 28, 2026 07:22 UTC

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Suppressed comments (1)

CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs:265

  • command-batch-added pluralizes on $count, but specs.Count.ToString(...) passes a string and can break singular/plural selection in Fluent. Pass counts as integers (and you can also pass total as an int for consistency).
        batch.Operations.AddRange(specs);
        ShellInterpreter.WriteLine(MessageService.GetArgsString(
            "command-batch-added",
            "count",
            specs.Count.ToString(CultureInfo.InvariantCulture),
            "total",
            batch.Operations.Count.ToString(CultureInfo.InvariantCulture)));
        return new CommandState();

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchExecutor.cs Outdated
Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs Outdated
Comment thread docs/commands.md
Copilot AI review requested due to automatic review settings August 27, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Comment thread docs/commands.md Outdated
Comment thread docs/commands.md Outdated
Copilot AI review requested due to automatic review settings August 27, 2026 13:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

CosmosDBShell/Azure.Data.Cosmos.Shell.Core/CosmosShellPrompt.cs:65

  • Theme.FormatMuted(...) already applies Markup.Escape internally. Passing Markup.Escape(...) here double-escapes the text, so the prompt will render the literal escape sequences (e.g., showing "[[batch:1]]" instead of "[batch:1]") when a batch is active.
        if (batch is not null)
        {
            basePrompt += " " + Theme.FormatMuted(Markup.Escape($"[batch:{batch.Operations.Count}]"));
        }

Copilot AI review requested due to automatic review settings August 27, 2026 13:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Suppressed comments (2)

CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs:234

  • batch begin prints a human-facing message unconditionally. In machine mode this can introduce non-structured output; consider suppressing this message when shell.IsMachineMode is true so only structured results are emitted.
        ShellInterpreter.WriteLine(MessageService.GetArgsString(
            "command-batch-begun",
            "database",
            databaseName!,
            "container",

CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs:262

  • batch add prints a human-facing message unconditionally. In machine mode this can pollute stdout and make output harder to consume programmatically; consider suppressing the message when shell.IsMachineMode is true.
        ShellInterpreter.WriteLine(MessageService.GetArgsString(
            "command-batch-added",
            "count",
            specs.Count,
            "total",

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchExecutor.cs
Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs Outdated
Copilot AI review requested due to automatic review settings August 27, 2026 13:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Return structured error states for rolled-back transactional batches so CLI and MCP callers receive failure semantics without losing per-operation results. Restrict MCP batch calls to the stateless run workflow and document the contract.
Copilot AI review requested due to automatic review settings August 27, 2026 13:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/BatchCommand.cs:66

  • For stateful subcommands (add/execute/cancel/status/show), the command still accepts --partition-key / -db / -con options but silently ignores them in favor of the active batch’s bound context. This can mislead users into thinking they’re queuing/executing against a different container or partition key than the one that will actually be used.
    public override async Task<CommandState> ExecuteAsync(ShellInterpreter shell, CommandState commandState, string commandText, CancellationToken token)
    {
        var subcommand = this.Subcommand.Trim().ToLowerInvariant();

        return subcommand switch

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Mcp/ToolOperations.cs Outdated
Use human-oriented interactive output for batch status and execution while preserving structured machine results. Classify transactional failures by HTTP status, keep structured error details, and harden MCP batch validation.
Copilot AI review requested due to automatic review settings August 27, 2026 15:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

CosmosDBShell/Azure.Data.Cosmos.Shell.Mcp/ToolOperations.cs:466

  • (cmd as BatchCommand)?.Subcommand.Trim() can throw if MCP binds a JSON null for subcommand (the binder sets the string property to null). Use a null-conditional trim to avoid a NullReferenceException and let the normal missing/invalid-subcommand path handle it.
        var batchSubcommand = (cmd as BatchCommand)?.Subcommand.Trim();

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Mcp/ToolOperations.cs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 28, 2026 07:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated no new comments.

@mkrueger
Mike Krüger (mkrueger) merged commit c246023 into main Aug 28, 2026
10 checks passed
@mkrueger
Mike Krüger (mkrueger) deleted the dev/copilot/batch-support branch August 28, 2026 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P1] Add Transactional Batch support

3 participants