kura_dialect behaviour (kura v2.0.6)

View Source

SQL dialect behaviour. Translates a portable #kura_query{} AST into backend-specific SQL.

#kura_query{} is the portable AST: it describes operations as atoms and tuples, not as SQL strings. The dialect callbacks turn that AST into SQL bytes appropriate for a given backend.

Today

The canonical implementation is kura_dialect_pg, which targets PostgreSQL via the pgo driver's $N placeholder convention.

Tomorrow

Adding SQLite or MySQL is a matter of providing another implementation of this behaviour. Differences (placeholder syntax ? vs $N, identifier quoting "foo" vs `foo`, RETURNING vs lastrowid, ON CONFLICT vs ON DUPLICATE KEY UPDATE, LIMIT/OFFSET vs FETCH FIRST) all live in the dialect impl. The AST stays the same.

Public API entry point

Consumers go through kura_query_compiler, which delegates to the configured dialect module. They do not call this behaviour's callbacks directly.

Summary

Types

Next placeholder index. Used when composing sub-queries (CTEs, sub-selects in WHERE) so placeholders stay contiguous across the entire compiled statement.

Parameter list in the order the placeholders appear in sql().

Compiled SQL bytes. Implementations are free to return iodata or a binary.

Callbacks

Optional. SQL bytes for a kura column type, used by kura_migrator DDL.

Compile a DELETE-by-primary-key.

Compile a bulk DELETE (DELETE ... WHERE ...) from a query AST.

Optional. SQL bytes for a column default value, used by kura_migrator DDL.

Compile a single-row INSERT (no options).

Compile a single-row INSERT with options (e.g. on_conflict).

Compile a bulk INSERT (multi-row).

Compile a bulk INSERT with options (returning => true | [Field]).

Compile a query AST into {SQL, Params}.

Compile a query AST starting placeholder numbering at StartCounter. Returns the next free counter so callers can chain sub-compilations.

Compile an UPDATE-by-primary-key.

Compile a bulk UPDATE (UPDATE ... WHERE ...) from a query AST and a SET map.

Types

counter()

-type counter() :: pos_integer().

Next placeholder index. Used when composing sub-queries (CTEs, sub-selects in WHERE) so placeholders stay contiguous across the entire compiled statement.

params()

-type params() :: [term()].

Parameter list in the order the placeholders appear in sql().

sql()

-type sql() :: iodata().

Compiled SQL bytes. Implementations are free to return iodata or a binary.

Callbacks

column_type/1

(optional)
-callback column_type(kura_types:kura_type()) -> binary().

Optional. SQL bytes for a kura column type, used by kura_migrator DDL.

delete/3

-callback delete(atom() | module(), atom(), term()) -> {sql(), params()}.

Compile a DELETE-by-primary-key.

delete_all/1

-callback delete_all(#kura_query{from :: atom() | module() | undefined,
                                 select :: [atom() | term()] | {exprs, [term()]},
                                 wheres :: [term()],
                                 joins :: [term()],
                                 order_bys :: [term()],
                                 group_bys :: [atom()],
                                 havings :: [term()],
                                 limit :: non_neg_integer() | undefined,
                                 offset :: non_neg_integer() | undefined,
                                 distinct :: boolean() | [atom()],
                                 lock :: binary() | undefined,
                                 prefix :: binary() | undefined,
                                 preloads :: [atom() | {atom(), list()}],
                                 ctes :: [{binary(), #kura_query{}}],
                                 combinations :: [{union | union_all | intersect | except, #kura_query{}}],
                                 include_deleted :: boolean()}) ->
                        {sql(), params()}.

Compile a bulk DELETE (DELETE ... WHERE ...) from a query AST.

format_default/1

(optional)
-callback format_default(term()) -> binary().

Optional. SQL bytes for a column default value, used by kura_migrator DDL.

insert/3

-callback insert(atom() | module(), [atom()], map()) -> {sql(), params()}.

Compile a single-row INSERT (no options).

insert/4

-callback insert(atom() | module(), [atom()], map(), map()) -> {sql(), params()}.

Compile a single-row INSERT with options (e.g. on_conflict).

insert_all/3

-callback insert_all(atom() | module(), [atom()], [map()]) -> {sql(), params()}.

Compile a bulk INSERT (multi-row).

insert_all/4

-callback insert_all(atom() | module(), [atom()], [map()], map()) -> {sql(), params()}.

Compile a bulk INSERT with options (returning => true | [Field]).

to_sql/1

-callback to_sql(#kura_query{from :: atom() | module() | undefined,
                             select :: [atom() | term()] | {exprs, [term()]},
                             wheres :: [term()],
                             joins :: [term()],
                             order_bys :: [term()],
                             group_bys :: [atom()],
                             havings :: [term()],
                             limit :: non_neg_integer() | undefined,
                             offset :: non_neg_integer() | undefined,
                             distinct :: boolean() | [atom()],
                             lock :: binary() | undefined,
                             prefix :: binary() | undefined,
                             preloads :: [atom() | {atom(), list()}],
                             ctes :: [{binary(), #kura_query{}}],
                             combinations :: [{union | union_all | intersect | except, #kura_query{}}],
                             include_deleted :: boolean()}) ->
                    {sql(), params()}.

Compile a query AST into {SQL, Params}.

to_sql_from/2

-callback to_sql_from(#kura_query{from :: atom() | module() | undefined,
                                  select :: [atom() | term()] | {exprs, [term()]},
                                  wheres :: [term()],
                                  joins :: [term()],
                                  order_bys :: [term()],
                                  group_bys :: [atom()],
                                  havings :: [term()],
                                  limit :: non_neg_integer() | undefined,
                                  offset :: non_neg_integer() | undefined,
                                  distinct :: boolean() | [atom()],
                                  lock :: binary() | undefined,
                                  prefix :: binary() | undefined,
                                  preloads :: [atom() | {atom(), list()}],
                                  ctes :: [{binary(), #kura_query{}}],
                                  combinations :: [{union | union_all | intersect | except, #kura_query{}}],
                                  include_deleted :: boolean()},
                      counter()) ->
                         {sql(), params(), counter()}.

Compile a query AST starting placeholder numbering at StartCounter. Returns the next free counter so callers can chain sub-compilations.

update/4

-callback update(atom() | module(), [atom()], map(), {atom(), term()}) -> {sql(), params()}.

Compile an UPDATE-by-primary-key.

update_all/2

-callback update_all(#kura_query{from :: atom() | module() | undefined,
                                 select :: [atom() | term()] | {exprs, [term()]},
                                 wheres :: [term()],
                                 joins :: [term()],
                                 order_bys :: [term()],
                                 group_bys :: [atom()],
                                 havings :: [term()],
                                 limit :: non_neg_integer() | undefined,
                                 offset :: non_neg_integer() | undefined,
                                 distinct :: boolean() | [atom()],
                                 lock :: binary() | undefined,
                                 prefix :: binary() | undefined,
                                 preloads :: [atom() | {atom(), list()}],
                                 ctes :: [{binary(), #kura_query{}}],
                                 combinations :: [{union | union_all | intersect | except, #kura_query{}}],
                                 include_deleted :: boolean()},
                     map()) ->
                        {sql(), params()}.

Compile a bulk UPDATE (UPDATE ... WHERE ...) from a query AST and a SET map.