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

Implement delete endpoint for Files, Nodes, Notes, Reminders and Timelines module #41

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
64c274b
feat: implement delete file
HunorTotBagi Jan 4, 2025
a75924f
feat: implement delete `Node` endpoint
HunorTotBagi Jan 4, 2025
ad0c261
chore: rename response
HunorTotBagi Jan 4, 2025
38d41e9
chore: rename
HunorTotBagi Jan 5, 2025
ec8ca94
feat: implement delete `Note` endpoint
HunorTotBagi Jan 5, 2025
05ccb51
feat: implement delete `Reminder` endpoint
HunorTotBagi Jan 5, 2025
9229e77
feat: implement delete `Timeline` endpoint
HunorTotBagi Jan 5, 2025
e4ca881
chore: add empty lines and rename
HunorTotBagi Jan 5, 2025
4b75aa6
chore: fix formatting & delete redundant empty lines
HunorTotBagi Jan 13, 2025
679a0c4
Merge branch 'main' into feat/implement-delete-endpoint-for-all-entities
HunorTotBagi Jan 13, 2025
7a6dd85
Merge branch 'main' into feat/implement-delete-endpoint-for-all-entities
HunorTotBagi Jan 14, 2025
708dd41
feat: add validation for `Id` and variable rename
HunorTotBagi Jan 14, 2025
c8e37a4
feat: add validation for `Id` and variable rename for the rest of del…
HunorTotBagi Jan 14, 2025
f08f8e6
feat: Validate Ids sent as part of requests for the rest of the modules
HunorTotBagi Jan 14, 2025
14263e4
chore: remove variable and make adjustments to GetByIdHandlers
HunorTotBagi Jan 15, 2025
dbb5f48
chore: add empty line after ReSharper comment in GetByIdQuery files
HunorTotBagi Jan 15, 2025
208c22f
refactor: make delete commands strongly typed
HunorTotBagi Jan 15, 2025
b78fc26
Merge branch 'main' into feat/implement-delete-endpoint-for-all-entities
HunorTotBagi Jan 16, 2025
3dc8612
fix: rename class
HunorTotBagi Jan 16, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Files.Application.Entities.Files.Commands.DeleteFileAsset;

namespace Files.Api.Endpoints.Files;

public class DeleteFileAsset : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapDelete("/Files/{fileId}", async (string fileId, ISender sender) =>
{
var result = await sender.Send(new DeleteFileAssetCommand(fileId));
var response = result.Adapt<DeleteFileAssetResponse>();

return Results.Ok(response);
})
.WithName("DeleteFileAsset")
.Produces<DeleteFileAssetResponse>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Delete File Asset")
.WithDescription("Delete File Asset");
}
}

public record DeleteFileAssetResponse(bool FileDeleted);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Files.Application.Entities.Files.Commands.DeleteFileAsset;

public record DeleteFileAssetCommand(string FileAssetId) : ICommand<DeleteFileAssetResult>;

public record DeleteFileAssetResult(bool FileDeleted);

