using Invercargill; using Invercargill.DataStructures; using Invercargill.Expressions; using InvercargillSql; using InvercargillSql.Orm; using Inversion; using ClankerSaddle.Data; namespace ClankerSaddle.Services { /** The user_preferences key of the Spry theme slug ("" = core default). */ public const string PREF_THEME = "theme"; /** The user_preferences key of the colour mode (auto|light|dark). */ public const string PREF_MODE = "mode"; /** The default colour mode when no preference is stored. */ public const string MODE_DEFAULT = "auto"; /** * Per-user preferences (goal 41 task 2): the account settings' * key/value store behind the Spry theme picker. Reads go through * the ORM query API; writes are raw UPSERTs — the table's * composite primary key (user_id, key) defeats the ORM's * single-column update_async, so INSERT ... ON CONFLICT replaces * both halves of the pair. * * The theme helpers ({@link get_theme}, {@link set_theme}, {@link * get_mode}, {@link set_mode}) are thin sugar over the generic * string accessors; validation lives with the action that owns * the form, not here — storage accepts any string. */ public class UserPreferenceService : Object { private OrmSession db = inject(); private Connection connection = inject(); /** * The stored value of `key` for `user_id`, or "" when the * user never set it. */ public async string get_string(int64 user_id, string key) throws Error { var row = yield db.query() .where(expr("user_id == $0 && key == $1", elem(user_id), elem(key))) .first_async(); return row != null ? ((!)row).value : ""; } /** * Upserts `value` under `key` for `user_id`: one row per * (user, key), replaced on conflict. */ public async void set_string(int64 user_id, string key, string value) throws Error { yield connection.create_command( "INSERT INTO user_preferences (user_id, key, value)" + " VALUES (:user_id, :key, :value)" + " ON CONFLICT(user_id, key) DO UPDATE SET value = excluded.value") .with_parameter("user_id", elem(user_id)) .with_parameter("key", elem(key)) .with_parameter("value", elem(value)) .execute_non_query_async(); } /** The stored theme slug ("" = the Spry core default). */ public async string get_theme(int64 user_id) throws Error { return yield get_string(user_id, PREF_THEME); } /** Stores the theme slug ("" = the Spry core default). */ public async void set_theme(int64 user_id, string theme) throws Error { yield set_string(user_id, PREF_THEME, theme); } /** The stored colour mode (auto when never set). */ public async string get_mode(int64 user_id) throws Error { var mode = yield get_string(user_id, PREF_MODE); return mode.length > 0 ? mode : MODE_DEFAULT; } /** Stores the colour mode. */ public async void set_mode(int64 user_id, string mode) throws Error { yield set_string(user_id, PREF_MODE, mode); } } }