Skip to content

Commit

Permalink
Add Use-MdbcTransaction.
Browse files Browse the repository at this point in the history
  • Loading branch information
nightroman committed Nov 28, 2019
1 parent bbd5ce1 commit 17e1bde
Show file tree
Hide file tree
Showing 12 changed files with 470 additions and 43 deletions.
22 changes: 16 additions & 6 deletions .build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,22 @@ task PushNuGet NuGet, {
Clean

# Synopsis: Make and push the PSGallery package.
task PushPSGallery Package, Version, {
assert ($TargetFramework -eq 'netstandard2.0')
$NuGetApiKey = Read-Host NuGetApiKey
Publish-Module -Path z/tools/$ModuleName -NuGetApiKey $NuGetApiKey
},
Clean
task PushPSGallery @(
if ($TargetFramework -eq 'netstandard2.0') {
'Package'
'Version'
{
$NuGetApiKey = Read-Host NuGetApiKey
Publish-Module -Path z/tools/$ModuleName -NuGetApiKey $NuGetApiKey
}
'Clean'
}
else {
{
Invoke-Build PushPSGallery -TargetFramework netstandard2.0
}
}
)

# Synopsis: Test synopsis of each cmdlet and warn about unexpected.
task TestHelpSynopsis {
Expand Down
60 changes: 59 additions & 1 deletion Module/en-US/Mdbc.dll-Help.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,12 @@ $AClient = @{

$ASession = @{
parameters = @{
Session = 'Specifies the client session which executes the command.'
Session = @'
Specifies the client session which invokes the command.
If it is omitted then the cmdlet is invoked in the current default session,
either its own or the transaction session created by Use-MdbcTransaction.
'@
}
}

Expand Down Expand Up @@ -1156,3 +1161,56 @@ Tells to ignore document elements that do not match the properties.
'@
}
}

### Use-MdbcTransaction
Merge-Helps $AClient @{
command = 'Use-MdbcTransaction'
synopsis = 'Invokes the script with a transaction.'
description = @'
The cmdlet starts a transaction session and invokes the specified script. The
script calls data cmdlets and either succeeds or fails. The cmdlet commits or
aborts the transaction accordingly.
The transaction session is default for cmdlets with the parameter Session.
For the script the session is exposed as the automatic variable $Session.
Nested calls are allowed but transactions and sessions are independent.
In particular, they may not see changes made in parent or nested calls.
'@
parameters = @{
Script = @'
Specifies the script to be invoked with a transaction session.
'@
}

outputs = @(
@{
type = '[object]'
description = 'Output of the specified script.'
}
)

examples = @(
@{
code = {
# add several documents using a transaction
$documents = ...
Use-MdbcTransaction {
$documents | Add-MdbcData
}
}
}
@{
code = {
# move a document using a transaction
$c1 = Get-MdbcCollection MyData1
$c2 = Get-MdbcCollection MyData2
Use-MdbcTransaction {
# get and remove from MyData1 | add to MyData2
Get-MdbcData @{_id = 1} -Remove -Collection $c1 |
Add-MdbcData -Collection $c2
}
}
}
)
}
22 changes: 19 additions & 3 deletions Src/Commands/AbstractSessionCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// Copyright (c) Roman Kuzmin
// http://www.apache.org/licenses/LICENSE-2.0

using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Management.Automation;

namespace Mdbc.Commands
Expand All @@ -15,15 +15,31 @@ public abstract class AbstractSessionCommand : Abstract, IDisposable
bool _disposed;
IClientSessionHandle _Session;

//! ThreadStatic and `= new Stack()` fails in Split-Pipeline
[ThreadStatic]
static Stack<IClientSessionHandle> _DefaultSessions_;
static Stack<IClientSessionHandle> DefaultSessions { get { return _DefaultSessions_ ?? (_DefaultSessions_ = new Stack<IClientSessionHandle>()); } }
internal static void PushDefaultSession(IClientSessionHandle session) { DefaultSessions.Push(session); }
internal static IClientSessionHandle PopDefaultSession() { return DefaultSessions.Pop(); }

[Parameter]
public IClientSessionHandle Session
{
get
{
if (_Session == null)
{
_Session = MyClient.StartSession();
_dispose = true;
if (DefaultSessions.Count == 0)
{
// temporary session
_Session = MyClient.StartSession();
_dispose = true;
}
else
{
// the current default session
_Session = DefaultSessions.Peek();
}
}
return _Session;
}
Expand Down
4 changes: 2 additions & 2 deletions Src/CollectionExt.cs → Src/Commands/CollectionExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
using MongoDB.Driver;
using System.Collections.Generic;

namespace Mdbc
namespace Mdbc.Commands
{
static class CollectionExt
{
public static long MyCount(this IMongoCollection<BsonDocument> collection, IClientSessionHandle session, FilterDefinition<BsonDocument> filter, long skip, long first)
{
if (skip <= 0 && first <= 0)
return collection.CountDocuments(filter);
return collection.CountDocuments(session, filter);

var options = new CountOptions();
if (skip > 0)
Expand Down
48 changes: 48 additions & 0 deletions Src/Commands/UseTransactionCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

// Copyright (c) Roman Kuzmin
// http://www.apache.org/licenses/LICENSE-2.0

using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Management.Automation;

namespace Mdbc.Commands
{
[Cmdlet(VerbsOther.Use, "MdbcTransaction"), OutputType(typeof(IMongoDatabase))]
public sealed class UseTransactionCommand : AbstractClientCommand
{
[Parameter(Position = 0, Mandatory = true)]
public ScriptBlock Script { get; set; }

protected override void BeginProcessing()
{
var session = Client.StartSession();
AbstractSessionCommand.PushDefaultSession(session);
try
{
session.StartTransaction();
try
{
var vars = new List<PSVariable>() { new PSVariable("Session", session) };
var result = Script.InvokeWithContext(null, vars);
foreach (var item in result)
WriteObject(item);

session.CommitTransaction();
}
catch (RuntimeException exn)
{
var text = $"{exn.Message}{Environment.NewLine}{exn.ErrorRecord.InvocationInfo.PositionMessage}";
var exn2 = new RuntimeException(text, exn);
WriteException(exn2, null);
}
}
finally
{
AbstractSessionCommand.PopDefaultSession();
session.Dispose();
}
}
}
}
2 changes: 1 addition & 1 deletion Src/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "rk", Scope = "namespaceanddescendants", Target = "Mdbc.Commands")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1825:Avoid zero-length array allocations.", Justification = "<Pending>", Scope = "member", Target = "~F:Mdbc.MyDocument.EmptyArray")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "<Pending>", Scope = "type", Target = "~T:Mdbc.Collection")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "<Pending>", Scope = "type", Target = "~T:Mdbc.Dictionary")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "<Pending>", Scope = "type", Target = "~T:Mdbc.Dictionary")]
2 changes: 1 addition & 1 deletion Src/Mdbc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
1 change: 1 addition & 0 deletions Tests/About.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,6 @@ task PublicTypes {
'RenameCollectionCommand'
'SetDataCommand'
'UpdateDataCommand'
'UseTransactionCommand'
)
}
4 changes: 2 additions & 2 deletions Tests/MongoFiles.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ task Get-MongoFile Update-MongoFiles, {
$r = @(Get-MongoFile -CollectionName test 'collectionext|documentinput' | Sort-Object)
$r
equals 3 $r.Count
assert ($r[0] -clike '*\Mdbc\Src\CollectionExt.cs')
assert ($r[0] -clike '*\Mdbc\Src\Commands\CollectionExt.cs')
assert ($r[1] -clike '*\Mdbc\Src\DocumentInput.cs')
assert ($r[2] -clike '*\Mdbc\Tests\DocumentInput.test.ps1')

$r = @(Get-MongoFile -CollectionName test 'CollectionExt.cs' -Name)
equals 1 $r.Count
assert ($r[0] -clike '*\Mdbc\Src\CollectionExt.cs')
assert ($r[0] -clike '*\Mdbc\Src\Commands\CollectionExt.cs')
}
27 changes: 0 additions & 27 deletions Tests/Session.test.ps1

This file was deleted.

0 comments on commit 17e1bde

Please sign in to comment.