kura_dialect_sqlite (kura_sqlite v0.2.5)

View Source

SQLite dialect. Translates #kura_query{} AST into SQLite-flavored SQL.

Strategy

SQLite 3.35+ supports nearly every SQL feature kura emits: RETURNING, ON CONFLICT (col) DO UPDATE, LIMIT/OFFSET, double-quoted identifiers. The main wire-protocol difference vs PG is the placeholder syntax: PG uses $N, SQLite uses ?N.

This dialect delegates the AST-to-SQL emission to kura_dialect_pg and post-processes the SQL string to swap $N for ?N. The number of placeholders and their positions are unchanged. Edge cases where SQL bytes between dialects truly diverge (JSONB operators, advisory locks, partial-index expressions, etc.) are out of scope for this phase 2 skeleton and will be addressed by capability flags in phase 3.

Notes

  • All callbacks are pure pass-throughs to kura_dialect_pg followed by swap_placeholders/1.
  • Identifier quoting: SQLite (with SQLITE_DQS=0 as esqlite ships) treats "foo" as an identifier. Same as PG.
  • esqlite returns rows as tuples, not maps. Map-shaped result conversion happens in kura_driver_sqlite.

Summary

Functions

column_type/1

-spec column_type(kura_types:kura_type()) -> binary().

delete(SchemaOrTable, PKField, PKValue)

-spec delete(atom() | module(), atom(), term()) -> {iodata(), [term()]}.

delete_all(Query)

-spec 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()}) ->
                    {iodata(), [term()]}.

format_default/1

-spec format_default(term()) -> binary().

insert(SchemaOrTable, Fields, Data)

-spec insert(atom() | module(), [atom()], map()) -> {iodata(), [term()]}.

insert(SchemaOrTable, Fields, Data, Opts)

-spec insert(atom() | module(), [atom()], map(), map()) -> {iodata(), [term()]}.

insert_all(SchemaOrTable, Fields, Rows)

-spec insert_all(atom() | module(), [atom()], [map()]) -> {iodata(), [term()]}.

insert_all(SchemaOrTable, Fields, Rows, Opts)

-spec insert_all(atom() | module(), [atom()], [map()], map()) -> {iodata(), [term()]}.

swap_placeholders(SQL)

-spec swap_placeholders(iodata()) -> binary().

Rewrite PG's $N placeholders to SQLite's ?N form.

Both backends accept positional and numbered placeholders. SQLite specifically: ?NNN where NNN is a 1-indexed integer. Position-for- position swap; counts and ordering preserved.

Bytes inside string literals are not rewritten; SQLite uses single quotes for literals (SQLITE_DQS=0 excludes double-quoted strings) and the kura emitter follows the same convention.

to_sql(Query)

-spec 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()}) ->
                {iodata(), [term()]}.

to_sql_from(Query, StartCounter)

-spec 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()},
                  pos_integer()) ->
                     {iodata(), [term()], pos_integer()}.

update(SchemaOrTable, Fields, Changes, PK)

-spec update(atom() | module(), [atom()], map(), {atom(), term()}) -> {iodata(), [term()]}.

update_all(Query, SetMap)

-spec 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()) ->
                    {iodata(), [term()]}.