From de5b479c4707cd5070c9390c68f999f22f87f500 Mon Sep 17 00:00:00 2001
From: austinried <4966622+austinried@users.noreply.github.com>
Date: Thu, 17 Jun 2021 13:01:47 +0900
Subject: [PATCH] building out settings db
finally got transactions working too
---
App.tsx | 4 +-
src/clients.ts | 6 ++
src/components/Settings.tsx | 37 +++++++++++
src/db/client.ts | 67 -------------------
src/state/artists.ts | 4 +-
src/storage/db.ts | 71 ++++++++++++++++++++
src/storage/music.ts | 19 ++++++
src/storage/settings.ts | 103 +++++++++++++++++++++++++++++
src/subsonic/{client.ts => api.ts} | 0
9 files changed, 240 insertions(+), 71 deletions(-)
create mode 100644 src/clients.ts
create mode 100644 src/components/Settings.tsx
delete mode 100644 src/db/client.ts
create mode 100644 src/storage/db.ts
create mode 100644 src/storage/music.ts
create mode 100644 src/storage/settings.ts
rename src/subsonic/{client.ts => api.ts} (100%)
diff --git a/App.tsx b/App.tsx
index e5b8d85..5b7a91a 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,10 +1,10 @@
import React from 'react';
import { RecoilRoot } from 'recoil';
-import ArtistsList from './src/components/ArtistsList';
+import SettingsView from './src/components/Settings';
const App = () => (
-
+
);
diff --git a/src/clients.ts b/src/clients.ts
new file mode 100644
index 0000000..c4a579d
--- /dev/null
+++ b/src/clients.ts
@@ -0,0 +1,6 @@
+import { MusicDb } from "./storage/music";
+import { SettingsDb } from "./storage/settings";
+import { SubsonicApiClient } from "./subsonic/api";
+
+export const musicDb = new MusicDb();
+export const settingsDb = new SettingsDb();
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
new file mode 100644
index 0000000..72cbfb8
--- /dev/null
+++ b/src/components/Settings.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { Button, View } from 'react-native';
+import { musicDb, settingsDb } from '../clients';
+
+const DbControls = () => {
+
+ const recreateMusicDb = async () => {
+ try { await musicDb.deleteDb(); } catch {}
+ await musicDb.createDb();
+ }
+
+ const recreateSettingsDb = async () => {
+ try { await settingsDb.deleteDb(); } catch {}
+ await settingsDb.createDb();
+ }
+
+ return (
+
+
+
+
+ );
+}
+
+const SettingsView = () => (
+
+
+
+)
+
+export default SettingsView;
diff --git a/src/db/client.ts b/src/db/client.ts
deleted file mode 100644
index 7b62493..0000000
--- a/src/db/client.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import SQLite, { DatabaseParams, ResultSet, SQLiteDatabase } from 'react-native-sqlite-storage';
-
-SQLite.enablePromise(true);
-
-abstract class DbStorage {
- private dbParams: DatabaseParams;
-
- constructor(dbParams: DatabaseParams) {
- this.dbParams = dbParams;
- }
-
- abstract createDb(): Promise
-
- private async openDb(): Promise {
- return await SQLite.openDatabase({ ...this.dbParams });
- }
-
- async deleteDb(): Promise {
- await SQLite.deleteDatabase({ ...this.dbParams });
- }
-
- async executeSql(sql: string, params?: any[]): Promise<[ResultSet]> {
- const db = await this.openDb();
- try {
- // https://github.com/andpor/react-native-sqlite-storage/issues/410
- // if (params) {
- // for (const p of params) {
- // if (Array.isArray(p)) {
- // throw new Error('param value cannot be an array');
- // }
- // }
- // }
- return await db.executeSql(sql, params);
- } catch (err) {
- try { await db.close(); } catch {}
- throw err;
- } finally {
- try { await db.close(); } catch {}
- }
- }
-}
-
-export class MusicDb extends DbStorage {
- constructor() {
- super({ name: 'music.db', location: 'default' });
- }
-
- async createDb(): Promise {
- await this.executeSql(`
- CREATE TABLE artists (
- id PRIMARY KEY NOT NULL,
- name NOT NULL,
- starred
- );
- `);
- }
-}
-
-class SettingsDb extends DbStorage {
- constructor() {
- super({ name: 'settings.db', location: 'Library' });
- }
-
- async createDb(): Promise {
- return;
- }
-}
diff --git a/src/state/artists.ts b/src/state/artists.ts
index 1fdaf5d..fc71af6 100644
--- a/src/state/artists.ts
+++ b/src/state/artists.ts
@@ -1,7 +1,7 @@
import md5 from 'md5';
import { atom, selector, useSetRecoilState } from 'recoil';
-import { SubsonicApiClient } from '../subsonic/client';
-import { MusicDb } from '../db/client';
+import { SubsonicApiClient } from '../subsonic/api';
+import { MusicDb } from '../storage/music';
const db = new MusicDb();
diff --git a/src/storage/db.ts b/src/storage/db.ts
new file mode 100644
index 0000000..b9473f9
--- /dev/null
+++ b/src/storage/db.ts
@@ -0,0 +1,71 @@
+import SQLite, { DatabaseParams, ResultSet, SQLiteDatabase, Transaction } from 'react-native-sqlite-storage';
+
+SQLite.enablePromise(true);
+
+export abstract class DbStorage {
+ private dbParams: DatabaseParams;
+
+ constructor(dbParams: DatabaseParams) {
+ this.dbParams = dbParams;
+ }
+
+ // abstract createDb(): Promise
+
+ protected async createDb(scope: (tx: Transaction) => void): Promise {
+ await this.transaction(tx => {
+ tx.executeSql(`
+ CREATE TABLE db_version (
+ version INTEGER NOT NULL
+ );
+ `);
+ tx.executeSql(`
+ INSERT INTO db_version (version)
+ VALUES (?);
+ `, [1]);
+
+ scope(tx);
+ });
+ }
+
+ async dbExists(): Promise {
+ const results = await this.executeSql(`
+ SELECT name FROM sqlite_master
+ WHERE type='table' AND name='db_version';
+ `);
+
+ return results[0].rows.length > 0;
+ }
+
+ private async openDb(): Promise {
+ return await SQLite.openDatabase({ ...this.dbParams });
+ }
+
+ async deleteDb(): Promise {
+ await SQLite.deleteDatabase({ ...this.dbParams });
+ }
+
+ async executeSql(sql: string, params?: any[]): Promise<[ResultSet]> {
+ const db = await this.openDb();
+ try {
+ // https://github.com/andpor/react-native-sqlite-storage/issues/410
+ return await db.executeSql(sql, params);
+ } catch (err) {
+ try { await db.close(); } catch {}
+ throw err;
+ } finally {
+ try { await db.close(); } catch {}
+ }
+ }
+
+ async transaction(scope: (tx: Transaction) => void): Promise {
+ const db = await this.openDb();
+ try {
+ await db.transaction(scope);
+ } catch (err) {
+ try { await db.close(); } catch {}
+ throw err;
+ } finally {
+ try { await db.close(); } catch {}
+ }
+ }
+}
diff --git a/src/storage/music.ts b/src/storage/music.ts
new file mode 100644
index 0000000..0ba3f05
--- /dev/null
+++ b/src/storage/music.ts
@@ -0,0 +1,19 @@
+import { DbStorage } from './db';
+
+export class MusicDb extends DbStorage {
+ constructor() {
+ super({ name: 'music.db', location: 'default' });
+ }
+
+ async createDb(): Promise {
+ super.createDb(tx => {
+ tx.executeSql(`
+ CREATE TABLE artists (
+ id TEXT PRIMARY KEY NOT NULL,
+ name TEXT NOT NULL,
+ starred INTEGER NOT NULL
+ );
+ `);
+ });
+ }
+}
diff --git a/src/storage/settings.ts b/src/storage/settings.ts
new file mode 100644
index 0000000..bc81f6d
--- /dev/null
+++ b/src/storage/settings.ts
@@ -0,0 +1,103 @@
+import { DbStorage } from './db';
+
+export interface ServerSettings {
+ id: string;
+ address: string;
+ username: string;
+ token: string;
+ salt: string;
+}
+
+export interface AppSettings {
+ server?: string;
+}
+
+export class SettingsDb extends DbStorage {
+ constructor() {
+ super({ name: 'settings.db', location: 'Library' });
+ }
+
+ async createDb(): Promise {
+ super.createDb(tx => {
+ tx.executeSql(`
+ CREATE TABLE servers (
+ id TEXT PRIMARY KEY NOT NULL,
+ address TEXT NOT NULL,
+ username TEXT NOT NULL,
+ token TEXT NOT NULL,
+ salt TEXT NOT NULL
+ );
+ `);
+ tx.executeSql(`
+ CREATE TABLE app (
+ server TEXT
+ );
+ `);
+ tx.executeSql(`
+ INSERT INTO app (server)
+ VALUES (NULL);
+ `);
+ });
+ }
+
+ async getServers(): Promise {
+ return (await this.executeSql(`
+ SELECT * FROM servers;
+ `))[0].rows.raw().map(x => ({
+ id: x.id,
+ address: x.address,
+ username: x.username,
+ token: x.token,
+ salt: x.salt,
+ }));
+ }
+
+ async getServer(id: string): Promise {
+ return (await this.getServers()).find(x => x.id === id);
+ }
+
+ async addServer(server: ServerSettings): Promise {
+ await this.executeSql(`
+ INSERT INTO servers (id, address, username, token, salt)
+ VALUES (?, ?, ?, ?, ?);
+ `, [server.id, server.address, server.username, server.token, server.salt]);
+ }
+
+ async removeServer(id: string): Promise {
+ await this.executeSql(`
+ DELETE FROM servers
+ WHERE id = ?;
+ `, [id]);
+ }
+
+ async updateServer(server: ServerSettings): Promise {
+ await this.executeSql(`
+ UPDATE servers SET
+ address = ?,
+ username = ?,
+ token = ?,
+ salt = ?
+ WHERE id = ?;
+ `, [
+ server.address, server.username, server.token, server.salt,
+ server.id,
+ ]);
+ }
+
+ async getApp(): Promise {
+ return (await this.executeSql(`
+ SELECT * FROM app;
+ `))[0].rows.raw().map(x => ({
+ server: x.server || undefined,
+ }))[0];
+ }
+
+ async updateApp(app: AppSettings): Promise {
+ await this.executeSql(`
+ UPDATE app SET
+ server = ?;
+ `, [
+ app.server || null,
+ ]);
+ }
+}
diff --git a/src/subsonic/client.ts b/src/subsonic/api.ts
similarity index 100%
rename from src/subsonic/client.ts
rename to src/subsonic/api.ts