Skip to content

Commit 662000d

Browse files
committed
Add Article and Metadata APIs; enhance service registration
- Added new /api/articles endpoint with paging, sorting, and include support - Introduced /api/metadata/entities/{name}/whitelist for entity metadata - Registered attribute whitelist scanning and metadata services for relevant assemblies - Improved API grouping and organization in Program.cs
1 parent 4dd4014 commit 662000d

1 file changed

Lines changed: 85 additions & 2 deletions

File tree

samples/TinyRepository.Sample/Program.cs

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
using Microsoft.EntityFrameworkCore;
33
using Microsoft.EntityFrameworkCore.Diagnostics;
44
using Microsoft.Net.Http.Headers;
5+
using TinyRepository.DTOs;
56
using TinyRepository.Ef;
67
using TinyRepository.Extensions;
8+
using TinyRepository.Interfaces;
9+
using TinyRepository.Metadata.Interfaces;
10+
using TinyRepository.Paging;
711
using TinyRepository.Sample.DTOs;
812
using TinyRepository.Sample.Entities;
913
using TinyRepository.Sample.Services;
@@ -39,10 +43,12 @@ public static void Main(string[] args)
3943
//options.ConfigureWarnings(warnings => warnings.Ignore(RelationalEventId.PendingModelChangesWarning));
4044
});
4145

42-
//builder.Services.AddAttributeWhitelistScan(typeof(SampleEntity).Assembly);
4346
builder.Services.AddRepositoryPattern<AppDbContext>();
47+
4448
// scan attributi nell'assembly di dominio con maxDepth = 3
45-
builder.Services.AddAttributeWhitelistScan(opt => opt.MaxDepth = 3, typeof(SampleEntity).Assembly);
49+
//builder.Services.AddAttributeWhitelistScan(typeof(SampleEntity).Assembly);
50+
builder.Services.AddAttributeWhitelistScan(opt => opt.MaxDepth = 4, typeof(Article).Assembly);
51+
builder.Services.AddMetadataService(typeof(Author).Assembly);
4652

4753
builder.Services.AddTransient<ISampleService, SampleService>();
4854
builder.Services.AddEndpointsApiExplorer();
@@ -77,6 +83,8 @@ public static void Main(string[] args)
7783
app.UseRouting();
7884
app.UseCors();
7985

86+
#region "Sample API"
87+
8088
var exampleApi = app.MapGroup("/api/example")
8189
.WithDescription("Example APIs for TinyRepository")
8290
.WithTags("Example APIs");
@@ -108,6 +116,81 @@ public static void Main(string[] args)
108116
.Produces<Created<SampleEntity>>(StatusCodes.Status201Created)
109117
.ProducesProblem(StatusCodes.Status400BadRequest);
110118

119+
#endregion
120+
121+
#region "Article API"
122+
123+
var articleApi = app.MapGroup("/api/articles")
124+
.WithDescription("Article APIs for TinyRepository")
125+
.WithTags("Article APIs");
126+
127+
// endpoint demo con alias e include parsing
128+
app.MapGet("/articles", async (IRepository<Article, int> repo, HttpRequest req) =>
129+
{
130+
// include param: comma separated (can be alias)
131+
var includeQuery = req.Query["include"].ToString();
132+
var includePaths = string.IsNullOrWhiteSpace(includeQuery) ? [] : includeQuery.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
133+
134+
var page = int.TryParse(req.Query["page"], out var p) ? Math.Max(1, p) : 1;
135+
var pageSize = int.TryParse(req.Query["pageSize"], out var ps) ? Math.Clamp(ps, 1, 100) : 10;
136+
137+
var useSplit = bool.TryParse(req.Query["split"], out var s) && s;
138+
139+
// sort param: alias or property, direction param "asc" or "desc"
140+
var sort = req.Query["sort"].ToString();
141+
var dir = req.Query["dir"].ToString() ?? "asc";
142+
var descending = string.Equals(dir, "desc", StringComparison.OrdinalIgnoreCase);
143+
144+
PagedResult<Article> pageResult;
145+
if (!string.IsNullOrWhiteSpace(sort))
146+
{
147+
pageResult = await repo.GetPagedTwoStageAsync(page, pageSize,
148+
orderByProperty: sort,
149+
descending: descending,
150+
filter: null,
151+
asNoTracking: true,
152+
cancellationToken: default,
153+
useAsSplitQuery: useSplit,
154+
includePaths: includePaths);
155+
}
156+
else
157+
{
158+
pageResult = await repo.GetPagedTwoStageAsync(page, pageSize,
159+
sortDescriptors: [Sorting.SortDescriptor.Asc("Title")],
160+
filter: null,
161+
asNoTracking: true,
162+
cancellationToken: default,
163+
useAsSplitQuery: useSplit,
164+
includePaths: includePaths);
165+
}
166+
167+
return Results.Ok(new { pageResult.TotalCount, pageResult.PageNumber, pageResult.PageSize, pageResult.Items });
168+
});
169+
170+
#endregion
171+
172+
#region "Metadata API"
173+
174+
var metadataApi = app.MapGroup("/api/metadata")
175+
.WithDescription("Metadata APIs for TinyRepository")
176+
.WithTags("Metadata APIs");
177+
178+
metadataApi.MapGet("/entities/{name}/whitelist", async (string name, IMetadataService metadata) =>
179+
{
180+
var dto = await metadata.GetEntityWhitelistAsync(name);
181+
if (dto == null)
182+
{
183+
return Results.NotFound(new { message = $"Entity '{name}' not found in scanned assemblies." });
184+
}
185+
186+
return Results.Ok(dto);
187+
})
188+
.WithName("GetEntityWhitelist")
189+
.Produces<EntityWhitelistDto>(StatusCodes.Status200OK)
190+
.Produces(StatusCodes.Status404NotFound);
191+
192+
#endregion
193+
111194
app.Run();
112195
}
113196
}

0 commit comments

Comments
 (0)