Skip to content
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
47 changes: 47 additions & 0 deletions sample/FastEndpoints/Source/EFModel/BlogContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel
{
using Microsoft.EntityFrameworkCore;
using System;

public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }

public BlogContext() : base()
{
}

public BlogContext(DbContextOptions options) : base(options)
{
}

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

modelBuilder.Entity<Post>()
.HasData(new Post()
{
Id = 1,
Title = Guid.NewGuid().ToString(),
Content = Guid.NewGuid().ToString(),
CreatedOn = DateTime.UtcNow,
IsVisible = true
}, new Post()
{
Id = 2,
Title = Guid.NewGuid().ToString(),
Content = Guid.NewGuid().ToString(),
CreatedOn = DateTime.UtcNow,
IsVisible = false
}, new Post()
{
Id = 3,
Title = Guid.NewGuid().ToString(),
Content = Guid.NewGuid().ToString(),
CreatedOn = DateTime.UtcNow,
IsVisible = true
});
}
}
}
15 changes: 15 additions & 0 deletions sample/FastEndpoints/Source/EFModel/Post.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel
{
using System;

public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public bool IsVisible { get; set; }
public int AmtLikes { get; set; }
public int AmtComments { get; set; }
public DateTime CreatedOn { get; set; }
}
}
18 changes: 12 additions & 6 deletions sample/FastEndpoints/Source/FastEndpointsNet9.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@
<RootNamespace>Panner.AspNetCore.Samples.FastEndpointsNet9</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FastEndpoints" Version="6.0.0"/>
<PackageReference Include="FastEndpoints.Generator" Version="6.0.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive"/>
<PackageReference Include="FastEndpoints.Security" Version="6.0.0"/>
<PackageReference Include="FastEndpoints.Swagger" Version="6.0.0"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FastEndpoints" Version="6.0.0" />
<PackageReference Include="FastEndpoints.Generator" Version="6.0.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="FastEndpoints.Security" Version="6.0.0" />
<PackageReference Include="FastEndpoints.Swagger" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.6" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Panner.AspNetCore.csproj" />
</ItemGroup>

</Project>
39 changes: 39 additions & 0 deletions sample/FastEndpoints/Source/Features/Posts/Endpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore;
using Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel;
using Panner.AspNetCore.Samples.FastEndpointsNet9.PannerExtensions;

namespace Posts;

sealed class Endpoint : Endpoint<Request, IEnumerable<Views.Post>>
{
private readonly BlogContext _context;

public Endpoint(BlogContext context)
{
_context = context;
}

public override void Configure()
{
Get("/posts");
AllowAnonymous();
}

public override async Task HandleAsync(Request r, CancellationToken c)
{
_context.Database.EnsureCreated();
var result = await _context.Posts
.Apply(r.Filters ?? Array.Empty<IFilterParticle<Post>>())
.Apply(r.Sorts ?? Array.Empty<ISortParticle<Post>>())
.Select(x => new Views.Post
{
Id = x.Id,
Title = x.Title,
Content = x.Content,
Creation = x.CreatedOn
})
.ToArrayAsync(c);

await SendAsync(result, cancellation: c);
}
}
14 changes: 14 additions & 0 deletions sample/FastEndpoints/Source/Features/Posts/Request.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Mvc;
using Panner;
using Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel;

namespace Posts;

