62 lines · 2.0 KB · TypeScript
RawDownload
import type { Database } from "bun:sqlite";import { Schema, type Effect } from "effect";import { RepositoryStore, type RepositoryError } from "./sqlite"; const UI_PREFERENCES_KEY = "ui_preferences"; type SettingRow = {  value: string;}; const UiPreferencesSchema = Schema.Record(Schema.String, Schema.String); const ensureSchema = (db: Database): void => {  db.run(`      CREATE TABLE IF NOT EXISTS controller_settings (        key TEXT PRIMARY KEY,        value TEXT NOT NULL,        updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP      )    `);}; export class ControllerSettingsStore extends RepositoryStore {  public constructor(dbPath: string) {    super(dbPath, "controller-settings.close", ensureSchema);  }   public getUiPreferencesEffect(): Effect.Effect<Record<string, string>, RepositoryError> {    return this.effect("controller-settings.get-ui-preferences", () => {      const row = this.db        .query("SELECT value FROM controller_settings WHERE key = ?")        .get(UI_PREFERENCES_KEY) as SettingRow | null;      if (!row) return {};      try {        return Schema.decodeUnknownSync(UiPreferencesSchema)(JSON.parse(row.value) as unknown);      } catch {        return {};      }    });  }   public saveUiPreferencesEffect(    preferences: Record<string, string>,  ): Effect.Effect<Record<string, string>, RepositoryError> {    return this.effect("controller-settings.save-ui-preferences", () => {      const clean = Object.fromEntries(        Object.entries(preferences).filter(          (entry): entry is [string, string] =>            typeof entry[0] === "string" && entry[0].length > 0 && typeof entry[1] === "string",        ),      );      this.db        .query(          `INSERT INTO controller_settings (key, value, updated_at)           VALUES (?, ?, CURRENT_TIMESTAMP)           ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP`,        )        .run(UI_PREFERENCES_KEY, JSON.stringify(clean));      return clean;    });  }}