ExOdata4
An OData v4 query parser and Ecto query builder for Elixir. Parse OData query strings or full URIs and get back Ecto queries ready to execute against your own repo.
Installation
Add ex_odata4 to your dependencies in mix.exs:
def deps do
[
{:ex_odata4, "~> 0.1.0"}
]
endConfiguration
Tell the library which OData entity names map to your Ecto schemas in config/config.exs:
config :ex_odata4, schemas: %{
"Orders" => MyApp.Orders,
"Products" => MyApp.Products
}The key is the entity name as it appears in the OData URI. The value is the Ecto schema module.
Usage
Parsing a full OData URI
ExOdata4.parse_uri("/Orders?$filter=Amount gt 1000&$top=25&$skip=0")
|> MyApp.Repo.all()Parsing a query string directly
ExOdata4.get("Orders", "$filter=Status eq 'active'&$orderby=CreatedAt desc&$top=10")
|> MyApp.Repo.all()
Both functions return an %Ecto.Query{}, so you pipe it into your own repo. This means the library has no opinion about your database, connection pool, or repo configuration.
Supported OData query options
| Option | Example |
|---|---|
$filter | $filter=Name eq 'John' |
$top | $top=25 |
$skip | $skip=50 |
$orderby | $orderby=Amount desc |
Supported filter operators
| Operator | Meaning |
|---|---|
eq | Equal |
ne | Not equal |
gt | Greater than |
ge | Greater than or equal |
lt | Less than |
le | Less than or equal |
and | Logical and |
or | Logical or |
Supported filter functions
| Function | Example | Translates to |
|---|---|---|
contains | contains(Name, 'John') | LIKE '%John%' |
startswith | startswith(Name, 'J') | LIKE 'J%' |
endswith | endswith(Email, '.com') | LIKE '%.com' |
Functions can be combined with logical operators:
$filter=contains(Name, 'John') and Amount gt 100
$filter=startswith(Status, 'act') or endswith(Email, '.com')Supported literal types
-
Strings:
'hello' -
Integers:
42,-7 -
Decimals:
3.14 -
Booleans:
true,false -
Null:
null -
Dates:
2024-01-01 -
GUIDs:
00000000-0000-0000-0000-000000000000
Not yet supported
The following OData v4 features are not currently implemented:
Query options
$select— field projection$expand— loading related entities$count— total result count$search— free-text search
Filter functions
-
String functions:
tolower(),toupper(),trim(),length(),substring(),concat() -
Date functions:
year(),month(),day(),hour(),minute(),second() -
Math functions:
round(),floor(),ceiling()
Filter operators
not— logical negation-
Lambda operators:
any(),all()
Path traversal
-
Navigation properties:
Orders/Customer/Name eq 'John' - Collection indexing
Contributions are welcome. Open an issue or PR on GitHub.
Error handling
If a schema name is not found in your config, a descriptive error is raised:
No schema configured for "Orders".
Add it to your config.exs:
config :ex_odata4, schemas: %{
"Orders" => MyApp.Orders
}License
MIT