-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
604 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
src/MyWallet/Features/Transactions/LIst/ListTransactions.Endpoint.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using MyWallet.Shared.Errors; | ||
using MyWallet.Shared.Features; | ||
|
||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed class ListTransactionEndpoint : IEndpoint | ||
{ | ||
public void Build(IEndpointRouteBuilder builder) => | ||
builder.MapGet("transactions", ListTransactionsAsync) | ||
.RequireAuthorization(); | ||
|
||
private static Task<IResult> ListTransactionsAsync( | ||
[AsParameters] ListTransactionsRequest request, | ||
ISender sender, | ||
HttpContext context, | ||
CancellationToken cancellationToken) | ||
{ | ||
return sender.Send(request.ToQuery(), cancellationToken) | ||
.ToResponseAsync(Results.Ok, context); | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
src/MyWallet/Features/Transactions/LIst/ListTransactions.Handler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using MyWallet.Domain.Wallets; | ||
using MyWallet.Shared.Features; | ||
using MyWallet.Shared.Persistence; | ||
|
||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed class ListTransactionsHandler(IWalletRepository walletRepository, IDbContext db) | ||
: IQueryHandler<ListTransactionsQuery, ListTransactionsResponse> | ||
{ | ||
public async Task<ErrorOr<ListTransactionsResponse>> Handle(ListTransactionsQuery query, | ||
CancellationToken cancellationToken) | ||
{ | ||
if (!await walletRepository.ExistsAsync(new WalletId(query.WalletId), cancellationToken)) | ||
{ | ||
return Shared.TransactionErrors.WalletNotFound; | ||
} | ||
|
||
var total = await CountTotalTransactionsAsync(query, cancellationToken); | ||
if (total is 0) | ||
{ | ||
return new ListTransactionsResponse( | ||
Items: [], | ||
Page: query.Page, | ||
Limit: query.Limit, | ||
Total: total) | ||
{ | ||
WalletId = query.WalletId, | ||
From = query.From, | ||
To = query.To | ||
}; | ||
} | ||
|
||
var transactions = await ListTransactionsAsync(query, cancellationToken); | ||
|
||
return new ListTransactionsResponse( | ||
Items: transactions, | ||
Page: query.Page, | ||
Limit: query.Limit, | ||
Total: total) | ||
{ | ||
WalletId = query.WalletId, | ||
From = query.From, | ||
To = query.To | ||
}; | ||
} | ||
|
||
private Task<int> CountTotalTransactionsAsync(ListTransactionsQuery query, | ||
CancellationToken cancellationToken) | ||
{ | ||
return db.ExecuteScalarAsync<int>( | ||
sql: """ | ||
SELECT COUNT(*) | ||
FROM transactions t | ||
WHERE t.wallet_id = @WalletId AND (t.date BETWEEN @From AND @To) | ||
""", | ||
param: query, | ||
cancellationToken); | ||
} | ||
|
||
private async Task<IEnumerable<TransactionResponse>> ListTransactionsAsync(ListTransactionsQuery query, | ||
CancellationToken cancellationToken) | ||
{ | ||
return await db.QueryAsync<TransactionResponse>( | ||
sql: """ | ||
SELECT | ||
t.id, | ||
t.type, | ||
t.name, | ||
(SELECT c.name FROM categories c WHERE c.id = t.category_id) AS category, | ||
t.amount, | ||
t.currency, | ||
t.date | ||
FROM transactions t | ||
WHERE t.wallet_id = @WalletId AND (t.date BETWEEN @From AND @To) | ||
ORDER BY t.date DESC, t.created_at DESC | ||
LIMIT @Limit OFFSET @Offset | ||
""", | ||
param: query, | ||
cancellationToken); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/MyWallet/Features/Transactions/LIst/ListTransactions.Query.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using MyWallet.Shared.Features; | ||
|
||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed record ListTransactionsQuery : IQuery<ListTransactionsResponse>, IHaveUser | ||
{ | ||
public required Ulid WalletId { get; init; } | ||
|
||
public required DateOnly From { get; init; } | ||
|
||
public required DateOnly To { get; init; } | ||
|
||
public required int Page { get; init; } | ||
|
||
public required int Limit { get; init; } | ||
|
||
public Ulid UserId { get; set; } | ||
|
||
public int Offset => (Page - 1) * Limit; | ||
} |
23 changes: 23 additions & 0 deletions
23
src/MyWallet/Features/Transactions/LIst/ListTransactions.Request.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed record ListTransactionsRequest | ||
{ | ||
public required Ulid WalletId { get; init; } | ||
|
||
public required DateOnly From { get; init; } | ||
|
||
public DateOnly? To { get; init; } | ||
|
||
public int? Page { get; init; } | ||
|
||
public int? Limit { get; init; } | ||
|
||
public ListTransactionsQuery ToQuery() => new() | ||
{ | ||
WalletId = WalletId, | ||
From = From, | ||
To = To ?? DateOnly.MaxValue, | ||
Page = Page ?? 1, | ||
Limit = Limit ?? 10 | ||
}; | ||
} |
33 changes: 33 additions & 0 deletions
33
src/MyWallet/Features/Transactions/LIst/ListTransactions.Response.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using MyWallet.Shared.Contracts; | ||
|
||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed record TransactionResponse | ||
{ | ||
public required Ulid Id { get; init; } | ||
|
||
public required string Type { get; init; } | ||
|
||
public required string Name { get; init; } | ||
|
||
public required string Category { get; init; } | ||
|
||
public required decimal Amount { get; init; } | ||
|
||
public required string Currency { get; init; } | ||
|
||
public required DateOnly Date { get; init; } | ||
} | ||
|
||
public sealed record ListTransactionsResponse( | ||
IEnumerable<TransactionResponse> Items, | ||
int Page, | ||
int Limit, | ||
int Total) : PageResponse<TransactionResponse>(Items, Page, Limit, Total) | ||
{ | ||
public required Ulid WalletId { get; init; } | ||
|
||
public required DateOnly From { get; init; } | ||
|
||
public required DateOnly To { get; init; } | ||
} |
11 changes: 11 additions & 0 deletions
11
src/MyWallet/Features/Transactions/LIst/ListTransactions.Security.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using MyWallet.Shared.Security; | ||
|
||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed class ListTransactionsSecurity : IAuthorizer<ListTransactionsQuery> | ||
{ | ||
public IEnumerable<IRequirement> GetRequirements(ListTransactionsQuery query) | ||
{ | ||
yield return new WalletOwnerRequirement(query.UserId, query.WalletId); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/MyWallet/Features/Transactions/LIst/ListTransactions.Validator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using MyWallet.Shared.Validations; | ||
|
||
namespace MyWallet.Features.Transactions.List; | ||
|
||
public sealed class ListTransactionsValidator : AbstractValidator<ListTransactionsQuery> | ||
{ | ||
public ListTransactionsValidator() | ||
{ | ||
RuleFor(q => q.To) | ||
.Must((query, to) => query.From <= to) | ||
.WithMessage("Must be greater than or equal to 'from' date."); | ||
|
||
RuleFor(q => q.Page) | ||
.PageNumber(); | ||
|
||
RuleFor(q => q.Limit) | ||
.PageLimit(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
GET {{baseUrl}}/transactions?walletId=01J5GXMBHYMZAT9YN8H7J3DS4J&from=2024-08-17 | ||
Authorization: Bearer {{accessToken}} |
Oops, something went wrong.