Add typeorm migrations

This commit is contained in:
Brandon Presley 2022-10-31 17:05:31 +13:00
parent b7f1c2192e
commit e7321b6d8e
35 changed files with 432 additions and 268 deletions

View File

@ -4,7 +4,8 @@ import DocumentPicker from 'react-native-document-picker';
import {FileSystem} from 'react-native-file-access'; import {FileSystem} from 'react-native-file-access';
import {Divider, IconButton, Menu} from 'react-native-paper'; import {Divider, IconButton, Menu} from 'react-native-paper';
import ConfirmDialog from './ConfirmDialog'; import ConfirmDialog from './ConfirmDialog';
import {AppDataSource, planRepo} from './db'; import {AppDataSource} from './data-source';
import {planRepo} from './db';
import {DrawerParamList} from './drawer-param-list'; import {DrawerParamList} from './drawer-param-list';
import GymSet from './gym-set'; import GymSet from './gym-set';
import {useSnackbar} from './MassiveSnack'; import {useSnackbar} from './MassiveSnack';

View File

@ -39,12 +39,9 @@ export default function PlanItem({
}, [setShow, item.id, onRemove]); }, [setShow, item.id, onRemove]);
const start = useCallback(async () => { const start = useCallback(async () => {
const workouts = item.workouts.split(','); console.log(`${PlanItem.name}.start:`, {item});
const first = workouts[0];
const set = await getBestSet(first);
console.log(`${PlanItem.name}.start:`, {set});
setShow(false); setShow(false);
navigation.navigate('StartPlan', {plan: item, set}); navigation.navigate('StartPlan', {plan: item});
}, [item, navigation]); }, [item, navigation]);
const longPress = useCallback( const longPress = useCallback(

View File

@ -39,7 +39,7 @@ export default function SetForm({
if (!name) return; if (!name) return;
let image = newImage; let image = newImage;
if (!newImage && !removeImage) if (!newImage && !removeImage)
image = await setRepo.findOne({where: {name}}).then(s => s.image); image = await setRepo.findOne({where: {name}}).then(s => s?.image);
console.log(`${SetForm.name}.handleSubmit:`, {image}); console.log(`${SetForm.name}.handleSubmit:`, {image});
save({ save({
@ -52,6 +52,7 @@ export default function SetForm({
minutes: Number(set.minutes ?? 3), minutes: Number(set.minutes ?? 3),
seconds: Number(set.seconds ?? 30), seconds: Number(set.seconds ?? 30),
sets: set.sets ?? 3, sets: set.sets ?? 3,
hidden: false,
}); });
}; };

View File

@ -65,7 +65,7 @@ export default function SetList() {
}); });
if (newSets.length === 0) return setEnd(true); if (newSets.length === 0) return setEnd(true);
if (!sets) return; if (!sets) return;
// setSets([...sets, ...newSets]); setSets([...sets, ...newSets]);
if (newSets.length < limit) return setEnd(true); if (newSets.length < limit) return setEnd(true);
setOffset(newOffset); setOffset(newOffset);
}, [term, end, offset, sets]); }, [term, end, offset, sets]);
@ -109,10 +109,6 @@ export default function SetList() {
data={sets} data={sets}
style={{flex: 1}} style={{flex: 1}}
renderItem={renderItem} renderItem={renderItem}
getItem={(data: any, index: number) => {
console.log({data, index});
return data[index];
}}
onEndReached={next} onEndReached={next}
/> />
)} )}

View File

