Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added Stream type #18

Merged
merged 11 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 4 additions & 32 deletions samples/EvenireDB.Samples.TemperatureSensors/Program.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
using EvenireDB.Client;
using EvenireDB.Common;
using EvenireDB.Samples.TemperatureSensors;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;


var builder = WebApplication.CreateBuilder(args);

var connectionString = new Uri(builder.Configuration.GetConnectionString("evenire"));

Check warning on line 9 in samples/EvenireDB.Samples.TemperatureSensors/Program.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'uriString' in 'Uri.Uri(string uriString)'.

var settings = builder.Configuration.GetSection("Settings").Get<Settings>();

var clientConfig = builder.Configuration.GetSection("Evenire").Get<EvenireClientConfig>();

builder.Services.AddHostedService<SensorsFakeProducer>()

Check warning on line 15 in samples/EvenireDB.Samples.TemperatureSensors/Program.cs

View workflow job for this annotation

GitHub Actions / build

The type 'EvenireDB.Samples.TemperatureSensors.Settings?' cannot be used as type parameter 'TService' in the generic type or method 'ServiceCollectionServiceExtensions.AddSingleton<TService>(IServiceCollection, TService)'. Nullability of type argument 'EvenireDB.Samples.TemperatureSensors.Settings?' doesn't match 'class' constraint.
.AddSingleton(settings)
.AddEvenireDB(clientConfig);

Check warning on line 17 in samples/EvenireDB.Samples.TemperatureSensors/Program.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'config' in 'IServiceCollection ServiceCollectionExtensions.AddEvenireDB(IServiceCollection services, EvenireClientConfig config)'.

var app = builder.Build();

Expand All @@ -32,7 +33,8 @@
app.MapGet("/sensors/{sensorId}", async ([FromServices] IEventsClient client, Guid sensorId) =>
{
var events = new List<Event>();
await foreach(var item in client.ReadAsync(sensorId, StreamPosition.End, Direction.Backward).ConfigureAwait(false))
var streamId = new StreamId(sensorId, nameof(Sensor));
await foreach(var item in client.ReadAsync(streamId, StreamPosition.End, Direction.Backward).ConfigureAwait(false))
events.Add(item);

if (events.Count() == 0)
Expand All @@ -43,33 +45,3 @@
});

app.Run();

public record Sensor
{
private Sensor(Guid id, Reading[]? readings)
{
this.Id = id;
this.Readings = readings ?? [];

this.Average = this.Readings.Select(r => r.Temperature).Average();
}

public Guid Id { get; }

public Reading[] Readings { get; }

public double Average { get; }

public static Sensor Create(Guid id, IEnumerable<Event> events)
{
var readings = events.Where(evt => evt.Type == "ReadingReceived")
.Select(evt => JsonSerializer.Deserialize<Reading>(evt.Data.Span))
.ToArray();

return new Sensor(id, readings);
}
}

public record Reading(double Temperature, DateTimeOffset When);

public record ReadingReceived(double Temperature, DateTimeOffset When);
3 changes: 3 additions & 0 deletions samples/EvenireDB.Samples.TemperatureSensors/Reading.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace EvenireDB.Samples.TemperatureSensors;

public record Reading(double Temperature, DateTimeOffset When);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace EvenireDB.Samples.TemperatureSensors;

public record ReadingReceived(double Temperature, DateTimeOffset When);
30 changes: 30 additions & 0 deletions samples/EvenireDB.Samples.TemperatureSensors/Sensor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using EvenireDB.Client;
using System.Text.Json;

namespace EvenireDB.Samples.TemperatureSensors;

