Skip to content
This repository was archived by the owner on Sep 3, 2024. It is now read-only.

Commit 5d2a01d

Browse files
message deletion
1 parent cc915b4 commit 5d2a01d

10 files changed

Lines changed: 117 additions & 35 deletions

src/SqlStreamStore.HAL.Tests/StreamMessageTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,20 @@ public async Task read_single_message_does_not_exist_stream()
5656
resource.ShouldLink(Constants.Relations.Feed, HeadOfStream);
5757
}
5858
}
59+
60+
[Fact]
61+
public async Task delete_single_message_by_version()
62+
{
63+
var writeResult = await _fixture.WriteNMessages("a-stream", 1);
64+
65+
using(var response = await _fixture.HttpClient.DeleteAsync("/streams/a-stream/0"))
66+
{
67+
response.StatusCode.ShouldBe(HttpStatusCode.OK);
68+
}
69+
using(var response = await _fixture.HttpClient.GetAsync("/streams/a-stream/0"))
70+
{
71+
response.StatusCode.ShouldBe(HttpStatusCode.NotFound);
72+
}
73+
}
5974
}
6075
}

src/SqlStreamStore.HAL/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public static class Headers
99
{
1010
public const string ExpectedVersion = "SSS-ExpectedVersion";
1111
public const string HeadPosition = "SSS-HeadPosition";
12+
public const string MessageId = "SSS-MessageId";
1213
public const string Location = "Location";
1314

1415
public static class ContentTypes

src/SqlStreamStore.HAL/DeleteStreamMiddleware.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ internal static class DeleteStreamMiddleware
1414
{
1515
public static MidFunc UseStreamStore(IStreamStore streamStore)
1616
{
17-
var stream = new StreamResource(streamStore);
17+
var streams = new StreamResource(streamStore);
18+
var streamMessaages = new StreamMessageResource(streamStore);
1819

1920
var builder = new AppBuilder()
20-
.MapWhen(IsStream, inner => inner.Use(DeleteStream(stream)));
21+
.MapWhen(IsStream, inner => inner.Use(DeleteStream(streams)))
22+
.MapWhen(IsStreamMessage, inner => inner.Use(DeleteStreamMessage(streamMessaages)));
2123

2224
return next =>
2325
{
@@ -30,6 +32,9 @@ public static MidFunc UseStreamStore(IStreamStore streamStore)
3032
private static bool IsStream(IOwinContext context)
3133
=> context.IsDelete() && context.Request.Path.IsStream();
3234

35+
private static bool IsStreamMessage(IOwinContext context)
36+
=> context.IsDelete() && context.Request.Path.IsStreamMessageByIdOrVersion();
37+
3338
private static MidFunc DeleteStream(StreamResource stream) => next => async env =>
3439
{
3540
var context = new OwinContext(env);
@@ -40,5 +45,16 @@ private static MidFunc DeleteStream(StreamResource stream) => next => async env
4045

4146
await context.WriteHalResponse(response);
4247
};
48+
49+
private static MidFunc DeleteStreamMessage(StreamMessageResource streamMessages) => next => async env =>
50+
{
51+
var context = new OwinContext(env);
52+
53+
var options = new DeleteStreamMessageOptions(context.Request);
54+
55+
var response = await streamMessages.DeleteMessage(options, context.Request.CallCancelled);
56+
57+
await context.WriteHalResponse(response);
58+
};
4359
}
4460
}

src/SqlStreamStore.HAL/PathStringExtensions.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
namespace SqlStreamStore.HAL
22
{
3+
using System;
34
using Microsoft.Owin;
45

56
internal static class PathStringExtensions
67
{
7-
public static bool IsAllStream(this PathString requestPath)
8+
public static bool IsAllStream(this PathString requestPath)
89
=> !requestPath.HasValue;
910

10-
public static bool IsAllStreamMessage(this PathString requestPath)
11+
public static bool IsAllStreamMessage(this PathString requestPath)
1112
=> long.TryParse(requestPath.Value?.Remove(0, 1), out _);
1213

13-
public static bool IsStream(this PathString requestPath)
14+
public static bool IsStream(this PathString requestPath)
1415
=> requestPath.Value?.Split('/').Length == 2;
1516

1617
public static bool IsStreamMessage(this PathString requestPath)
1718
{
1819
var segments = requestPath.Value?.Split('/');
19-
20+
2021
return segments?.Length == 3 && int.TryParse(segments[2], out _);
2122
}
2223

24+
public static bool IsStreamMessageByIdOrVersion(this PathString requestPath)
25+
{
26+
var segments = requestPath.Value?.Split('/');
27+
28+
return segments?.Length == 3 && (int.TryParse(segments[2], out _) || Guid.TryParse(segments[2], out _));
29+
}
30+
2331
public static bool IsStreamMetadata(this PathString requestPath)
2432
{
2533
var segments = requestPath.Value?.Split('/');
26-
34+
2735
return segments?.Length == 3 && segments[2] == Constants.Streams.Metadata;
2836
}
2937
}

src/SqlStreamStore.HAL/ReadStreamMiddleware.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
namespace SqlStreamStore.HAL
22
{
3-
using System.Net.Http;
4-
using System.Threading.Tasks;
53
using Microsoft.Owin;
64
using Microsoft.Owin.Builder;
75
using Owin;
@@ -55,7 +53,7 @@ private static MidFunc GetStreamMessage(StreamMessageResource streamMessages) =>
5553
{
5654
var context = new OwinContext(env);
5755

58-
var options = new ReadStreamMessageOptions(context.Request);
56+
var options = new ReadStreamMessageByStreamVersionOptions(context.Request);
5957

6058
var response = await streamMessages.GetMessage(options, context.Request.CallCancelled);
6159

@@ -64,17 +62,5 @@ private static MidFunc GetStreamMessage(StreamMessageResource streamMessages) =>
6462
await context.WriteHalResponse(response);
6563
}
6664
};
67-
68-
private static MidFunc GetStreamMessageOptions => next => env =>
69-
{
70-
var context = new OwinContext(env);
71-
72-
context.SetStandardCorsHeaders(
73-
HttpMethod.Get,
74-
HttpMethod.Head,
75-
HttpMethod.Options);
76-
77-
return Task.CompletedTask;
78-
};
7965
}
8066
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
namespace SqlStreamStore.HAL.Resources
2+
{
3+
using System;
4+
using System.Linq;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Microsoft.Owin;
8+
9+
internal class DeleteStreamMessageOptions
10+
{
11+
public DeleteStreamMessageOptions(IOwinRequest request)
12+
{
13+
var pieces = request.Path.Value.Split('/').Reverse().Take(2).ToArray();
14+
15+
StreamId = pieces.LastOrDefault();
16+
17+
if(Guid.TryParse(pieces.First(), out var messageId))
18+
{
19+
MessageId = messageId;
20+
}
21+
else
22+
{
23+
StreamVersion = int.Parse(pieces.First());
24+
}
25+
}
26+
27+
public string StreamId { get; }
28+
public int? StreamVersion { get; }
29+
public Guid? MessageId { get; }
30+
31+
public Func<IStreamStore, CancellationToken, Task> GetDeleteOperation()
32+
=> async (streamStore, ct) =>
33+
{
34+
var messageId = MessageId ?? (await streamStore.ReadStreamBackwards(
35+
StreamId,
36+
StreamVersion.GetValueOrDefault(-1),
37+
1,
38+
true,
39+
ct))
40+
.Messages.FirstOrDefault(
41+
message => StreamVersion == Streams.StreamVersion.End
42+
|| message.StreamVersion == StreamVersion)
43+
.MessageId;
44+
await streamStore.DeleteMessage(StreamId, messageId);
45+
};
46+
}
47+
}

src/SqlStreamStore.HAL/Resources/Links.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public static Link Last(ReadStreamPage page, ReadStreamOptions options)
137137
public static Link Feed(ReadStreamPage page, ReadStreamOptions options)
138138
=> new Link(Constants.Relations.Feed, Last(page, options).Href);
139139

140-
public static Link Feed(ReadStreamMessageOptions options)
140+
public static Link Feed(ReadStreamMessageByStreamVersionOptions options)
141141
=> new Link(
142142
Constants.Relations.Feed,
143143
LinkFormatter.FormatBackwardLink(
@@ -180,7 +180,7 @@ public static IEnumerable<Link> Navigation(ReadStreamPage page, ReadStreamOption
180180

181181
internal static class StreamMessage
182182
{
183-
public static Link Self(ReadStreamMessageOptions options) => new Link(
183+
public static Link Self(ReadStreamMessageByStreamVersionOptions options) => new Link(
184184
Constants.Relations.Self,
185185
$"{options.StreamVersion}");
186186

@@ -226,18 +226,18 @@ public static Link Last(ReadStreamPage page, ReadStreamOptions options)
226226

227227
private static Link First() => new Link(Constants.Relations.First, $"{0}");
228228

229-
private static Link Previous(ReadStreamMessageOptions options) => new Link(
229+
private static Link Previous(ReadStreamMessageByStreamVersionOptions options) => new Link(
230230
Constants.Relations.Previous,
231231
$"{options.StreamVersion - 1}");
232232

233-
private static Link Next(ReadStreamMessageOptions options) => new Link(
233+
private static Link Next(ReadStreamMessageByStreamVersionOptions options) => new Link(
234234
Constants.Relations.Next,
235235
$"{options.StreamVersion + 1}");
236236

237237
private static Link Last() => new Link(Constants.Relations.Last, $"{-1}");
238238

239239
public static IEnumerable<Link> Navigation(
240-
ReadStreamMessageOptions options,
240+
ReadStreamMessageByStreamVersionOptions options,
241241
Streams.StreamMessage message = default(Streams.StreamMessage))
242242
{
243243
yield return First();

src/SqlStreamStore.HAL/Resources/ReadStreamMessageOptions.cs renamed to src/SqlStreamStore.HAL/Resources/ReadStreamMessageByStreamVersionOptions.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,15 @@ namespace SqlStreamStore.HAL.Resources
77
using Microsoft.Owin;
88
using SqlStreamStore.Streams;
99

10-
internal class ReadStreamMessageOptions
10+
internal class ReadStreamMessageByStreamVersionOptions
1111
{
12-
public ReadStreamMessageOptions(IOwinRequest request)
12+
public ReadStreamMessageByStreamVersionOptions(IOwinRequest request)
1313
{
1414
var pieces = request.Path.Value.Split('/').Reverse().Take(2).ToArray();
1515

1616
StreamId = pieces.LastOrDefault();
1717

18-
if(int.TryParse(pieces.FirstOrDefault(), out var streamVersion))
19-
{
20-
StreamVersion = streamVersion;
21-
}
18+
StreamVersion = int.Parse(pieces.First());
2219
}
2320

2421
public int StreamVersion { get; }

src/SqlStreamStore.HAL/Resources/StreamMessageResource.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public StreamMessageResource(IStreamStore streamStore)
2626
}
2727

2828
public async Task<Response> GetMessage(
29-
ReadStreamMessageOptions options,
29+
ReadStreamMessageByStreamVersionOptions options,
3030
CancellationToken cancellationToken)
3131
{
3232
var operation = options.GetReadOperation();
@@ -76,5 +76,17 @@ public async Task<Response> GetMessage(
7676
.AddLinks(Links.StreamMessage.Navigation(options, message))
7777
.AddLinks(Links.Stream.Feed(options)));
7878
}
79+
80+
public async Task<Response> DeleteMessage(
81+
DeleteStreamMessageOptions options,
82+
CancellationToken cancellationToken)
83+
{
84+
var operation = options.GetDeleteOperation();
85+
86+
await operation.Invoke(_streamStore, cancellationToken);
87+
88+
return new Response(
89+
new HALResponse(new HALModelConfig()));
90+
}
7991
}
8092
}

src/SqlStreamStore.HAL/SqlStreamStore.HAL.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<PackageReference Include="LibLog" Version="4.2.6" PrivateAssets="All" />
2424
<PackageReference Include="Microsoft.CSharp" Version="4.4.0" />
2525
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
26-
<PackageReference Include="SqlStreamStore" Version="1.1.0" />
26+
<PackageReference Include="SqlStreamStore" Version="1.1.2-*" />
2727
<PackageReference Include="Tavis.UriTemplates" Version="1.1.1" />
2828
</ItemGroup>
2929
</Project>

0 commit comments

Comments
 (0)