Defining a Schema¶
A Schema
in FunQL .NET serves as the core configuration and entry point for processing FunQL queries. It defines what
data can be queried and which query options are supported (filtering, sorting, pagination).
This guide walks you through building a schema and configuring it to handle FunQL requests.
Implementing the Schema¶
To get started, create a class that inherits from FunQL's Schema
and override the OnInitializeSchema()
method. This
method is where you configure your schema, including supported features and requests:
public sealed class ApiSchema : Schema
{
protected override void OnInitializeSchema(ISchemaConfigBuilder schema)
{
// Schema configuration goes here
}
}
Note
While it's usually enough to implement OnInitializeSchema(ISchemaConfigBuilder)
, you may also implement
OnFinalizeSchema(ISchemaConfigBuilder)
, which can be used for additional customizations, like modifying default
settings or applying conventions.
FunQL schemas prioritize explicit configurations, providing developers with complete control and predictability. There are no hidden behaviors or 'automagic' configurations — every feature and setting must be explicitly defined.
Adding features¶
Features define the capabilities of your schema, from parsing and validating FunQL queries to translating them into LINQ expressions for execution.
To get started quickly, add the most commonly used features:
- Core features: Enables common operations like parsing, query validation, and execution.
- LINQ feature: Translates FunQL queries into LINQ expressions, which is useful for querying in-memory collections or external databases (e.g., using Entity Framework (EF) Core).
public sealed class ApiSchema : Schema
{
protected override void OnInitializeSchema(ISchemaConfigBuilder schema)
{
// Add core parsing, validation and execution features
schema.AddCoreFeatures();
// Enable LINQ query translation
schema.AddLinqFeature();
}
}
By adding only the features you need, you ensure that your schema remains lightweight and optimized for your use case.
Adding requests¶
In FunQL, requests define the entry points to your data. They represent the operations that users can query, specifying what data can be fetched and how it can be filtered or sorted.
Key concepts of requests¶
- Request name: Each request has a unique identifier, like
listSets
, used in queries to specify the operation to execute. - Parameters: Requests specify which parameters they support, like the
filter()
andsort()
parameters to provide advanced querying capabilities. - Return type: Requests define the type of data returned, such as a list of objects, along with the fields that can be queried, filtered, and sorted.
Example request¶
As an example, we'll configure a listSets()
request with support for filtering and sorting a list of LEGO sets. Once
configured, the schema is ready to handle advanced FunQL queries like:
Define the data model¶
Start by defining the Set
data model, which represents the LEGO sets and serves as the return type of the listSets()
request:
The fields Name
, Price
, and LaunchTime
will later be configured to support filtering and sorting.
Add the request¶
Define the listSets
request in the schema:
public sealed class ApiSchema : Schema
{
protected override void OnInitializeSchema(ISchemaConfigBuilder schema)
{
// Add the 'listSets' request
schema.Request("listSets")
// Enable support for the 'filter()' parameter
.SupportsFilter()
// Enable support for the 'sort()' parameter
.SupportsSort()
// Define the return type as a list of 'Set' objects (List<Set>)
.ReturnsListOfObjects<Set>(set =>
{
// Field configurations go here
});
}
}
At this point, the listSets
request is defined and supports the filter()
and sort()
parameters. However, the
fields must be explicitly configured before they can be filtered and sorted on, so let's configure this next.
Configure fields¶
Fields define which properties of the data model can be queried, filtered, and sorted. Expose the Set
properties
(Name
, Price
, and LaunchTime
) for filtering and sorting:
public sealed class ApiSchema : Schema
{
protected override void OnInitializeSchema(ISchemaConfigBuilder schema)
{
schema.Request("listSets")
.SupportsFilter()
.SupportsSort()
.ReturnsListOfObjects<Set>(set =>
{
// Configure the 'Name' field
set.SimpleField(it => it.Name)
// Override the default name ('Name') to use its JSON name
.HasName("name")
// Enable support for filtering on this field
.SupportsFilter(it =>
// Enable String functions like:
// - has(name, "War")
// - stw(upper(name), "STAR")
it.SupportsStringFilterFunctions()
)
// Enable support for sorting on this field
.SupportsSort(it =>
// Enable String functions like:
// - asc(lower(name))
// - desc(upper(name))
it.SupportsStringFieldFunctions()
);
set.SimpleField(it => it.Price)
.HasName("price")
.SupportsFilter(it =>
// Enable Double functions like:
// - eq(round(price), 100)
it.SupportsDoubleFilterFunctions()
)
.SupportsSort(it => it.SupportsDoubleFieldFunctions());
set.SimpleField(it => it.LaunchTime)
.HasName("launchTime")
.SupportsFilter(it =>
// Enable DateTime functions like:
// - gte(year(launchTime), 2010)
it.SupportsDateTimeFilterFunctions()
)
.SupportsSort(it => it.SupportsDateTimeFieldFunctions());
});
}
}
The Schema
is now fully configured and ready to handle listSets
requests.
Next steps¶
Now that you've learned how to define a schema, let's learn how to execute a query.