public record Sensor
{
private Sensor(Guid id, Reading[]? readings)
{
this.Id = id;
this.Readings = readings ?? [];

this.Average = this.Readings.Select(r => r.Temperature).Average();
}

public Guid Id { get; }

public Reading[] Readings { get; }

public double Average { get; }

public static Sensor Create(Guid id, IEnumerable<Event> events)
{
var readings = events.Where(evt => evt.Type == "ReadingReceived")
.Select(evt => JsonSerializer.Deserialize<Reading>(evt.Data.Span))
.ToArray();

return new Sensor(id, readings);

Check warning on line 28 in samples/EvenireDB.Samples.TemperatureSensors/Sensor.cs

View workflow job for this annotation

GitHub Actions / build

Argument of type 'Reading?[]' cannot be used for parameter 'readings' of type 'Reading[]' in 'Sensor.Sensor(Guid id, Reading[]? readings)' due to differences in the nullability of reference types.
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using EvenireDB.Client;
using EvenireDB.Common;

namespace EvenireDB.Samples.TemperatureSensors;

public class SensorsFakeProducer : BackgroundService
{
Expand All @@ -19,7 +22,10 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
foreach (var sensorId in _sensorConfig.SensorIds)
{
var reading = new ReadingReceived(Random.Shared.NextDouble() * 100, DateTimeOffset.UtcNow);
await _eventsClient.AppendAsync(sensorId, new[]

var streamId = new StreamId(sensorId, nameof(Sensor));

await _eventsClient.AppendAsync(streamId, new[]
{
EventData.Create(reading),
}, stoppingToken);
Expand Down
6 changes: 4 additions & 2 deletions samples/EvenireDB.Samples.TemperatureSensors/Settings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
public record Settings
namespace EvenireDB.Samples.TemperatureSensors;

public record Settings
{
public Guid[] SensorIds { get; init; }

Check warning on line 5 in samples/EvenireDB.Samples.TemperatureSensors/Settings.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'SensorIds' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
}
7 changes: 7 additions & 0 deletions src/EvenireDB.AdminUI/AlertTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public enum AlertTypes
{
Info,
Success,
Warning,
Danger
}
7 changes: 7 additions & 0 deletions src/EvenireDB.AdminUI/Extensions/StreamIdExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using EvenireDB.Common;

public static class StreamIdExtensions
{
public static string ToFriendlyString(this StreamId streamId)
=> $"{streamId.Type}/{streamId.Key}";
}
2 changes: 1 addition & 1 deletion src/EvenireDB.AdminUI/OperationStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
Processing,
Success,
Failure
}
}
26 changes: 22 additions & 4 deletions src/EvenireDB.AdminUI/Pages/NewStream.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,37 @@

<h1>Create Stream</h1>

<SendEvents StreamId="@_streamId" OnEventSent="OnStreamCreated"></SendEvents>
<form>
<div class="form-group row">
<label for="streamType" class="col-sm-2 col-form-label">Stream Type</label>
<div class="col-sm-10">
<input type="text" required class="form-control" placeholder="Stream Type" id="streamType" @bind-value="_streamType">
</div>
</div>
</form>

@if (!string.IsNullOrWhiteSpace(_streamType))
{
<SendEvents StreamId="@_streamId" OnEventSent="OnStreamCreated"></SendEvents>
}else{
<Alert Type="AlertTypes.Warning">Set the Stream Type to continue</Alert>
}

@code{
private Guid _streamId;
private Guid _streamKey;
private string _streamType;

private StreamId _streamId => new StreamId(_streamKey, _streamType);

protected override void OnInitialized()
{
_streamId = Guid.NewGuid();
_streamKey = Guid.NewGuid();
base.OnInitialized();
}

private void OnStreamCreated()
{
NavigationManager.NavigateTo($"/streams/{_streamId}");
var url = RoutingUtils.StreamDetails(_streamId);
NavigationManager.NavigateTo(url);
}
}
75 changes: 47 additions & 28 deletions src/EvenireDB.AdminUI/Pages/StreamDetails.razor
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
@page "/streams/{Id:guid}"
@page "/streams/{Type}/{Key:guid}"
@inject EvenireDB.Client.IStreamsClient streamsClient
@inject EvenireDB.Client.IEventsClient eventsClient

<PageTitle>Stream Details</PageTitle>

<h1>Stream Details</h1>
@if (_stream is not null)
{
if (_stream.IsCached)
{
<span class="badge badge-info">cached</span>
}
else
{
<span class="badge badge-secondary">not cached</span>
}
}

@if (_status == OperationStatus.Processing)
{
Expand All @@ -14,36 +25,36 @@ else if (_status == OperationStatus.Success && _stream != null)
{
<form>
<div class="form-group row">
<label for="streamId" class="col-sm-2 col-form-label">Id</label>
<div class="col-sm-10">
<input type="text" readonly class="form-control-plaintext" id="streamId" value="@_stream.StreamId">
@if (_stream.IsCached)
{
<span class="badge badge-info">cached</span>
}
else
{
<span class="badge badge-secondary">not cached</span>
}
<label for="streamId" class="col-md-2 col-form-label">Key</label>
<div class="col-md-4">
<input type="text" readonly class="form-control" id="streamId" value="@_stream.Id.Key">
</div>
</div>
<div class="form-group row">
<label for="eventsCount" class="col-sm-2 col-form-label">Events #</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="eventsCount" placeholder="@_stream.EventsCount">

<label for="streamType" class="col-md-2 col-form-label">Type</label>
<div class="col-md-4">
<input type="text" readonly class="form-control" id="streamType" value="@_stream.Id.Type">
</div>
</div>

<div class="form-group row">
<label for="createdAt" class="col-sm-2 col-form-label">Created at</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="createdAt" placeholder="@_stream.CreatedAt">
<label for="createdAt" class="col-md-2 col-form-label">Created at</label>
<div class="col-md-4">
<input type="text" readonly class="form-control" id="createdAt" value="@_stream.CreatedAt">
</div>

<label for="lastAccessedAt" class="col-sm-2 col-form-label">Last accessed at</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="lastAccessedAt" placeholder="@_stream.LastAccessedAt">
<label for="lastAccessedAt" class="col-md-2 col-form-label">Last accessed at</label>
<div class="col-md-4">
<input type="text" readonly class="form-control" id="lastAccessedAt" value="@_stream.LastAccessedAt">
</div>
</div>

<div class="form-group row">
<label for="eventsCount" class="col-md-2 col-form-label">Events #</label>
<div class="col-md-10">
<input type="text" readonly class="form-control" id="eventsCount" value="@_stream.EventsCount">
</div>
</div>

</form>

<div id="streamDetailsAccordion">
Expand All @@ -60,7 +71,7 @@ else if (_status == OperationStatus.Success && _stream != null)

<div id="stream-events-body" class="collapse" aria-labelledby="stream-events">
<div class="card-body">
<StreamEvents StreamId="@_stream.StreamId" @ref="_streamEvents"></StreamEvents>
<StreamEvents StreamId="@_stream.Id" @ref="_streamEvents"></StreamEvents>
</div>
</div>
</div>
Expand All @@ -77,7 +88,7 @@ else if (_status == OperationStatus.Success && _stream != null)

<div id="send-events-body" class="collapse show" aria-labelledby="send-events-head">
<div class="card-body">
<SendEvents StreamId="@_stream.StreamId" OnEventSent="RefreshDataAsync"></SendEvents>
<SendEvents StreamId="@_stream.Id" OnEventSent="RefreshDataAsync"></SendEvents>
</div>
</div>
</div>
Expand All @@ -99,7 +110,12 @@ else if (_status == OperationStatus.Failure)
private StreamEvents _streamEvents;

[Parameter]
public Guid Id { get; set; }
public Guid Key { get; set; }

[Parameter]
public string Type { get; set; }

private StreamId StreamId => new StreamId(Key, Type);

protected override async Task OnParametersSetAsync()
{
Expand All @@ -113,9 +129,12 @@ else if (_status == OperationStatus.Failure)
_stream = null;
_streamEvents?.Reset();

if (string.IsNullOrWhiteSpace(this.Type))
return;

try
{
_stream = await streamsClient.GetStreamInfoAsync(this.Id);
_stream = await streamsClient.GetStreamInfoAsync(this.StreamId);

_status = OperationStatus.Success;
}
Expand All @@ -124,7 +143,7 @@ else if (_status == OperationStatus.Failure)
_status = OperationStatus.Failure;
}

if(_streamEvents is not null)
if (_streamEvents is not null)
await _streamEvents!.FetchEventsAsync();
}
}
1 change: 1 addition & 0 deletions src/EvenireDB.AdminUI/Pages/Streams.razor
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Type</th>
<th scope="col">Events #</th>
<th scope="col">Is Cached</th>
<th scope="col">Created on</th>
Expand Down
7 changes: 7 additions & 0 deletions src/EvenireDB.AdminUI/RoutingUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using EvenireDB.Common;

public static class RoutingUtils
{
public static string StreamDetails(StreamId streamId)
=> $"streams/{streamId.Type}/{streamId.Key}";
}
11 changes: 11 additions & 0 deletions src/EvenireDB.AdminUI/Shared/Alert.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="alert alert-@(Type.ToString().ToLower()) show" role="alert">
@ChildContent
</div>

@code{
[Parameter]
public RenderFragment? ChildContent { get; set; }

[Parameter]
public AlertTypes Type { get; set; } = AlertTypes.Success;
}
Loading
Loading