Skip to content

Projection extension #16

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

Merged
merged 22 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cedba45
added properties to Member
CengoleFHV Jun 4, 2024
abedb21
added properties to Member
CengoleFHV Jun 4, 2024
ad9fd81
expanded Member props and added MEMBER_UPDATED Event
CengoleFHV Jun 5, 2024
7394b9e
Merge remote-tracking branch 'origin/projection_extension' into proje…
CengoleFHV Jun 5, 2024
5497c10
changed fom updatedEvent to Email and FullName Event
CengoleFHV Jun 5, 2024
93bff8c
added properties to Member
CengoleFHV Jun 4, 2024
e0bc0f3
expanded Member props and added MEMBER_UPDATED Event
CengoleFHV Jun 5, 2024
eaba781
changed fom updatedEvent to Email and FullName Event
CengoleFHV Jun 5, 2024
f4a0375
Merge branch 'projection_extension' of https://github.com/THC-Softwar…
CengoleFHV Jun 6, 2024
9baa887
added Club Name Changed Event
CengoleFHV Jun 6, 2024
7c68828
added properties to Member
CengoleFHV Jun 4, 2024
9e41f2e
expanded Member props and added MEMBER_UPDATED Event
CengoleFHV Jun 5, 2024
5d29c3e
changed fom updatedEvent to Email and FullName Event
CengoleFHV Jun 5, 2024
1f04ba9
expanded Member props and added MEMBER_UPDATED Event
CengoleFHV Jun 5, 2024
107660c
changed fom updatedEvent to Email and FullName Event
CengoleFHV Jun 5, 2024
b0d6332
added Club Name Changed Event
CengoleFHV Jun 6, 2024
a71eb09
Merge branch 'projection_extension' of https://github.com/THC-Softwar…
CengoleFHV Jun 7, 2024
c512c3d
fixed tests
CengoleFHV Jun 7, 2024
1c99417
Merge branch 'dev' into projection_extension
CengoleFHV Jun 7, 2024
a148ea3
fixed tests (again)
CengoleFHV Jun 7, 2024
ce1cdbe
added Unit Tests
CengoleFHV Jun 7, 2024
f3a7093
added Handles for new Member and Club Events
CengoleFHV Jun 7, 2024
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
25 changes: 13 additions & 12 deletions Application/RedisClubStreamService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.Text.Json.Nodes;
using MediatR;
using PlayOfferService.Domain.Events;
using PlayOfferService.Domain.Repositories;
using StackExchange.Redis;
using System.Text.Json.Nodes;

namespace PlayOfferService.Application;

Expand All @@ -13,8 +12,8 @@ public class RedisClubStreamService : BackgroundService
private readonly IDatabase _db;
private const string StreamName = "club_service_events.public.DomainEvent";
private const string GroupName = "pos.club.events.group";


public RedisClubStreamService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
Expand All @@ -28,13 +27,13 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();

if (!(await _db.KeyExistsAsync(StreamName)) ||
(await _db.StreamGroupInfoAsync(StreamName)).All(x=>x.Name!=GroupName))
(await _db.StreamGroupInfoAsync(StreamName)).All(x => x.Name != GroupName))
{
await _db.StreamCreateConsumerGroupAsync(StreamName, GroupName, "0-0");
}


var id = string.Empty;
while (!_cancellationToken.IsCancellationRequested)
Expand All @@ -58,24 +57,26 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
}

}

private TechnicalClubEvent? FilterandParseEvent(StreamEntry value)
{
var dict = value.Values.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
var jsonContent = JsonNode.Parse(dict.Values.First());
var eventInfo = jsonContent["payload"]["after"];

var eventType = eventInfo["eventType"].GetValue<string>();
var entityType = eventInfo["entityType"].GetValue<string>();

if ((eventType != "TENNIS_CLUB_REGISTERED"
&& eventType != "TENNIS_CLUB_LOCKED"
&& eventType != "TENNIS_CLUB_UNLOCKED"
&& eventType != "TENNIS_CLUB_DELETED") || entityType != "TENNIS_CLUB")
&& eventType != "TENNIS_CLUB_DELETED"
&& eventType != "TENNIS_CLUB_NAME_CHANGED"
) || entityType != "TENNIS_CLUB")
{
return null;
}

return EventParser.ParseEvent<TechnicalClubEvent>(eventInfo);
}
}
10 changes: 8 additions & 2 deletions Application/RedisMemberStreamService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,16 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
var eventType = eventInfo["eventType"].GetValue<string>();
var entityType = eventInfo["entityType"].GetValue<string>();

if ((eventType != "MEMBER_REGISTERED"
if (
(eventType != "MEMBER_REGISTERED"
&& eventType != "MEMBER_DELETED"
&& eventType != "MEMBER_LOCKED"
&& eventType != "MEMBER_UNLOCKED") || entityType != "MEMBER")
&& eventType != "MEMBER_UNLOCKED"
&& eventType != "MEMBER_EMAIL_CHANGED"
&& eventType != "MEMBER_FULL_NAME_CHANGED"
)
|| entityType != "MEMBER"
)
{
return null;
}
Expand Down
16 changes: 8 additions & 8 deletions Domain/DbReadContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,28 @@ public class DbReadContext : DbContext
public DbReadContext(DbContextOptions<DbReadContext> options) : base(options)
{
}