public class DeleteFileAssetCommandValidator : AbstractValidator<DeleteFileAssetCommand>
{
public DeleteFileAssetCommandValidator()
{
RuleFor(x => x.FileAssetId).NotEmpty().WithMessage("FileAssetId is required");
NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Files.Application.Entities.Files.Exceptions;

namespace Files.Application.Entities.Files.Commands.DeleteFileAsset;

public class DeleteFileAssetHandler(IFilesDbContext dbContext) : ICommandHandler<DeleteFileAssetCommand, DeleteFileAssetResult>
{
public async Task<DeleteFileAssetResult> Handle(DeleteFileAssetCommand command, CancellationToken cancellationToken)
{
var fileAsset = await dbContext.FileAssets
.AsNoTracking()
NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved
.SingleOrDefaultAsync(f => f.Id == FileAssetId.Of(Guid.Parse(command.FileAssetId)), cancellationToken);

if (fileAsset is null)
throw new FileAssetNotFoundException(command.FileAssetId);

NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved

dbContext.FileAssets.Remove(fileAsset);
await dbContext.SaveChangesAsync(cancellationToken);

return new DeleteFileAssetResult(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Nodes.Application.Entities.Nodes.Commands.DeleteNode;

namespace Nodes.Api.Endpoints.Nodes;

public class DeleteNode : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapDelete("/Nodes/{nodeId}", async (string nodeId, ISender sender) =>
{
var result = await sender.Send(new DeleteNodeCommand(nodeId));
var response = result.Adapt<DeleteNodeResponse>();

return Results.Ok(response);
})
.WithName("DeleteNode")
.Produces<DeleteNodeResponse>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Delete Node")
.WithDescription("Delete Node");
}
}

public record DeleteNodeResponse(bool NodeDeleted);
NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Nodes.Application.Entities.Nodes.Commands.DeleteNode;

public record DeleteNodeCommand(string NodeId) : ICommand<DeleteNodeResult>;

public record DeleteNodeResult(bool NodeDeleted);

public class DeleteNodeCommandValidator : AbstractValidator<DeleteNodeCommand>
{
public DeleteNodeCommandValidator()
{
RuleFor(x => x.NodeId).NotEmpty().WithMessage("NodeId is required");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Nodes.Application.Entities.Nodes.Exceptions;

namespace Nodes.Application.Entities.Nodes.Commands.DeleteNode;

public class DeleteNodeHandler(INodesDbContext dbContext) : ICommandHandler<DeleteNodeCommand, DeleteNodeResult>
{
public async Task<DeleteNodeResult> Handle(DeleteNodeCommand command, CancellationToken cancellationToken)
{
var node = await dbContext.Nodes
.AsNoTracking()
.SingleOrDefaultAsync(n => n.Id == NodeId.Of(Guid.Parse(command.NodeId)), cancellationToken);

if (node is null)
throw new NodeNotFoundException(command.NodeId);

NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved

dbContext.Nodes.Remove(node);
await dbContext.SaveChangesAsync(cancellationToken);

return new DeleteNodeResult(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Notes.Application.Entities.Notes.Commands.DeleteNote;

namespace Notes.Api.Endpoints.Notes;

public class DeleteNote : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapDelete("/Notes/{noteId}", async (string noteId, ISender sender) =>
{
var result = await sender.Send(new DeleteNoteCommand(noteId));
var response = result.Adapt<DeleteNoteResponse>();

return Results.Ok(response);
})
.WithName("DeleteNote")
.Produces<DeleteNoteResponse>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Delete Note")
.WithDescription("Delete Note");
}
}

public record DeleteNoteResponse(bool NoteDeleted);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Notes.Application.Entities.Notes.Commands.DeleteNote;

public record DeleteNoteCommand(string NoteId) : ICommand<DeleteNoteResult>;

public record DeleteNoteResult(bool NoteDeleted);

public class DeleteNoteCommandValidator : AbstractValidator<DeleteNoteCommand>
{
public DeleteNoteCommandValidator()
{
RuleFor(x => x.NoteId).NotEmpty().WithMessage("NoteId is required");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Notes.Application.Entities.Notes.Exceptions;

namespace Notes.Application.Entities.Notes.Commands.DeleteNote;

public class DeleteNoteHandler(INotesDbContext dbContext) : ICommandHandler<DeleteNoteCommand, DeleteNoteResult>
{
public async Task<DeleteNoteResult> Handle(DeleteNoteCommand command, CancellationToken cancellationToken)
{
var note = await dbContext.Notes
.AsNoTracking()
.SingleOrDefaultAsync(n => n.Id == NoteId.Of(Guid.Parse(command.NoteId)), cancellationToken);

if (note is null)
throw new NoteNotFoundException(command.NoteId);

NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved

dbContext.Notes.Remove(note);
await dbContext.SaveChangesAsync(cancellationToken);

return new DeleteNoteResult(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Reminders.Application.Entities.Reminders.Commands.DeleteReminder;

namespace Reminders.Api.Endpoints.Reminders;

public class DeleteReminder : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapDelete("/Reminders/{reminderId}", async (string reminderId, ISender sender) =>
{
var result = await sender.Send(new DeleteReminderCommand(reminderId));
var response = result.Adapt<DeleteReminderResponse>();

return Results.Ok(response);
})
.WithName("DeleteReminder")
.Produces<DeleteReminderResponse>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Delete Reminder")
.WithDescription("Delete Reminder");
}
}

public record DeleteReminderResponse(bool ReminderDeleted);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Reminders.Application.Entities.Reminders.Commands.DeleteReminder;

public record DeleteReminderCommand(string ReminderId) : ICommand<DeleteReminderResult>;

public record DeleteReminderResult(bool ReminderDeleted);

public class DeleteReminderCommandValidator : AbstractValidator<DeleteReminderCommand>
{
public DeleteReminderCommandValidator()
{
RuleFor(x => x.ReminderId).NotEmpty().WithMessage("ReminderId is required");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Reminders.Application.Entities.Reminders.Exceptions;

namespace Reminders.Application.Entities.Reminders.Commands.DeleteReminder;

public class DeleteReminderHandler(IRemindersDbContext dbContext) : ICommandHandler<DeleteReminderCommand, DeleteReminderResult>
{
public async Task<DeleteReminderResult> Handle(DeleteReminderCommand command, CancellationToken cancellationToken)
{
var reminder = await dbContext.Reminders
.AsNoTracking()
.SingleOrDefaultAsync(r => r.Id == ReminderId.Of(Guid.Parse(command.ReminderId)), cancellationToken);

if (reminder is null)
throw new ReminderNotFoundException(command.ReminderId);

NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved

dbContext.Reminders.Remove(reminder);
await dbContext.SaveChangesAsync(cancellationToken);

return new DeleteReminderResult(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Timelines.Application.Entities.Timelines.Commands.DeleteTimeline;

namespace Timelines.Api.Endpoints.Timelines;

public class DeleteTimeline : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapDelete("/Timelines/{timelineId}", async (string timelineId, ISender sender) =>
{
var result = await sender.Send(new DeleteTimelineCommand(timelineId));
var response = result.Adapt<DeleteTimelineResponse>();

return Results.Ok(response);
})
.WithName("DeleteTimeline")
.Produces<DeleteTimelineResponse>()
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithSummary("Delete Timeline")
.WithDescription("Delete Timeline");
}
}

public record DeleteTimelineResponse(bool TimelineDeleted);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Timelines.Application.Entities.Timelines.Commands.DeleteTimeline;

public record DeleteTimelineCommand(string TimelineId) : ICommand<DeleteTimelineResult>;

public record DeleteTimelineResult(bool TimelineDeleted);

public class DeleteTimelineCommandValidator : AbstractValidator<DeleteTimelineCommand>
{
public DeleteTimelineCommandValidator()
{
RuleFor(x => x.TimelineId).NotEmpty().WithMessage("TimelineId is required");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Timelines.Application.Entities.Timelines.Exceptions;

namespace Timelines.Application.Entities.Timelines.Commands.DeleteTimeline;

public class DeleteNodeHandler(ITimelinesDbContext dbContext) : ICommandHandler<DeleteTimelineCommand, DeleteTimelineResult>
Copy link
Owner

Choose a reason for hiding this comment

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

DeleteNodeHandler? 😨

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. But interesting how the naming doesn't matter it still will work, but of course I agree the naming is not correct. Changes made ✅

{
public async Task<DeleteTimelineResult> Handle(DeleteTimelineCommand command, CancellationToken cancellationToken)
{
var timeline = await dbContext.Timelines
.AsNoTracking()
NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved
.SingleOrDefaultAsync(t => t.Id == TimelineId.Of(Guid.Parse(command.TimelineId)), cancellationToken);

if (timeline is null)
throw new TimelineNotFoundException(command.TimelineId);

NikolaVetnic marked this conversation as resolved.
Show resolved Hide resolved

dbContext.Timelines.Remove(timeline);
await dbContext.SaveChangesAsync(cancellationToken);

return new DeleteTimelineResult(true);
}
}
Loading