@ -6,12 +6,12 @@ import {Button} from 'react-native-paper';
import {getBestSet} from './best.service'; import {getBestSet} from './best.service';
import {PADDING} from './constants'; import {PADDING} from './constants';
import CountMany from './count-many'; import CountMany from './count-many';
import {AppDataSource, getNow, setRepo} from './db'; import {AppDataSource} from './data-source';
import {getNow, setRepo} from './db';
import GymSet from './gym-set'; import GymSet from './gym-set';
import MassiveInput from './MassiveInput'; import MassiveInput from './MassiveInput';
import {useSnackbar} from './MassiveSnack'; import {useSnackbar} from './MassiveSnack';
import {PlanPageParams} from './plan-page-params'; import {PlanPageParams} from './plan-page-params';
import {countMany} from './set.service';
import SetForm from './SetForm'; import SetForm from './SetForm';
import StackHeader from './StackHeader'; import StackHeader from './StackHeader';
import StartPlanItem from './StartPlanItem'; import StartPlanItem from './StartPlanItem';
@ -19,15 +19,14 @@ import {useSettings} from './use-settings';
export default function StartPlan() { export default function StartPlan() {
const {params} = useRoute<RouteProp<PlanPageParams, 'StartPlan'>>(); const {params} = useRoute<RouteProp<PlanPageParams, 'StartPlan'>>();
const {set} = params; const [name, setName] = useState('');
const [name, setName] = useState(set.name); const [reps, setReps] = useState('');
const [reps, setReps] = useState(set.reps.toString()); const [weight, setWeight] = useState('');
const [weight, setWeight] = useState(set.weight.toString()); const [unit, setUnit] = useState<string>('kg');
const [unit, setUnit] = useState<string>();
const {toast} = useSnackbar(); const {toast} = useSnackbar();
const [minutes, setMinutes] = useState(set.minutes); const [minutes, setMinutes] = useState(3);
const [seconds, setSeconds] = useState(set.seconds); const [seconds, setSeconds] = useState(30);
const [best, setBest] = useState<GymSet>(set); const [best, setBest] = useState<GymSet>();
const [selected, setSelected] = useState(0); const [selected, setSelected] = useState(0);
const {settings} = useSettings(); const {settings} = useSettings();
const [counts, setCounts] = useState<CountMany[]>(); const [counts, setCounts] = useState<CountMany[]>();
@ -38,35 +37,55 @@ export default function StartPlan() {
const [selection, setSelection] = useState({ const [selection, setSelection] = useState({
start: 0, start: 0,
end: set.reps.toString().length, end: 0,
}); });
const refresh = useCallback(() => { const refresh = useCallback(() => {
const questions = workouts.map(_ => '(?)').join(','); const questions = workouts
const condition = ` .map((workout, index) => `('${workout}',${index})`)
sets.name = workouts.name .join(',');
console.log({questions, workouts});
const select = `
SELECT workouts.name, COUNT(sets.id) as total
FROM (select 0 as name, 0 as sequence union values ${questions}) as workouts
LEFT JOIN sets ON sets.name = workouts.name
AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime') AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime')
AND NOT sets.hidden AND NOT sets.hidden
GROUP BY workouts.name
ORDER BY workouts.sequence
LIMIT -1
OFFSET 1
`; `;
return AppDataSource.manager return AppDataSource.manager.query(select).then(newCounts => {
.createQueryBuilder() setCounts(newCounts);
.select('COUNT(sets.id)', 'total') console.log(`${StartPlan.name}.focus:`, {newCounts});
.addSelect('workouts') return newCounts;
.from(`(SELECT 0 AS name UNION values ${questions})`, 'workouts') });
.leftJoin('sets', condition)
.groupBy('workouts.name')
.limit(-1)
.offset(1)
.getRawMany()
.then(newCounts => {
setCounts(newCounts);
console.log(`${StartPlan.name}.focus:`, {newCounts});
});
}, [workouts]); }, [workouts]);
const select = useCallback(
async (index: number, newCounts?: CountMany[]) => {
setSelected(index);
console.log(`${StartPlan.name}.next:`, {name, index});
if (!counts && !newCounts) return;
const workout = counts ? counts[index] : newCounts[index];
console.log(`${StartPlan.name}.next:`, {workout});
const newBest = await getBestSet(workout.name);
console.log(`${StartPlan.name}.next:`, {newBest});
setMinutes(newBest.minutes);
setSeconds(newBest.seconds);
setName(newBest.name);
setReps(newBest.reps.toString());
setWeight(newBest.weight.toString());
setUnit(newBest.unit);
setBest(newBest);
},
[name, counts],
);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
refresh(); refresh().then(newCounts => select(0, newCounts));
}, [refresh]), }, [refresh]),
); );
@ -77,12 +96,12 @@ export default function StartPlan() {
name, name,
weight: +weight, weight: +weight,
reps: +reps, reps: +reps,
minutes: set.minutes,
seconds: set.seconds,
steps: set.steps,
image: set.image,
unit, unit,
created: now, created: now,
minutes,
seconds,
sets: best.sets,
hidden: false,
}); });
await refresh(); await refresh();
if ( if (
@ -108,26 +127,6 @@ export default function StartPlan() {
[toast], [toast],
); );
const select = useCallback(
async (index: number) => {
setSelected(index);
console.log(`${StartPlan.name}.next:`, {name, index});
if (!counts) return;
const workout = counts[index];
console.log(`${StartPlan.name}.next:`, {workout});
const newBest = await getBestSet(workout.name);
console.log(`${StartPlan.name}.next:`, {newBest});
setMinutes(newBest.minutes);
setSeconds(newBest.seconds);
setName(newBest.name);
setReps(newBest.reps.toString());
setWeight(newBest.weight.toString());
setUnit(newBest.unit);
setBest(newBest);
},
[name, counts],
);
return ( return (
<> <>
<StackHeader title={params.plan.days.replace(/,/g, ', ')} /> <StackHeader title={params.plan.days.replace(/,/g, ', ')} />

View File

@ -2,7 +2,6 @@ import {Picker} from '@react-native-picker/picker';
import {RouteProp, useRoute} from '@react-navigation/native'; import {RouteProp, useRoute} from '@react-navigation/native';
import {useEffect, useState} from 'react'; import {useEffect, useState} from 'react';
import {View} from 'react-native'; import {View} from 'react-native';
import {getOneRepMax} from './best.service';
import {BestPageParams} from './BestPage'; import {BestPageParams} from './BestPage';
import Chart from './Chart'; import Chart from './Chart';
import {PADDING} from './constants'; import {PADDING} from './constants';
@ -56,7 +55,14 @@ export default function ViewBest() {
.then(setVolumes); .then(setVolumes);
break; break;
default: default:
getOneRepMax({name: params.best.name, period}).then(setWeights); // Brzycki formula https://en.wikipedia.org/wiki/One-repetition_maximum#Brzycki
builder
.addSelect('MAX(weight / (1.0278 - 0.0278 * reps))', 'weight')
.getRawMany()
.then(weights => {
console.log({weights});
setWeights(weights);
});
} }
}, [params.best.name, metric, period]); }, [params.best.name, metric, period]);

