Spectre.Query is a library for doing simplified (safe) querying in Entity Framework Core. Perfect when you want to let end users or APIs search with a SQL-esque language without actually letting them execute any SQL directly (which you never should).
ID > 0 AND Year < 2007 AND Comment != null AND !Seen
The query engine was originally implemented very quick and dirty for an internal application, and before open sourcing it, the code have been somewhat cleaned up. However, there are still things that will need to be improved. Some functionality was also removed due to the hackish nature of the implementation. See known issues below for more information.
This project is currently under active development and might not be ready for production.
-
Navigation properties are not supported. For more complex queries, use Query Types.
-
There's currently no support for non-integer numbers.
-
Generates SQL from query expressions. The query translator should be rewritten to generate a
System.Linq.Expression
.
PM> Install-Package Spectre.Query
var provider = QueryProviderBuilder.Build(context, options =>
{
options.Configure<Movie>(movie =>
{
movie.Map("Id", e => e.MovieId);
movie.Map("Title", e => e.Name);
movie.Map("Year", e => e.ReleasedAt);
movie.Map("Score", e => e.Rating);
movie.Map("Seen", e => e.Seen);
});
});
The created IQueryProvider<TContext>
is thread safe and
can be cached for the duration of the application.
var movies = provider.Query<Movie>(context, "NOT Seen AND Score > 60").ToList();
PM> Install-Package Spectre.Query.AspNetCore
Start by adding the registrations in your Startup.cs
.
public void ConfigureServices(IServiceCollection services)
{
services.AddQueryProvider<MovieDbContext>(options =>
{
options.Entity<Movie>(movie =>
{
movie.Map("Id", e => e.MovieId);
movie.Map("Title", e => e.Name);
movie.Map("Year", e => e.ReleasedAt);
movie.Map("Score", e => e.Rating);
movie.Map("Seen", e => e.Seen);
});
});
// ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// This is not required, but will make sure that all
// initialization is performed at start up and not at
// the first time the query provider is used.
app.UseQueryProvider<MovieDbContext>();
// ...
}
[ApiController]
[Route("api/movies")]
public class MovieController : ControllerBase
{
private readonly IQueryProviderSession<MovieContext> _provider;
public MovieController(IQueryProviderSession<MovieContext> provider)
{
_provider = provider;
}
[HttpGet]
public IActionResult<List<Movie>> Query([FromHeader]string query = "Rating > 80 AND !Seen")
{
return _provider
.Query<Movie>(query)
.OrderByDescending(x => x.Rating)
.ToList();
}
}
Copyright © Spectre Systems
Spectre.Query is provided as-is under the MIT license. For more information see LICENSE.