Split out database logic into service files

This commit is contained in:
Brandon Presley 2022-09-04 16:56:46 +12:00
parent 76e0ea49b4
commit e3b3c6ca09
19 changed files with 321 additions and 309 deletions

View File

@ -6,8 +6,8 @@ import {
import React, {useCallback, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {getBestReps, getBestWeights} from './best.service';
import {BestPageParams} from './BestPage';
import {getBestReps, getBestWeights} from './db';
import Set from './set';
export default function BestList() {

View File

@ -5,15 +5,9 @@ import {FileSystem} from 'react-native-file-access';
import {Divider, IconButton, Menu} from 'react-native-paper';
import {DrawerParamList, SnackbarContext} from './App';
import ConfirmDialog from './ConfirmDialog';
import {
addPlans,
addSets,
deletePlans,
deleteSets,
getAllPlans,
getAllSets,
} from './db';
import {Plan} from './plan';
import {addPlans, deletePlans, getAllPlans} from './plan.service';
import {addSets, deleteSets, getAllSets} from './set.service';
import {write} from './write';
const setFields = 'id,name,reps,weight,created,unit,hidden';

View File

@ -9,9 +9,10 @@ import React, {useCallback, useEffect, useState} from 'react';
import {ScrollView, StyleSheet, Text, View} from 'react-native';
import {Button, IconButton} from 'react-native-paper';
import {DrawerParamList} from './App';
import {addPlan, getNames, setPlan} from './db';
import MassiveSwitch from './MassiveSwitch';
import {addPlan, setPlan} from './plan.service';
import {PlanPageParams} from './PlanPage';
import {getNames} from './set.service';
import {DAYS} from './time';
export default function EditPlan() {

View File

@ -8,10 +8,11 @@ import React, {useCallback, useContext} from 'react';
import {NativeModules, View} from 'react-native';
import {IconButton} from 'react-native-paper';
import {SnackbarContext} from './App';
import {addSet, getSettings, setSet} from './db';
import {HomePageParams} from './HomePage';
import Set from './set';
import {addSet, setSet} from './set.service';
import SetForm from './SetForm';
import {getSettings} from './settings.service';
export default function EditSet() {
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();

View File

@ -9,9 +9,10 @@ import {Image, ScrollView, View} from 'react-native';
import DocumentPicker from 'react-native-document-picker';
import {Button, IconButton} from 'react-native-paper';
import {set} from 'react-native-reanimated';
import {addSet, getSets, setSetImage, setSetName, setWorkouts} from './db';
import MassiveInput from './MassiveInput';
import {setWorkouts} from './plan.service';
import Set from './set';
import {addSet, getSets, setSetImage, setSetName} from './set.service';
import {WorkoutsPageParams} from './WorkoutsPage';
export default function EditWorkout() {

View File

@ -2,8 +2,8 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
import React, {useCallback, useState} from 'react';
import {GestureResponderEvent} from 'react-native';
import {List, Menu} from 'react-native-paper';
import {deletePlan} from './db';
import {Plan} from './plan';
import {deletePlan} from './plan.service';
import {PlanPageParams} from './PlanPage';
export default function PlanItem({

View File

@ -6,10 +6,10 @@ import {
import React, {useCallback, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {getPlans} from './db';
import DrawerMenu from './DrawerMenu';
import MassiveFab from './MassiveFab';
import {Plan} from './plan';
import {getPlans} from './plan.service';
import PlanItem from './PlanItem';
import {PlanPageParams} from './PlanPage';

View File

@ -1,9 +1,9 @@
import React, {useEffect, useRef, useState} from 'react';
import {ScrollView} from 'react-native';
import {Button, Text} from 'react-native-paper';
import {getSets} from './db';
import MassiveInput from './MassiveInput';
import Set from './set';
import {getSets} from './set.service';
export default function SetForm({
save,

View File

@ -2,9 +2,9 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
import React, {useCallback, useState} from 'react';
import {GestureResponderEvent, Image} from 'react-native';
import {Divider, List, Menu, Text} from 'react-native-paper';
import {deleteSet} from './db';
import {HomePageParams} from './HomePage';
import Set from './set';
import {deleteSet} from './set.service';
export default function SetItem({
item,

View File

@ -6,19 +6,15 @@ import {
import React, {useCallback, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {
defaultSet,
getBest,
getSets,
getSettings,
getTodaysPlan,
getTodaysSets,
} from './db';
import {getBestSet} from './best.service';
import DrawerMenu from './DrawerMenu';
import {HomePageParams} from './HomePage';
import MassiveFab from './MassiveFab';
import {getTodaysPlan} from './plan.service';
import Set from './set';
import {defaultSet, getSets, getTodaysSets} from './set.service';
import SetItem from './SetItem';
import {getSettings} from './settings.service';
const limit = 15;
@ -65,7 +61,7 @@ export default function SetList() {
todaysWorkouts[todaysWorkouts.indexOf(todaysSets[0].name!) + 1];
}
console.log(`${SetList.name}.predict:`, {workout});
const best = await getBest(workout);
const best = await getBestSet(workout);
console.log(`${SetList.name}.predict:`, {best});
setSet({...best});
setWorkouts(todaysWorkouts);

View File

@ -10,9 +10,9 @@ import DocumentPicker from 'react-native-document-picker';
import {Button, Searchbar, Text} from 'react-native-paper';
import {SnackbarContext} from './App';
import ConfirmDialog from './ConfirmDialog';
import {getSettings, setSettings} from './db';
import MassiveInput from './MassiveInput';
import MassiveSwitch from './MassiveSwitch';
import {getSettings, setSettings} from './settings.service';
export default function SettingsPage() {
const [vibrate, setVibrate] = useState(true);

View File

@ -10,9 +10,9 @@ import {IconButton} from 'react-native-paper';
import RNPickerSelect from 'react-native-picker-select';
import Share from 'react-native-share';
import ViewShot from 'react-native-view-shot';
import {getVolumes, getWeightsBy} from './best.service';
import {BestPageParams} from './BestPage';
import Chart from './Chart';
import {getVolumes, getWeights} from './db';
import {Metrics} from './metrics';
import {Periods} from './periods';
import Set from './set';
@ -59,7 +59,7 @@ export default function ViewBest() {
useEffect(() => {
if (metric === Metrics.Weight)
getWeights(params.best.name, period).then(setWeights);
getWeightsBy(params.best.name, period).then(setWeights);
else if (metric === Metrics.Volume)
getVolumes(params.best.name, period).then(setVolumes);

View File

@ -3,7 +3,7 @@ import React, {useCallback, useEffect, useState} from 'react';
import {GestureResponderEvent, Image} from 'react-native';
import {List, Menu, Text} from 'react-native-paper';
import ConfirmDialog from './ConfirmDialog';
import {deleteSetsBy, getSets} from './db';
import {deleteSetsBy, getSets} from './set.service';
import Workout from './workout';
import {WorkoutsPageParams} from './WorkoutsPage';

View File

@ -6,8 +6,8 @@ import {
import React, {useCallback, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {getWorkouts} from './db';
import MassiveFab from './MassiveFab';
import {getWorkouts} from './set.service';
import SetList from './SetList';
import Workout from './workout';
import WorkoutItem from './WorkoutItem';

89
best.service.ts Normal file
View File

@ -0,0 +1,89 @@
import {db, defaultSet} from './db';
import {Periods} from './periods';
import Set from './set';
import Volume from './volume';
export const getBestSet = async (name: string): Promise<Set> => {
const bestWeight = `
SELECT name, reps, unit, MAX(weight) AS weight
FROM sets
WHERE name = ? AND NOT hidden
GROUP BY name;
`;
const bestReps = `
SELECT name, MAX(reps) as reps, unit, weight
FROM sets
WHERE name = ? AND weight = ? AND NOT hidden
GROUP BY name;
`;
const [weightResult] = await db.executeSql(bestWeight, [name]);
if (!weightResult.rows.length) return {...defaultSet};
const [repsResult] = await db.executeSql(bestReps, [
name,
weightResult.rows.item(0).weight,
]);
return repsResult.rows.item(0);
};
export const getWeightsBy = async (
name: string,
period: Periods,
): Promise<Set[]> => {
const select = `
SELECT max(weight) AS weight,
STRFTIME('%Y-%m-%d', created) as created, unit
FROM sets
WHERE name = ? AND NOT hidden
AND DATE(created) >= DATE('now', 'weekday 0', ?)
GROUP BY name, STRFTIME('%Y-%m-%d', created)
`;
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
const [result] = await db.executeSql(select, [name, difference]);
return result.rows.raw();
};
export const getVolumes = async (
name: string,
period: Periods,
): Promise<Volume[]> => {
const select = `
SELECT sum(weight * reps) AS value,
STRFTIME('%Y-%m-%d', created) as created, unit
FROM sets
WHERE name = ? AND NOT hidden
AND DATE(created) >= DATE('now', 'weekday 0', ?)
GROUP BY name, STRFTIME('%Y-%m-%d', created)
`;
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
const [result] = await db.executeSql(select, [name, difference]);
return result.rows.raw();
};
export const getBestWeights = async (search: string): Promise<Set[]> => {
const select = `
SELECT name, reps, unit, MAX(weight) AS weight
FROM sets
WHERE name LIKE ? AND NOT hidden
GROUP BY name;
`;
const [result] = await db.executeSql(select, [`%${search}%`]);
return result.rows.raw();
};
export const getBestReps = async (
name: string,
weight: number,
): Promise<Set[]> => {
const select = `
SELECT name, MAX(reps) as reps, unit, weight
FROM sets
WHERE name = ? AND weight = ? AND NOT hidden
GROUP BY name;
`;
const [result] = await db.executeSql(select, [name, weight]);
return result.rows.raw();
};

279
db.ts
View File

@ -3,13 +3,6 @@ import {
openDatabase,
SQLiteDatabase,
} from 'react-native-sqlite-storage';
import {Periods} from './periods';
import {Plan} from './plan';
import Set from './set';
import Settings from './settings';
import {DAYS} from './time';
import Volume from './volume';
import Workout from './workout';
enablePromise(true);
@ -95,159 +88,12 @@ export const migrations = async () => {
if (result.rows.length === 0) await db.executeSql(insertSettings);
};
export const getSettings = async () => {
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
const settings: Settings = result.rows.item(0);
return settings;
};
export const setSettings = async (value: Settings) => {
const update = `
UPDATE settings
SET vibrate=?,minutes=?,sets=?,seconds=?,alarm=?,
predict=?,sound=?,notify=?,images=?
`;
return db.executeSql(update, [
value.vibrate,
value.minutes,
value.sets,
value.seconds,
value.alarm,
value.predict,
value.sound,
value.notify,
value.images,
]);
};
export const setSet = async (value: Set) => {
const update = `
UPDATE sets
SET name = ?, reps = ?, weight = ?, unit = ?
WHERE id = ?
`;
return db.executeSql(update, [
value.name,
value.reps,
value.weight,
value.unit,
value.id,
]);
};
export const addSets = async (values: string) => {
const insert = `
INSERT INTO sets(name,reps,weight,created,unit,hidden)
VALUES ${values}
`;
return db.executeSql(insert);
};
export const addSet = async (value: Set) => {
const insert = `
INSERT INTO sets(name, reps, weight, created, unit, image)
VALUES (?,?,?,strftime('%Y-%m-%dT%H:%M:%S', 'now', 'localtime'),?, ?)
`;
const {name, reps, weight, unit, image} = value;
return db.executeSql(insert, [name, reps, weight, unit, image]);
};
export const setWorkouts = async (oldName: string, newName: string) => {
const update = `
UPDATE plans SET workouts = REPLACE(workouts, ?, ?)
WHERE workouts LIKE ?
`;
return db.executeSql(update, [oldName, newName, `%${oldName}%`]);
};
export const setPlan = async (value: Plan) => {
const update = `UPDATE plans SET days = ?, workouts = ? WHERE id = ?`;
return db.executeSql(update, [value.days, value.workouts, value.id]);
};
export const addPlan = async (value: Plan) => {
const insert = `INSERT INTO plans(days, workouts) VALUES (?, ?)`;
return db.executeSql(insert, [value.days, value.workouts]);
};
export const addPlans = async (values: string) => {
const insert = `
INSERT INTO plans(days,workouts) VALUES ${values}
`;
return db.executeSql(insert);
};
export const deletePlans = async () => {
return db.executeSql(`DELETE FROM plans`);
};
export const deleteSets = async () => {
return db.executeSql(`DELETE FROM sets`);
};
export const deletePlan = async (id: number) => {
return db.executeSql(`DELETE FROM plans WHERE id = ?`, [id]);
};
export const deleteSet = async (id: number) => {
return db.executeSql(`DELETE FROM sets WHERE id = ?`, [id]);
};
export const deleteSetsBy = async (name: string) => {
return db.executeSql(`DELETE FROM sets WHERE name = ?`, [name]);
};
export const getAllPlans = async (): Promise<Plan[]> => {
const select = `SELECT * from plans`;
const [result] = await db.executeSql(select);
return result.rows.raw();
};
export const getAllSets = async (): Promise<Set[]> => {
const select = `SELECT * from sets`;
const [result] = await db.executeSql(select);
return result.rows.raw();
};
export interface PageParams {
search: string;
limit: number;
offset: number;
}
export const getSets = async ({
search,
limit,
offset,
}: PageParams): Promise<Set[]> => {
const select = `
SELECT * from sets
WHERE name LIKE ? AND NOT hidden
ORDER BY created DESC
LIMIT ? OFFSET ?
`;
const [result] = await db.executeSql(select, [`%${search}%`, limit, offset]);
return result.rows.raw();
};
export const getTodaysPlan = async (): Promise<Plan[]> => {
const today = DAYS[new Date().getDay()];
const [result] = await db.executeSql(
`SELECT * FROM plans WHERE days LIKE ? LIMIT 1`,
[`%${today}%`],
);
return result.rows.raw();
};
export const getTodaysSets = async (): Promise<Set[]> => {
const today = new Date().toISOString().split('T')[0];
const [result] = await db.executeSql(
`SELECT * FROM sets WHERE created LIKE ? ORDER BY created DESC`,
[`${today}%`],
);
return result.rows.raw();
};
export const defaultSet = {
name: '',
id: 0,
@ -255,128 +101,3 @@ export const defaultSet = {
weight: 20,
unit: 'kg',
};
export const getBest = async (query: string): Promise<Set> => {
const bestWeight = `
SELECT name, reps, unit, MAX(weight) AS weight
FROM sets
WHERE name = ? AND NOT hidden
GROUP BY name;
`;
const bestReps = `
SELECT name, MAX(reps) as reps, unit, weight
FROM sets
WHERE name = ? AND weight = ? AND NOT hidden
GROUP BY name;
`;
const [weightResult] = await db.executeSql(bestWeight, [query]);
if (!weightResult.rows.length) return {...defaultSet};
const [repsResult] = await db.executeSql(bestReps, [
query,
weightResult.rows.item(0).weight,
]);
return repsResult.rows.item(0);
};
export const setSetName = async (oldName: string, newName: string) => {
const update = `UPDATE sets SET name = ? WHERE name = ?`;
return db.executeSql(update, [newName, oldName]);
};
export const setSetImage = async (name: string, image: string) => {
const update = `UPDATE sets SET image = ? WHERE name = ?`;
return db.executeSql(update, [name, image]);
};
export const getWeights = async (
name: string,
period: Periods,
): Promise<Set[]> => {
const select = `
SELECT max(weight) AS weight,
STRFTIME('%Y-%m-%d', created) as created, unit
FROM sets
WHERE name = ? AND NOT hidden
AND DATE(created) >= DATE('now', 'weekday 0', ?)
GROUP BY name, STRFTIME('%Y-%m-%d', created)
`;
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
const [result] = await db.executeSql(select, [name, difference]);
return result.rows.raw();
};
export const getVolumes = async (
name: string,
period: Periods,
): Promise<Volume[]> => {
const select = `
SELECT sum(weight * reps) AS value,
STRFTIME('%Y-%m-%d', created) as created, unit
FROM sets
WHERE name = ? AND NOT hidden
AND DATE(created) >= DATE('now', 'weekday 0', ?)
GROUP BY name, STRFTIME('%Y-%m-%d', created)
`;
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
const [result] = await db.executeSql(select, [name, difference]);
return result.rows.raw();
};
export const getNames = async (): Promise<string[]> => {
const [result] = await db.executeSql('SELECT DISTINCT name FROM sets');
return result.rows.raw();
};
export const getBestWeights = async (search: string): Promise<Set[]> => {
const select = `
SELECT name, reps, unit, MAX(weight) AS weight
FROM sets
WHERE name LIKE ? AND NOT hidden
GROUP BY name;
`;
const [result] = await db.executeSql(select, [`%${search}%`]);
return result.rows.raw();
};
export const getBestReps = async (
name: string,
weight: number,
): Promise<Set[]> => {
const select = `
SELECT name, MAX(reps) as reps, unit, weight
FROM sets
WHERE name = ? AND weight = ? AND NOT hidden
GROUP BY name;
`;
const [result] = await db.executeSql(select, [name, weight]);
return result.rows.raw();
};
export const getPlans = async (search: string): Promise<Plan[]> => {
const select = `
SELECT * from plans
WHERE days LIKE ? OR workouts LIKE ?
`;
const [result] = await db.executeSql(select, [`%${search}%`, `%${search}%`]);
return result.rows.raw();
};
export const getWorkouts = async ({
search,
limit,
offset,
}: PageParams): Promise<Workout[]> => {
const select = `
SELECT DISTINCT sets.name
FROM sets
WHERE sets.name LIKE ?
ORDER BY sets.name
LIMIT ? OFFSET ?
`;
const [result] = await db.executeSql(select, [search, limit, offset]);
return result.rows.raw();
};

60
plan.service.ts Normal file
View File

@ -0,0 +1,60 @@
import {db} from './db';
import {Plan} from './plan';
import {DAYS} from './time';
export const getPlans = async (search: string): Promise<Plan[]> => {
const select = `
SELECT * from plans
WHERE days LIKE ? OR workouts LIKE ?
`;
const [result] = await db.executeSql(select, [`%${search}%`, `%${search}%`]);
return result.rows.raw();
};
export const getTodaysPlan = async (): Promise<Plan[]> => {
const today = DAYS[new Date().getDay()];
const [result] = await db.executeSql(
`SELECT * FROM plans WHERE days LIKE ? LIMIT 1`,
[`%${today}%`],
);
return result.rows.raw();
};
export const setWorkouts = async (oldName: string, newName: string) => {
const update = `
UPDATE plans SET workouts = REPLACE(workouts, ?, ?)
WHERE workouts LIKE ?
`;
return db.executeSql(update, [oldName, newName, `%${oldName}%`]);
};
export const setPlan = async (value: Plan) => {
const update = `UPDATE plans SET days = ?, workouts = ? WHERE id = ?`;
return db.executeSql(update, [value.days, value.workouts, value.id]);
};
export const addPlan = async (value: Plan) => {
const insert = `INSERT INTO plans(days, workouts) VALUES (?, ?)`;
return db.executeSql(insert, [value.days, value.workouts]);
};
export const addPlans = async (values: string) => {
const insert = `
INSERT INTO plans(days,workouts) VALUES ${values}
`;
return db.executeSql(insert);
};
export const deletePlans = async () => {
return db.executeSql(`DELETE FROM plans`);
};
export const deletePlan = async (id: number) => {
return db.executeSql(`DELETE FROM plans WHERE id = ?`, [id]);
};
export const getAllPlans = async (): Promise<Plan[]> => {
const select = `SELECT * from plans`;
const [result] = await db.executeSql(select);
return result.rows.raw();
};

122
set.service.ts Normal file
View File

@ -0,0 +1,122 @@
import {db} from './db';
import Set from './set';
import Workout from './workout';
export const setSet = async (value: Set) => {
const update = `
UPDATE sets
SET name = ?, reps = ?, weight = ?, unit = ?
WHERE id = ?
`;
return db.executeSql(update, [
value.name,
value.reps,
value.weight,
value.unit,
value.id,
]);
};
export const addSets = async (values: string) => {
const insert = `
INSERT INTO sets(name,reps,weight,created,unit,hidden)
VALUES ${values}
`;
return db.executeSql(insert);
};
export const addSet = async (value: Set) => {
const insert = `
INSERT INTO sets(name, reps, weight, created, unit, image)
VALUES (?,?,?,strftime('%Y-%m-%dT%H:%M:%S', 'now', 'localtime'),?, ?)
`;
const {name, reps, weight, unit, image} = value;
return db.executeSql(insert, [name, reps, weight, unit, image]);
};
export const deleteSets = async () => {
return db.executeSql(`DELETE FROM sets`);
};
export const deleteSet = async (id: number) => {
return db.executeSql(`DELETE FROM sets WHERE id = ?`, [id]);
};
export const deleteSetsBy = async (name: string) => {
return db.executeSql(`DELETE FROM sets WHERE name = ?`, [name]);
};
export const getAllSets = async (): Promise<Set[]> => {
const select = `SELECT * from sets`;
const [result] = await db.executeSql(select);
return result.rows.raw();
};
export interface PageParams {
search: string;
limit: number;
offset: number;
}
export const getSets = async ({
search,
limit,
offset,
}: PageParams): Promise<Set[]> => {
const select = `
SELECT * from sets
WHERE name LIKE ? AND NOT hidden
ORDER BY created DESC
LIMIT ? OFFSET ?
`;
const [result] = await db.executeSql(select, [`%${search}%`, limit, offset]);
return result.rows.raw();
};
export const getTodaysSets = async (): Promise<Set[]> => {
const today = new Date().toISOString().split('T')[0];
const [result] = await db.executeSql(
`SELECT * FROM sets WHERE created LIKE ? ORDER BY created DESC`,
[`${today}%`],
);
return result.rows.raw();
};
export const defaultSet = {
name: '',
id: 0,
reps: 10,
weight: 20,
unit: 'kg',
};
export const setSetName = async (oldName: string, newName: string) => {
const update = `UPDATE sets SET name = ? WHERE name = ?`;
return db.executeSql(update, [newName, oldName]);
};
export const setSetImage = async (name: string, image: string) => {
const update = `UPDATE sets SET image = ? WHERE name = ?`;
return db.executeSql(update, [name, image]);
};
export const getNames = async (): Promise<string[]> => {
const [result] = await db.executeSql('SELECT DISTINCT name FROM sets');
return result.rows.raw();
};
export const getWorkouts = async ({
search,
limit,
offset,
}: PageParams): Promise<Workout[]> => {
const select = `
SELECT DISTINCT sets.name
FROM sets
WHERE sets.name LIKE ?
ORDER BY sets.name
LIMIT ? OFFSET ?
`;
const [result] = await db.executeSql(select, [search, limit, offset]);
return result.rows.raw();
};

27
settings.service.ts Normal file
View File

@ -0,0 +1,27 @@
import {db} from './db';
import Settings from './settings';
export const getSettings = async () => {
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
const settings: Settings = result.rows.item(0);
return settings;
};
export const setSettings = async (value: Settings) => {
const update = `
UPDATE settings
SET vibrate=?,minutes=?,sets=?,seconds=?,alarm=?,
predict=?,sound=?,notify=?,images=?
`;
return db.executeSql(update, [
value.vibrate,
value.minutes,
value.sets,
value.seconds,
value.alarm,
value.predict,
value.sound,
value.notify,
value.images,
]);
};