FIQLEx v0.1.8 FIQLEx.QueryBuilders.SQLQueryBuilder View Source

Builds SQL queries from FIQL AST.

Possible options for this query builder are:

  • table: The table name to use in the FROM statement (defaults to "table")
  • select: SELECT statement to build (see below).
  • ecto: Tuple containing the ecto repo and the ecto schema to use for the query. This will execute the query and return the result as a list
  • only: A list with the only fields to accept in the query (if only and except are both provided, only is used)
  • except: A list with the fields to reject in the query (if only and except are both provided, only is used)
  • order_by: A string order by to be added to the query
  • limit: A limit for the query
  • offset: An offset for the query
  • case_sensitive: Boolean value (default to true) to set equals case sensitive or not
  • transformer: Function that takes a selector and its value as parameter and must return the transformed value

Select option

Possible values of the select option are:

  • :all: use SELECT * (default value)
  • :from_selectors: Searches for all selectors in the FIQL AST and use them as SELECT statement. For instance, for the following query: age=ge=25;name==*Doe, the SELECT statement will be SELECT age, name
  • selectors: You specify a list of items you want to use in the SELECT statement.

Ecto option

You can directly execute the SQL query in an Ecto context by proving in a tuple the repo and the schema to use.

For instance:

FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, echo: {Repo, User})

May return something like this:

{:ok, [%User{name: "John", age: 18}, %User{name: "John", age: 21}]}

Examples

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name = 'John'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors, table: "author")
{:ok, "SELECT name FROM author WHERE name = 'John'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :all)
{:ok, "SELECT * FROM table WHERE name = 'John'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: ["another", "other"])
{:ok, "SELECT another, other FROM table WHERE name = 'John'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John;(age=gt=25,age=lt=18)"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name, age FROM table WHERE (name = 'John' AND (age > 25 OR age < 18))"}

iex> FIQLEx.build_query(FIQLEx.parse!("name=ge=John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:error, :invalid_format}

iex> FIQLEx.build_query(FIQLEx.parse!("name=ge=2019-02-02T18:23:03Z"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name >= '2019-02-02T18:23:03Z'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=12.4"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name <> 12.4"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=true"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name <> true"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=false"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name <> false"}

iex> FIQLEx.build_query(FIQLEx.parse!("name"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name IS NOT NULL"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=(1,2,Hello)"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name NOT IN (1, 2, 'Hello')"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!='Hello \\'World'"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name <> 'Hello ''World'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=*Hello"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name NOT LIKE '%Hello'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==Hello*"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name FROM table WHERE name LIKE 'Hello%'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==Hello;age=ge=10;friend==true"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name, age, friend FROM table WHERE (name = 'Hello' AND (age >= 10 AND friend = true))"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==Hello,age=ge=10,friend==true"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name, age, friend FROM table WHERE (name = 'Hello' OR (age >= 10 OR friend = true))"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==Hello;age=ge=10;friend==true;ok"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name, age, friend, ok FROM table WHERE (name = 'Hello' AND (age >= 10 AND (friend = true AND ok IS NOT NULL)))"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==Hello,age=ge=10,friend==true,ok"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors)
{:ok, "SELECT name, age, friend, ok FROM table WHERE (name = 'Hello' OR (age >= 10 OR (friend = true OR ok IS NOT NULL)))"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, only: ["bad"])
{:error, :selector_not_allowed}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, only: ["name"])
{:ok, "SELECT * FROM table WHERE name = 'John'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, except: ["name"])
{:error, :selector_not_allowed}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, except: ["bad"])
{:ok, "SELECT * FROM table WHERE name = 'John'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, order_by: "name DESC")
{:ok, "SELECT * FROM table WHERE name = 'John' ORDER BY name DESC"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, limit: "10")
{:ok, "SELECT * FROM table WHERE name = 'John' LIMIT 10"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, offset: "10")
{:ok, "SELECT * FROM table WHERE name = 'John' OFFSET 10"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, order_by: "name", limit: "5", offset: "10")
{:ok, "SELECT * FROM table WHERE name = 'John' ORDER BY name LIMIT 5 OFFSET 10"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors, case_sensitive: false)
{:ok, "SELECT name FROM table WHERE LOWER(name) = LOWER('John')"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=John"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors, case_sensitive: false)
{:ok, "SELECT name FROM table WHERE LOWER(name) <> LOWER('John')"}

iex> FIQLEx.build_query(FIQLEx.parse!("name!=*Hello"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors, case_sensitive: false)
{:ok, "SELECT name FROM table WHERE name NOT ILIKE '%Hello'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==Hello*"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors, case_sensitive: false)
{:ok, "SELECT name FROM table WHERE name ILIKE 'Hello%'"}

iex> FIQLEx.build_query(FIQLEx.parse!("name==John;age==18"), FIQLEx.QueryBuilders.SQLQueryBuilder, select: :from_selectors, transformer: fn selector, value -> if(selector == "name", do: "Johny", else: value) end)
{:ok, "SELECT name, age FROM table WHERE (name = 'Johny' AND age = 18)"}

Link to this section Summary

Link to this section Functions

Link to this function

binary_equal(selector_name, value, opts)

View Source
Link to this function

binary_like(selector_name, value, opts)

View Source
Link to this function

binary_not_equal(selector_name, value, opts)

View Source
Link to this function

binary_not_like(selector_name, value, opts)

View Source
Link to this function

get_selectors(ast)

View Source
get_selectors(ast :: FIQLEx.ast()) :: [binary()]

Returns a list of all selectors for a given AST

Link to this function

handle_ast(curr_ast, ast, state)

View Source
handle_ast(FIQLEx.ast(), FIQLEx.ast(), any()) ::
  {:ok, any()} | {:error, any()}

This function will go deeper in the ast traversal.

Parameters are:

  • curr_ast: The AST we want to go deeper with
  • ast: The global AST
  • state: The current state of your query builder

The function returns {:ok, state} if everything is fine, and {:error, reason} if there is an error

Link to this function

handle_ast!(curr_ast, ast, state)

View Source
handle_ast!(FIQLEx.ast(), FIQLEx.ast(), any()) :: any()

Same as handle_ast/3 but returns the state or raises an exception.

Link to this function

identity_transformer(selector, value)

View Source