View File

@ -2,8 +2,8 @@ module.exports = {
presets: ['module:metro-react-native-babel-preset'], presets: ['module:metro-react-native-babel-preset'],
plugins: [ plugins: [
'@babel/plugin-transform-flow-strip-types', '@babel/plugin-transform-flow-strip-types',
['@babel/plugin-proposal-class-properties', { loose: true }],
['@babel/plugin-proposal-decorators', { legacy: true }], ['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
'react-native-reanimated/plugin', 'react-native-reanimated/plugin',
'react-native-paper/babel', 'react-native-paper/babel',
], ],

View File

@ -1,31 +1,5 @@
import {db, setRepo} from './db'; import {setRepo} from './db';
import GymSet from './gym-set'; import GymSet from './gym-set';
import {Periods} from './periods';
export const getOneRepMax = async ({
name,
period,
}: {
name: string;
period: Periods;
}) => {
// Brzycki formula https://en.wikipedia.org/wiki/One-repetition_maximum#Brzycki
const select = `
SELECT max(weight / (1.0278 - 0.0278 * reps)) 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(?, created)
`;
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
let group = '%Y-%m-%d';
if (period === Periods.Yearly) group = '%Y-%m';
const [result] = await db.executeSql(select, [name, difference, group]);
return result.rows.raw();
};
export const getBestSet = async (name: string): Promise<GymSet> => { export const getBestSet = async (name: string): Promise<GymSet> => {
return setRepo return setRepo

58
data-source.ts Normal file
View File

@ -0,0 +1,58 @@
import {DataSource} from 'typeorm';
import GymSet from './gym-set';
import {Sets1667185586014} from './migrations/1667185586014-sets';
import {plans1667186124792} from './migrations/1667186124792-plans';
import {settings1667186130041} from './migrations/1667186130041-settings';
import {addSound1667186139844} from './migrations/1667186139844-add-sound';
import {addHidden1667186159379} from './migrations/1667186159379-add-hidden';
import {addNotify1667186166140} from './migrations/1667186166140-add-notify';
import {addImage1667186171548} from './migrations/1667186171548-add-image';
import {addImages1667186179488} from './migrations/1667186179488-add-images';
import {insertSettings1667186203827} from './migrations/1667186203827-insert-settings';
import {addSteps1667186211251} from './migrations/1667186211251-add-steps';
import {addSets1667186250618} from './migrations/1667186250618-add-sets';
import {addMinutes1667186255650} from './migrations/1667186255650-add-minutes';
import {addSeconds1667186259174} from './migrations/1667186259174-add-seconds';
import {addShowUnit1667186265588} from './migrations/1667186265588-add-show-unit';
import {addColor1667186320954} from './migrations/1667186320954-add-color';
import {addSteps1667186348425} from './migrations/1667186348425-add-steps';
import {addDate1667186431804} from './migrations/1667186431804-add-date';
import {addShowDate1667186435051} from './migrations/1667186435051-add-show-date';
import {addTheme1667186439366} from './migrations/1667186439366-add-theme';
import {addShowSets1667186443614} from './migrations/1667186443614-add-show-sets';
import {addSetsCreated1667186451005} from './migrations/1667186451005-add-sets-created';
import {addNoSound1667186456118} from './migrations/1667186456118-add-no-sound';
import {Plan} from './plan';
import Settings from './settings';
export const AppDataSource = new DataSource({
type: 'react-native',
database: 'massive.db',
location: 'default',
entities: [GymSet, Plan, Settings],
migrationsTableName: 'typeorm_migrations',
migrations: [
Sets1667185586014,
plans1667186124792,
settings1667186130041,
addSound1667186139844,
addHidden1667186159379,
addNotify1667186166140,
addImage1667186171548,
addImages1667186179488,
insertSettings1667186203827,
addSteps1667186211251,
addSets1667186250618,
addMinutes1667186255650,
addSeconds1667186259174,
addShowUnit1667186265588,
addColor1667186320954,
addSteps1667186348425,
addDate1667186431804,
addShowDate1667186435051,
addTheme1667186439366,
addShowSets1667186443614,
addSetsCreated1667186451005,
addNoSound1667186456118,
],
});

154
db.ts
View File

@ -1,143 +1,13 @@
import { import {enablePromise, SQLiteDatabase} from 'react-native-sqlite-storage';
enablePromise, import {AppDataSource} from './data-source';
openDatabase,
SQLiteDatabase,
} from 'react-native-sqlite-storage';
import {DataSource} from 'typeorm';
import GymSet from './gym-set'; import GymSet from './gym-set';
import {Plan} from './plan'; import {Plan} from './plan';
import Settings from './settings'; import Settings from './settings';
enablePromise(true); enablePromise(true);
const migrations = [
`
CREATE TABLE IF NOT EXISTS sets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
reps INTEGER NOT NULL,
weight INTEGER NOT NULL,
created TEXT NOT NULL,
unit TEXT DEFAULT 'kg'
)
`,
`
CREATE TABLE IF NOT EXISTS plans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
days TEXT NOT NULL,
workouts TEXT NOT NULL
)
`,
`
CREATE TABLE IF NOT EXISTS settings (
minutes INTEGER NOT NULL DEFAULT 3,
seconds INTEGER NOT NULL DEFAULT 30,
alarm BOOLEAN NOT NULL DEFAULT 0,
vibrate BOOLEAN NOT NULL DEFAULT 1,
sets INTEGER NOT NULL DEFAULT 3
)
`,
`ALTER TABLE settings ADD COLUMN sound TEXT NULL`,
`
CREATE TABLE IF NOT EXISTS workouts(
name TEXT PRIMARY KEY,
sets INTEGER DEFAULT 3
)
`,
`
ALTER TABLE sets ADD COLUMN hidden DEFAULT false
`,
`
ALTER TABLE settings ADD COLUMN notify DEFAULT false
`,
`
ALTER TABLE sets ADD COLUMN image TEXT NULL
`,
`
ALTER TABLE settings ADD COLUMN images BOOLEAN DEFAULT true
`,
`
SELECT * FROM settings LIMIT 1
`,
`
INSERT INTO settings(minutes) VALUES(3)
`,
`
ALTER TABLE workouts ADD COLUMN steps TEXT NULL
`,
`
INSERT OR IGNORE INTO workouts (name) SELECT DISTINCT name FROM sets
`,
`
ALTER TABLE sets ADD COLUMN sets INTEGER NOT NULL DEFAULT 3
`,
`
ALTER TABLE sets ADD COLUMN minutes INTEGER NOT NULL DEFAULT 3
`,
`
ALTER TABLE sets ADD COLUMN seconds INTEGER NOT NULL DEFAULT 30
`,
`
ALTER TABLE settings ADD COLUMN showUnit BOOLEAN DEFAULT true
`,
`
ALTER TABLE sets ADD COLUMN steps TEXT NULL
`,
`
UPDATE sets SET steps = (
SELECT workouts.steps FROM workouts WHERE workouts.name = sets.name
)
`,
`
DROP TABLE workouts
`,
`
ALTER TABLE settings ADD COLUMN color TEXT NULL
`,
`
UPDATE settings SET showUnit = 1
`,
`
ALTER TABLE settings ADD COLUMN workouts BOOLEAN DEFAULT true
`,
`
ALTER TABLE settings ADD COLUMN steps BOOLEAN DEFAULT true
`,
`
ALTER TABLE settings ADD COLUMN nextAlarm TEXT NULL
`,
`
ALTER TABLE settings ADD COLUMN newSet TEXT NULL
`,
`
ALTER TABLE settings ADD COLUMN date TEXT NULL
`,
`
ALTER TABLE settings ADD COLUMN showDate BOOLEAN DEFAULT false
`,
`
ALTER TABLE settings ADD COLUMN theme TEXT
`,
`
ALTER TABLE settings ADD COLUMN showSets BOOLEAN DEFAULT true
`,
`
CREATE INDEX sets_created ON sets(created)
`,
`
ALTER TABLE settings ADD COLUMN noSound BOOLEAN DEFAULT false
`,
];
export let db: SQLiteDatabase; export let db: SQLiteDatabase;
export const AppDataSource = new DataSource({
type: 'react-native',
database: 'massive.db',
location: 'default',
entities: [GymSet, Plan, Settings],
});
export const setRepo = AppDataSource.manager.getRepository(GymSet); export const setRepo = AppDataSource.manager.getRepository(GymSet);
export const planRepo = AppDataSource.manager.getRepository(Plan); export const planRepo = AppDataSource.manager.getRepository(Plan);
export const settingsRepo = AppDataSource.manager.getRepository(Settings); export const settingsRepo = AppDataSource.manager.getRepository(Settings);
@ -149,22 +19,8 @@ export const getNow = (): Promise<{now: string}[]> => {
}; };
export const runMigrations = async () => { export const runMigrations = async () => {
console.log(`${runMigrations.name}:`, 'Initializing...');
await AppDataSource.initialize(); await AppDataSource.initialize();
db = await openDatabase({name: 'massive.db'}); console.log(`${runMigrations.name}:`, 'Running migrations...');
await db.executeSql(` await AppDataSource.runMigrations();
CREATE TABLE IF NOT EXISTS migrations(
id INTEGER PRIMARY KEY AUTOINCREMENT,
command TEXT NOT NULL
)
`);
const [result] = await db.executeSql(`SELECT * FROM migrations`);
const missing = migrations.slice(result.rows.length);
for (const command of missing) {
await db.executeSql(command).catch(console.error);
const insert = `
INSERT INTO migrations (command)
VALUES (?)
`;
await db.executeSql(insert, [command]);
}
}; };

View File

@ -27,13 +27,13 @@ export default class GymSet {
hidden = false; hidden = false;
@Column('text') @Column('text')
created?: string; created: string;
@Column('text') @Column('text')
unit?: string; unit: string;
@Column('text') @Column('text')
image?: string; image: string;
@Column('text') @Column('text')
steps?: string; steps?: string;

View File

@ -0,0 +1,20 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class Sets1667185586014 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS sets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
reps INTEGER NOT NULL,
weight INTEGER NOT NULL,
created TEXT NOT NULL,
unit TEXT DEFAULT 'kg'
)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE sets`);
}
}

View File

@ -0,0 +1,17 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class plans1667186124792 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS plans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
days TEXT NOT NULL,
workouts TEXT NOT NULL
)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('plans');
}
}

View File

@ -0,0 +1,19 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class settings1667186130041 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS settings (
minutes INTEGER NOT NULL DEFAULT 3,
seconds INTEGER NOT NULL DEFAULT 30,
alarm BOOLEAN NOT NULL DEFAULT 0,
vibrate BOOLEAN NOT NULL DEFAULT 1,
sets INTEGER NOT NULL DEFAULT 3
)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('settings');
}
}

View File

@ -0,0 +1,11 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addSound1667186139844 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE settings ADD COLUMN sound TEXT NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'sound');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addHidden1667186159379 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE sets ADD COLUMN hidden DEFAULT false
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('sets', 'hidden');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addNotify1667186166140 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN notify DEFAULT false
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'notify');
}
}

View File

@ -0,0 +1,11 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addImage1667186171548 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE sets ADD COLUMN image TEXT NULL');
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('sets', 'image');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addImages1667186179488 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN images BOOLEAN DEFAULT true
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'images');
}
}

View File

@ -0,0 +1,11 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class insertSettings1667186203827 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('INSERT INTO settings(minutes) VALUES(3)');
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('DELETE FROM settings');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addSteps1667186211251 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN steps BOOLEAN DEFAULT true
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'steps');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addSets1667186250618 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE sets ADD COLUMN sets INTEGER NOT NULL DEFAULT 3
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('sets', 'sets');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addMinutes1667186255650 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE sets ADD COLUMN minutes INTEGER NOT NULL DEFAULT 3
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('sets', 'minutes');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addSeconds1667186259174 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE sets ADD COLUMN seconds INTEGER NOT NULL DEFAULT 30
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('sets', 'seconds');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addShowUnit1667186265588 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN showUnit BOOLEAN DEFAULT true
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'showUnit');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addColor1667186320954 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN color TEXT NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'color');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addSteps1667186348425 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE sets ADD COLUMN steps TEXT NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('sets', 'steps');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addDate1667186431804 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN date TEXT NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'date');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addShowDate1667186435051 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN showDate BOOLEAN DEFAULT false
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'showDate');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addTheme1667186439366 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN theme TEXT
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'theme');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addShowSets1667186443614 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN showSets BOOLEAN DEFAULT true
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'showSets');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addSetsCreated1667186451005 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE INDEX sets_created ON sets(created)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropIndex('sets', 'sets_created');
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class addNoSound1667186456118 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE settings ADD COLUMN noSound BOOLEAN DEFAULT false
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('settings', 'noSound');
}
}

View File

@ -1,5 +1,4 @@
import {Plan} from './plan'; import {Plan} from './plan';
import GymSet from './gym-set';
export type PlanPageParams = { export type PlanPageParams = {
PlanList: {}; PlanList: {};
@ -8,6 +7,5 @@ export type PlanPageParams = {
}; };
StartPlan: { StartPlan: {
plan: Plan; plan: Plan;
set: GymSet;
}; };
}; };

View File

@ -1,19 +0,0 @@
import CountMany from './count-many';
import {db} from './db';
export const countMany = async (names: string[]): Promise<CountMany[]> => {
const questions = names.map(_ => '(?)').join(',');
console.log({questions, names});
const select = `
SELECT workouts.name, COUNT(sets.id) as total
FROM (select 0 as name union values ${questions}) as workouts
LEFT JOIN sets ON sets.name = workouts.name
AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime')
AND NOT sets.hidden
GROUP BY workouts.name
LIMIT -1
OFFSET 1
`;
const [result] = await db.executeSql(select, names);
return result.rows.raw();
};