mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 00:59:28 +01:00
building out settings db
finally got transactions working too
This commit is contained in:
parent
2a6821c25d
commit
de5b479c47
4
App.tsx
4
App.tsx
@ -1,10 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
import ArtistsList from './src/components/ArtistsList';
|
import SettingsView from './src/components/Settings';
|
||||||
|
|
||||||
const App = () => (
|
const App = () => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
<ArtistsList />
|
<SettingsView />
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
6
src/clients.ts
Normal file
6
src/clients.ts
Normal file
@ -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();
|
||||||
37
src/components/Settings.tsx
Normal file
37
src/components/Settings.tsx
Normal file
@ -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 (
|
||||||
|
<View>
|
||||||
|
<Button
|
||||||
|
title='Recreate Music DB'
|
||||||
|
onPress={recreateMusicDb}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title='Recreate Settings DB'
|
||||||
|
onPress={recreateSettingsDb}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsView = () => (
|
||||||
|
<View>
|
||||||
|
<DbControls />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default SettingsView;
|
||||||
@ -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<void>
|
|
||||||
|
|
||||||
private async openDb(): Promise<SQLiteDatabase> {
|
|
||||||
return await SQLite.openDatabase({ ...this.dbParams });
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteDb(): Promise<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import md5 from 'md5';
|
import md5 from 'md5';
|
||||||
import { atom, selector, useSetRecoilState } from 'recoil';
|
import { atom, selector, useSetRecoilState } from 'recoil';
|
||||||
import { SubsonicApiClient } from '../subsonic/client';
|
import { SubsonicApiClient } from '../subsonic/api';
|
||||||
import { MusicDb } from '../db/client';
|
import { MusicDb } from '../storage/music';
|
||||||
|
|
||||||
const db = new MusicDb();
|
const db = new MusicDb();
|
||||||
|
|
||||||
|
|||||||
71
src/storage/db.ts
Normal file
71
src/storage/db.ts
Normal file
@ -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<void>
|
||||||
|
|
||||||
|
protected async createDb(scope: (tx: Transaction) => void): Promise<void> {
|
||||||
|
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<boolean> {
|
||||||
|
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<SQLiteDatabase> {
|
||||||
|
return await SQLite.openDatabase({ ...this.dbParams });
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteDb(): Promise<void> {
|
||||||
|
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<void> {
|
||||||
|
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 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/storage/music.ts
Normal file
19
src/storage/music.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { DbStorage } from './db';
|
||||||
|
|
||||||
|
export class MusicDb extends DbStorage {
|
||||||
|
constructor() {
|
||||||
|
super({ name: 'music.db', location: 'default' });
|
||||||
|
}
|
||||||
|
|
||||||
|
async createDb(): Promise<void> {
|
||||||
|
super.createDb(tx => {
|
||||||
|
tx.executeSql(`
|
||||||
|
CREATE TABLE artists (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
starred INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
103
src/storage/settings.ts
Normal file
103
src/storage/settings.ts
Normal file
@ -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<void> {
|
||||||
|
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<ServerSettings[]> {
|
||||||
|
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<ServerSettings | undefined> {
|
||||||
|
return (await this.getServers()).find(x => x.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addServer(server: ServerSettings): Promise<void> {
|
||||||
|
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<void> {
|
||||||
|
await this.executeSql(`
|
||||||
|
DELETE FROM servers
|
||||||
|
WHERE id = ?;
|
||||||
|
`, [id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateServer(server: ServerSettings): Promise<void> {
|
||||||
|
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<AppSettings> {
|
||||||
|
return (await this.executeSql(`
|
||||||
|
SELECT * FROM app;
|
||||||
|
`))[0].rows.raw().map(x => ({
|
||||||
|
server: x.server || undefined,
|
||||||
|
}))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateApp(app: AppSettings): Promise<void> {
|
||||||
|
await this.executeSql(`
|
||||||
|
UPDATE app SET
|
||||||
|
server = ?;
|
||||||
|
`, [
|
||||||
|
app.server || null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user