Packages

A Gleam library for building and orchestrating agents on the BEAM.

Current section

Files

Jump to
pig src pig@workspace@kv.erl
Raw

src/pig@workspace@kv.erl

-module(pig@workspace@kv).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/pig/workspace/kv.gleam").
-export([remember/3, recall/2, list_keys/2]).
-export_type([error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Key-value store operations for pig workspace.\n").
-type error() :: {sql_error, sqlight:error()} | {not_found, binary()}.
-file("src/pig/workspace/kv.gleam", 24).
?DOC(
" Store a key-value pair, updating the value if the key already exists.\n"
"\n"
" Uses an upsert operation (INSERT ... ON CONFLICT DO UPDATE) to handle\n"
" both new keys and updates to existing keys atomically.\n"
"\n"
" # Example\n"
" ```gleam\n"
" let assert Ok(Nil) = kv.remember(conn, \"user:1\", \"Alice\")\n"
" let assert Ok(Nil) = kv.remember(conn, \"user:1\", \"Alice Smith\") // Updates\n"
" ```\n"
).
-spec remember(sqlight:connection(), binary(), binary()) -> {ok, nil} |
{error, error()}.
remember(Conn, Key, Value) ->
Sql = <<"
INSERT INTO kv_store (key, value, updated_at)
VALUES (?, ?, unixepoch())
ON CONFLICT(key) DO UPDATE SET
value = excluded.value,
updated_at = unixepoch()
RETURNING key
"/utf8>>,
_pipe = sqlight:'query'(
Sql,
Conn,
[sqlight:text(Key), sqlight:text(Value)],
gleam@dynamic@decode:at(
[0],
{decoder, fun gleam@dynamic@decode:decode_string/1}
)
),
_pipe@1 = gleam@result:map_error(
_pipe,
fun(Field@0) -> {sql_error, Field@0} end
),
gleam@result:map(_pipe@1, fun(_) -> nil end).
-file("src/pig/workspace/kv.gleam", 61).
?DOC(
" Retrieve a value by key.\n"
"\n"
" Returns an error if the key doesn't exist.\n"
"\n"
" # Example\n"
" ```gleam\n"
" case kv.recall(conn, \"user:1\") {\n"
" Ok(name) -> io.println(\"Found: \" <> name)\n"
" Error(kv.NotFound(key)) -> io.println(\"Key not found: \" <> key)\n"
" Error(_) -> io.println(\"Database error\")\n"
" }\n"
" ```\n"
).
-spec recall(sqlight:connection(), binary()) -> {ok, binary()} |
{error, error()}.
recall(Conn, Key) ->
Sql = <<"SELECT value FROM kv_store WHERE key = ?"/utf8>>,
_pipe = sqlight:'query'(
Sql,
Conn,
[sqlight:text(Key)],
gleam@dynamic@decode:at(
[0],
{decoder, fun gleam@dynamic@decode:decode_string/1}
)
),
_pipe@1 = gleam@result:map_error(
_pipe,
fun(Field@0) -> {sql_error, Field@0} end
),
gleam@result:'try'(_pipe@1, fun(Rows) -> case Rows of
[Value] ->
{ok, Value};
_ ->
{error, {not_found, Key}}
end end).
-file("src/pig/workspace/kv.gleam", 100).
?DOC(" Escape SQL LIKE wildcard characters (%, _, \\) so they match literally.\n").
-spec escape_like(binary()) -> binary().
escape_like(S) ->
_pipe = S,
_pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"%"/utf8>>, <<"\\%"/utf8>>),
gleam@string:replace(_pipe@2, <<"_"/utf8>>, <<"\\_"/utf8>>).
-file("src/pig/workspace/kv.gleam", 82).
?DOC(
" List all keys that start with the given prefix, sorted alphabetically.\n"
"\n"
" Escapes SQL LIKE wildcards in the prefix so they match literally.\n"
).
-spec list_keys(sqlight:connection(), binary()) -> {ok, list(binary())} |
{error, error()}.
list_keys(Conn, Prefix) ->
Escaped = escape_like(Prefix),
Sql = <<"SELECT key FROM kv_store WHERE key LIKE ? || '%' ESCAPE '\\' ORDER BY key ASC"/utf8>>,
_pipe = sqlight:'query'(
Sql,
Conn,
[sqlight:text(Escaped)],
gleam@dynamic@decode:at(
[0],
{decoder, fun gleam@dynamic@decode:decode_string/1}
)
),
gleam@result:map_error(_pipe, fun(Field@0) -> {sql_error, Field@0} end).