sealed class Request
{
[FromQuery]
public IReadOnlyCollection<ISortParticle<Post>>? Sorts { get; set; }

[FromQuery]
public IReadOnlyCollection<IFilterParticle<Post>>? Filters { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Panner.AspNetCore.Samples.FastEndpointsNet9.PannerExtensions
{
using global::Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel;
using global::Panner.Builders;

public static partial class PEntityBuilderExtensions
{
/// <summary>Marks the entity as sortable by popularity.</summary>
public static PEntityBuilder<Post> IsSortableByPopularity(this PEntityBuilder<Post> builder)
{
builder.GetOrCreateGenerator<ISortParticle<Post>, SortPostsByPopularityParticleGenerator>();
return builder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Panner.AspNetCore.Samples.FastEndpointsNet9.PannerExtensions
{
using global::Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel;
using System.Linq;

public class SortPostByPopularityParticle : ISortParticle<Post>
{
readonly bool Descending;

public SortPostByPopularityParticle(bool descending)
{
this.Descending = descending;
}

public IOrderedQueryable<Post> ApplyTo(IOrderedQueryable<Post> source)
{
if (this.Descending)
return source
.ThenByDescending(x => x.AmtLikes)
.ThenByDescending(x => x.AmtComments);
else
return source
.ThenBy(x => x.AmtLikes)
.ThenBy(x => x.AmtComments);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel;

namespace Panner.AspNetCore.Samples.FastEndpointsNet9.PannerExtensions
{
public class SortPostsByPopularityParticleGenerator : ISortParticleGenerator<Post>
{
public bool TryGenerate(IPContext context, string input, out ISortParticle<Post> particle)
{
var descending = input.StartsWith('-');
var remaining = descending ? input.Substring(1) : input;

if (!remaining.Trim().Equals("Popularity", System.StringComparison.OrdinalIgnoreCase))
{
particle = null;
return false;
}

particle = new SortPostByPopularityParticle(descending);
return true;
}
}
}
27 changes: 26 additions & 1 deletion sample/FastEndpoints/Source/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
using Microsoft.EntityFrameworkCore;
using Panner.AspNetCore.Samples.FastEndpointsNet9.EFModel;
using Panner.AspNetCore.Samples.FastEndpointsNet9.PannerExtensions;
using Panner.Builders;

var bld = WebApplication.CreateBuilder(args);

bld.Services
.AddAuthenticationJwtBearer(s => s.SigningKey = bld.Configuration["Auth:JwtKey"])
.AddAuthorization()
.AddFastEndpoints(o => o.SourceGeneratorDiscoveredTypes = DiscoveredTypes.All)
.SwaggerDocument();

bld.Services.UsePanner(c =>
{
c.Entity<Post>()
.IsSortableByPopularity()
.Property(x => x.Id, o => o
.IsSortableAs(nameof(Views.Post.Id))
.IsFilterableAs(nameof(Views.Post.Id))
)
.Property(x => x.Title, o => o
.IsSortableAs(nameof(Views.Post.Title))
)
.Property(x => x.CreatedOn, o => o
.IsSortableAs(nameof(Views.Post.Creation))
.IsFilterableAs(nameof(Views.Post.Creation))
);
});

bld.Services.AddDbContext<BlogContext>(o => o.UseInMemoryDatabase("BlogDb"));

var app = bld.Build();
app.UseAuthentication()
.UseAuthorization()
Expand All @@ -14,4 +39,4 @@
c.Errors.UseProblemDetails();
})
.UseSwaggerGen();
app.Run();
app.Run();
12 changes: 12 additions & 0 deletions sample/FastEndpoints/Source/Views/Post.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Panner.AspNetCore.Samples.FastEndpointsNet9.Views
{
using System;

public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Creation { get; set; }
}
}
47 changes: 47 additions & 0 deletions samples/WebAPINet8MinimalFluent/EFModel/BlogContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.EFModel
{
using Microsoft.EntityFrameworkCore;
using System;

public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }

public BlogContext() : base()
{
}

public BlogContext(DbContextOptions options) : base(options)
{
}

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

modelBuilder.Entity<Post>()
.HasData(new Post()
{
Id = 1,
Title = Guid.NewGuid().ToString(),
Content = Guid.NewGuid().ToString(),
CreatedOn = DateTime.UtcNow,
IsVisible = true
}, new Post()
{
Id = 2,
Title = Guid.NewGuid().ToString(),
Content = Guid.NewGuid().ToString(),
CreatedOn = DateTime.UtcNow,
IsVisible = false
}, new Post()
{
Id = 3,
Title = Guid.NewGuid().ToString(),
Content = Guid.NewGuid().ToString(),
CreatedOn = DateTime.UtcNow,
IsVisible = true
});
}
}
}
15 changes: 15 additions & 0 deletions samples/WebAPINet8MinimalFluent/EFModel/Post.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.EFModel
{
using System;

public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public bool IsVisible { get; set; }
public int AmtLikes { get; set; }
public int AmtComments { get; set; }
public DateTime CreatedOn { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.PannerExtensions
{
using global::Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.EFModel;
using global::Panner.Builders;

public static partial class PEntityBuilderExtensions
{
/// <summary>Marks the entity as sortable by popularity.</summary>
public static PEntityBuilder<Post> IsSortableByPopularity(this PEntityBuilder<Post> builder)
{
builder.GetOrCreateGenerator<ISortParticle<Post>, SortPostsByPopularityParticleGenerator>();
return builder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.PannerExtensions
{
using global::Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.EFModel;
using System.Linq;

public class SortPostByPopularityParticle : ISortParticle<Post>
{
readonly bool Descending;

public SortPostByPopularityParticle(bool descending)
{
this.Descending = descending;
}

public IOrderedQueryable<Post> ApplyTo(IOrderedQueryable<Post> source)
{
if (this.Descending)
return source
.ThenByDescending(x => x.AmtLikes)
.ThenByDescending(x => x.AmtComments);
else
return source
.ThenBy(x => x.AmtLikes)
.ThenBy(x => x.AmtComments);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.EFModel;

namespace Panner.AspNetCore.Samples.WebApiNet8MinimalFluent.PannerExtensions
{
public class SortPostsByPopularityParticleGenerator : ISortParticleGenerator<Post>
{
public bool TryGenerate(IPContext context, string input, out ISortParticle<Post> particle)
{
var descending = input.StartsWith('-');
var remaining = descending ? input.Substring(1) : input;

if (!remaining.Trim().Equals("Popularity", System.StringComparison.OrdinalIgnoreCase))
{
particle = null;
return false;
}

particle = new SortPostByPopularityParticle(descending);
return true;
}
}
}
Loading
Loading