public DbSet<PlayOffer> PlayOffers { get; set; }
public DbSet<Club> Clubs { get; set; }
public DbSet<Member> Members { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<Court> Courts { get; set; }
public DbSet<BaseEvent> AppliedEvents { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new BaseEventConfiguration());

// TODO: Remove before coop testing
var testClub = new Club{Id = Guid.Parse("06b812a7-5131-4510-82ff-bffac33e0f3e"), Status = Status.ACTIVE};
var testMemberIds = new List<Guid> {Guid.Parse("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), Guid.Parse("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d")};
var testClub = new Club { Id = Guid.Parse("06b812a7-5131-4510-82ff-bffac33e0f3e"), Name = "Test Club", Status = Status.ACTIVE };
var testMemberIds = new List<Guid> { Guid.Parse("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), Guid.Parse("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d") };

var testMembers = new List<Object>{
new {Id = testMemberIds[0], ClubId = testClub.Id, Status = Status.ACTIVE},
new {Id = testMemberIds[1], ClubId = testClub.Id, Status = Status.ACTIVE}
};

// Need to directly specify foreign keys for seeding
var testPlayOffer = new
{
Expand All @@ -42,7 +42,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
ProposedEndTime = DateTime.UtcNow.AddHours(1),
IsCancelled = false
};

modelBuilder.Entity<Club>().HasData(testClub);
foreach (var testMember in testMembers)
{
Expand Down
6 changes: 6 additions & 0 deletions Domain/Events/Club/ClubNameChangedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace PlayOfferService.Domain.Events.Club;

public class ClubNameChangedEvent : DomainEvent
{
public string Name { get; set; }
}
6 changes: 5 additions & 1 deletion Domain/Events/DomainEvent.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System.Text.Json.Serialization;
using PlayOfferService.Domain.Events.Club;
using PlayOfferService.Domain.Events.Court;
using PlayOfferService.Domain.Events.Member;
using PlayOfferService.Domain.Events.PlayOffer;
using PlayOfferService.Domain.Events.Reservation;
using System.Text.Json.Serialization;

namespace PlayOfferService.Domain.Events;

Expand All @@ -11,10 +12,13 @@ namespace PlayOfferService.Domain.Events;
[JsonDerivedType(typeof(ClubLockedEvent), typeDiscriminator: "TENNIS_CLUB_LOCKED")]
[JsonDerivedType(typeof(ClubUnlockedEvent), typeDiscriminator: "TENNIS_CLUB_UNLOCKED")]
[JsonDerivedType(typeof(ClubDeletedEvent), typeDiscriminator: "TENNIS_CLUB_DELETED")]
[JsonDerivedType(typeof(ClubNameChangedEvent), typeDiscriminator: "TENNIS_CLUB_NAME_CHANGED")]
[JsonDerivedType(typeof(MemberCreatedEvent), typeDiscriminator: "MEMBER_REGISTERED")]
[JsonDerivedType(typeof(MemberLockedEvent), typeDiscriminator: "MEMBER_LOCKED")]
[JsonDerivedType(typeof(MemberUnlockedEvent), typeDiscriminator: "MEMBER_UNLOCKED")]
[JsonDerivedType(typeof(MemberDeletedEvent), typeDiscriminator: "MEMBER_DELETED")]
[JsonDerivedType(typeof(MemberEmailChangedEvent), typeDiscriminator: "MEMBER_EMAIL_CHANGED")]
[JsonDerivedType(typeof(MemberFullNameChangedEvent), typeDiscriminator: "MEMBER_FULL_NAME_CHANGED")]
[JsonDerivedType(typeof(PlayOfferCreatedEvent), typeDiscriminator: "PLAYOFFER_CREATED")]
[JsonDerivedType(typeof(PlayOfferJoinedEvent), typeDiscriminator: "PLAYOFFER_JOINED")]
[JsonDerivedType(typeof(PlayOfferCancelledEvent), typeDiscriminator: "PLAYOFFER_CANCELLED")]
Expand Down
3 changes: 3 additions & 0 deletions Domain/Events/EventType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ public enum EventType
TENNIS_CLUB_LOCKED,
TENNIS_CLUB_UNLOCKED,
TENNIS_CLUB_DELETED,
TENNIS_CLUB_NAME_CHANGED,
MEMBER_REGISTERED,
MEMBER_LOCKED,
MEMBER_UNLOCKED,
MEMBER_DELETED,
MEMBER_EMAIL_CHANGED,
MEMBER_FULL_NAME_CHANGED,
ReservationCreatedEvent,
ReservationRejectedEvent,
ReservationLimitExceeded,
Expand Down
6 changes: 6 additions & 0 deletions Domain/Events/Member/MemberEmailChangedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace PlayOfferService.Domain.Events.Member;

public class MemberEmailChangedEvent : DomainEvent
{
public string Email { get; set; }
}
8 changes: 8 additions & 0 deletions Domain/Events/Member/MemberFullNameChangedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using PlayOfferService.Domain.ValueObjects;

namespace PlayOfferService.Domain.Events.Member;

public class MemberFullNameChangedEvent : DomainEvent
{
public FullName FullName { get; set; }
}
23 changes: 17 additions & 6 deletions Domain/Models/Club.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System.ComponentModel.DataAnnotations.Schema;
using PlayOfferService.Domain.Events;
using PlayOfferService.Domain.Events.Club;
using System.ComponentModel.DataAnnotations.Schema;

namespace PlayOfferService.Domain.Models;

public class Club
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public string Name { get; set; }
public Status Status { get; set; }

public void Apply(List<BaseEvent> baseEvents)
Expand All @@ -16,7 +18,7 @@ public void Apply(List<BaseEvent> baseEvents)
switch (baseEvent.EventType)
{
case EventType.TENNIS_CLUB_REGISTERED:
ApplyClubCreatedEvent((ClubCreatedEvent) baseEvent.EventData);
ApplyClubCreatedEvent((ClubCreatedEvent)baseEvent.EventData);
break;
case EventType.TENNIS_CLUB_LOCKED:
ApplyClubLockedEvent();
Expand All @@ -27,29 +29,38 @@ public void Apply(List<BaseEvent> baseEvents)
case EventType.TENNIS_CLUB_DELETED:
ApplyClubDeletedEvent();
break;
case EventType.TENNIS_CLUB_NAME_CHANGED:
ApplyClubNameChangedEvent((ClubNameChangedEvent)baseEvent.EventData);
break;
default:
throw new ArgumentOutOfRangeException($"{nameof(baseEvent.EventType)} is not supported for the entity Club!");
}
}
}

private void ApplyClubCreatedEvent(ClubCreatedEvent domainEvent)
{
Id = domainEvent.TennisClubId.Id;
Name = domainEvent.Name;
}

private void ApplyClubLockedEvent()
{
Status = Status.LOCKED;
}

private void ApplyClubUnlockedEvent()
{
Status = Status.ACTIVE;
}

private void ApplyClubDeletedEvent()
{
Status = Status.DELETED;
}

private void ApplyClubNameChangedEvent(ClubNameChangedEvent domainEvent)
{
Name = domainEvent.Name;
}
}
41 changes: 32 additions & 9 deletions Domain/Models/Member.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ public class Member
{
public Guid Id { get; set; }
public Guid ClubId { get; set; }


public string? Email { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }

public Status Status { get; set; }

public void Apply(List<BaseEvent> baseEvents)
{
foreach (var baseEvent in baseEvents)
{
switch (baseEvent.EventType)
{
case EventType.MEMBER_REGISTERED:
Apply((MemberCreatedEvent) baseEvent.EventData);
Apply((MemberCreatedEvent)baseEvent.EventData);
break;
case EventType.MEMBER_LOCKED:
ApplyMemberLockedEvent();
Expand All @@ -28,29 +31,49 @@ public void Apply(List<BaseEvent> baseEvents)
case EventType.MEMBER_DELETED:
ApplyMemberDeletedEvent();
break;
case EventType.MEMBER_EMAIL_CHANGED:
ApplyMemberEmailChangedEvent((MemberEmailChangedEvent)baseEvent.EventData);
break;
case EventType.MEMBER_FULL_NAME_CHANGED:
ApplyMemberFullNameChangedEvent((MemberFullNameChangedEvent)baseEvent.EventData);
break;
default:
throw new ArgumentOutOfRangeException($"{nameof(baseEvent.EventType)} is not supported for the entity Member!");
throw new ArgumentOutOfRangeException(
$"{nameof(baseEvent.EventType)} is not supported for the entity Member!");
}
}
}


private void ApplyMemberEmailChangedEvent(MemberEmailChangedEvent baseEventEventData)
{
Email = baseEventEventData.Email;
}

private void ApplyMemberFullNameChangedEvent(MemberFullNameChangedEvent baseEventEventData)
{
FirstName = baseEventEventData.FullName.FirstName;
LastName = baseEventEventData.FullName.LastName;
}

private void Apply(MemberCreatedEvent domainEvent)
{
Id = domainEvent.MemberId.Id;
Email = domainEvent.Email;
FirstName = domainEvent.Name.FirstName;
LastName = domainEvent.Name.LastName;
ClubId = domainEvent.TennisClubId.Id;
Status = domainEvent.Status;
}

private void ApplyMemberLockedEvent()
{
Status = Status.LOCKED;
}

private void ApplyMemberUnlockedEvent()
{
Status = Status.ACTIVE;
}

private void ApplyMemberDeletedEvent()
{
Status = Status.DELETED;
Expand Down
Loading
Loading