From b7f1c2192ee3c717590a319d4ec7568f91989474 Mon Sep 17 00:00:00 2001 From: Brandon Presley Date: Mon, 31 Oct 2022 13:20:36 +1300 Subject: [PATCH] Pause converting to typeorm due to odd error ERROR TypeError: Cannot read property 'getItem' of undefined This error is located at: in FlatList (created by SetList) in RCTView (created by View) in View (created by Page) in Page (created by SetList) in SetList (created by SceneView) ... I found an open issue on the react-native github which seems related https://github.com/facebook/react-native/issues/31523 but after following all of their suggestions I still have the same error. I tried: - Removing @babel/plugin-proposal-class-properties & @babel/plugin-transform-flow-strip-types - Adding @babel/plugin-transform-flow-strip-types --- .prettierrc.js | 2 +- App.tsx | 5 +- BestList.tsx | 29 ++++- BestPage.tsx | 4 +- Chart.tsx | 4 +- DrawerMenu.tsx | 56 ++++---- EditPlan.tsx | 25 ++-- EditSet.tsx | 39 +++--- EditWorkout.tsx | 35 +++-- PlanItem.tsx | 5 +- PlanList.tsx | 9 +- SetForm.tsx | 13 +- SetItem.tsx | 10 +- SetList.tsx | 56 +++++--- SettingsPage.tsx | 32 ++--- StartPlan.tsx | 38 ++++-- StartPlanItem.tsx | 11 +- ViewBest.tsx | 33 ++++- WorkoutItem.tsx | 8 +- WorkoutList.tsx | 37 +++--- WorkoutsPage.tsx | 4 +- babel.config.js | 8 +- best.service.ts | 102 ++------------- db.ts | 22 ++++ gym-set.ts | 40 ++++++ home-page-params.ts | 4 +- index.js | 12 +- package.json | 6 +- plan-page-params.ts | 4 +- plan.service.ts | 60 --------- plan.ts | 10 +- set.service.ts | 187 --------------------------- set.ts | 14 -- settings.service.ts | 23 ---- settings.ts | 50 ++++++-- tsconfig.json | 6 +- yarn.lock | 304 ++++++++++++++++++++++++++++++++++++++++++-- 37 files changed, 721 insertions(+), 586 deletions(-) create mode 100644 gym-set.ts delete mode 100644 plan.service.ts delete mode 100644 set.ts delete mode 100644 settings.service.ts diff --git a/.prettierrc.js b/.prettierrc.js index 2b54074..11ff33d 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -4,4 +4,4 @@ module.exports = { bracketSpacing: false, singleQuote: true, trailingComma: 'all', -}; +} diff --git a/App.tsx b/App.tsx index aac63f7..086090e 100644 --- a/App.tsx +++ b/App.tsx @@ -13,11 +13,10 @@ import { import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; import {Color} from './color'; import {lightColors} from './colors'; -import {runMigrations} from './db'; +import {runMigrations, settingsRepo} from './db'; import MassiveSnack from './MassiveSnack'; import Routes from './Routes'; import Settings from './settings'; -import {getSettings} from './settings.service'; import {SettingsContext} from './use-settings'; export const CombinedDefaultTheme = { @@ -51,7 +50,7 @@ const App = () => { useEffect(() => { runMigrations().then(async () => { - const gotSettings = await getSettings(); + const gotSettings = await settingsRepo.findOne({where: {}}); console.log(`${App.name}.runMigrations:`, {gotSettings}); setSettings(gotSettings); if (gotSettings.color) setColor(gotSettings.color); diff --git a/BestList.tsx b/BestList.tsx index 97cf8e1..90f1212 100644 --- a/BestList.tsx +++ b/BestList.tsx @@ -6,25 +6,40 @@ import { import {useCallback, useState} from 'react'; import {FlatList, Image} from 'react-native'; import {List} from 'react-native-paper'; -import {getBestReps, getBestWeights} from './best.service'; import {BestPageParams} from './BestPage'; +import {setRepo} from './db'; import DrawerHeader from './DrawerHeader'; +import GymSet from './gym-set'; import Page from './Page'; -import Set from './set'; import {useSettings} from './use-settings'; export default function BestList() { - const [bests, setBests] = useState(); + const [bests, setBests] = useState(); const [term, setTerm] = useState(''); const navigation = useNavigation>(); const {settings} = useSettings(); const refresh = useCallback(async (value: string) => { - const weights = await getBestWeights(value); + const weights = await setRepo + .createQueryBuilder() + .select() + .addSelect('MAX(weight)', 'weight') + .where('name LIKE :name', {name: `%${value}%`}) + .andWhere('NOT hidden') + .groupBy('name') + .getMany(); console.log(`${BestList.name}.refresh:`, {length: weights.length}); - let newBest: Set[] = []; + let newBest: GymSet[] = []; for (const set of weights) { - const reps = await getBestReps(set.name, set.weight); + const reps = await setRepo + .createQueryBuilder() + .select() + .addSelect('MAX(reps)', 'reps') + .where('name = :name', {name: set.name}) + .andWhere('weight = :weight', {weight: set.weight}) + .andWhere('NOT hidden') + .groupBy('name') + .getMany(); newBest.push(...reps); } setBests(newBest); @@ -44,7 +59,7 @@ export default function BestList() { [refresh], ); - const renderItem = ({item}: {item: Set}) => ( + const renderItem = ({item}: {item: GymSet}) => ( (); export type BestPageParams = { BestList: {}; ViewBest: { - best: Set; + best: GymSet; }; }; diff --git a/Chart.tsx b/Chart.tsx index a035658..0c1ba81 100644 --- a/Chart.tsx +++ b/Chart.tsx @@ -4,7 +4,7 @@ import {Grid, LineChart, XAxis, YAxis} from 'react-native-svg-charts'; import {CombinedDarkTheme, CombinedDefaultTheme} from './App'; import {useColor} from './color'; import {MARGIN, PADDING} from './constants'; -import Set from './set'; +import GymSet from './gym-set'; import useDark from './use-dark'; export default function Chart({ @@ -14,7 +14,7 @@ export default function Chart({ yFormat, }: { yData: number[]; - xData: Set[]; + xData: GymSet[]; xFormat: (value: any, index: number) => string; yFormat: (value: any) => string; }) { diff --git a/DrawerMenu.tsx b/DrawerMenu.tsx index b73da37..5f93d5e 100644 --- a/DrawerMenu.tsx +++ b/DrawerMenu.tsx @@ -4,18 +4,18 @@ import DocumentPicker from 'react-native-document-picker'; import {FileSystem} from 'react-native-file-access'; import {Divider, IconButton, Menu} from 'react-native-paper'; import ConfirmDialog from './ConfirmDialog'; +import {AppDataSource, planRepo} from './db'; import {DrawerParamList} from './drawer-param-list'; +import GymSet from './gym-set'; import {useSnackbar} from './MassiveSnack'; import {Plan} from './plan'; -import {addPlans, deletePlans, getAllPlans} from './plan.service'; -import Set from './set'; -import {addSets, deleteSets, getAllSets} from './set.service'; import useDark from './use-dark'; import {write} from './write'; const setFields = 'id,name,reps,weight,created,unit,hidden,sets,minutes,seconds'; const planFields = 'id,days,workouts'; +const setRepo = AppDataSource.manager.getRepository(GymSet); export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { const [showMenu, setShowMenu] = useState(false); @@ -25,14 +25,14 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { const dark = useDark(); const exportSets = useCallback(async () => { - const sets = await getAllSets(); + const sets = await setRepo.find({}); const data = [setFields] .concat( sets.map(set => setFields .split(',') .map(fieldString => { - const field = fieldString as keyof Set; + const field = fieldString as keyof GymSet; if (field === 'unit') return set[field] || 'kg'; return set[field]; }) @@ -45,7 +45,7 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { }, []); const exportPlans = useCallback(async () => { - const plans: Plan[] = await getAllPlans(); + const plans = await planRepo.find({}); const data = [planFields] .concat(plans.map(set => `"${set.id}","${set.days}","${set.workouts}"`)) .join('\n'); @@ -62,14 +62,14 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { const uploadSets = useCallback(async () => { const result = await DocumentPicker.pickSingle(); const file = await FileSystem.readFile(result.uri); - console.log(`${DrawerMenu.name}.${uploadSets.name}:`, file.length); + console.log(`${DrawerMenu.name}.uploadSets:`, file.length); const lines = file.split('\n'); console.log(lines[0]); if (!setFields.includes(lines[0])) return toast('Invalid csv.', 3000); const values = lines .slice(1) .filter(line => line) - .map(set => { + .map(line => { let [ , setName, @@ -81,15 +81,22 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { sets, minutes, seconds, - ] = set.split(','); - unit = unit || 'kg'; - hidden = hidden || '0'; - return `('${setName}',${reps},${weight},'${created}','${unit}',${hidden},${ - sets ?? 3 - },${minutes ?? 3},${seconds ?? 30})`; - }) - .join(','); - await addSets(setFields.split(',').slice(1).join(','), values); + ] = line.split(','); + const set: GymSet = { + name: setName, + reps: +reps, + weight: +weight, + created, + unit: unit ?? 'kg', + hidden: !!Number(hidden), + sets: +sets, + minutes: +minutes, + seconds: +seconds, + }; + return set; + }); + console.log(`${DrawerMenu.name}.uploadSets:`, {values}); + await setRepo.insert(values); toast('Data imported.', 3000); reset({index: 0, routes: [{name}]}); }, [reset, name, toast]); @@ -108,10 +115,13 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { const [, days, workouts] = set .split('","') .map(cell => cell.replace(/"/g, '')); - return `('${days}','${workouts}')`; - }) - .join(','); - await addPlans(values); + const plan: Plan = { + days, + workouts, + }; + return plan; + }); + await planRepo.insert(values); toast('Data imported.', 3000); }, [toast]); @@ -125,8 +135,8 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) { const remove = useCallback(async () => { setShowMenu(false); setShowRemove(false); - if (name === 'Home') await deleteSets(); - else if (name === 'Plans') await deletePlans(); + if (name === 'Home') await setRepo.delete({}); + else if (name === 'Plans') await planRepo.delete({}); toast('All data has been deleted.', 4000); reset({index: 0, routes: [{name}]}); }, [reset, name, toast]); diff --git a/EditPlan.tsx b/EditPlan.tsx index 0536d40..a12f22e 100644 --- a/EditPlan.tsx +++ b/EditPlan.tsx @@ -8,10 +8,9 @@ import {useCallback, useEffect, useState} from 'react'; import {ScrollView, StyleSheet, View} from 'react-native'; import {Button, Text} from 'react-native-paper'; import {MARGIN, PADDING} from './constants'; +import {planRepo, setRepo} from './db'; import {DrawerParamList} from './drawer-param-list'; import {PlanPageParams} from './plan-page-params'; -import {addPlan, updatePlan} from './plan.service'; -import {getNames} from './set.service'; import StackHeader from './StackHeader'; import Switch from './Switch'; import {DAYS} from './time'; @@ -29,10 +28,15 @@ export default function EditPlan() { const navigation = useNavigation>(); useEffect(() => { - getNames().then(n => { - console.log(EditPlan.name, {n}); - setNames(n); - }); + setRepo + .createQueryBuilder() + .select('name') + .distinct(true) + .getRawMany() + .then(values => { + console.log(EditPlan.name, {values}); + setNames(values.map(value => value.name)); + }); }, []); const save = useCallback(async () => { @@ -40,14 +44,7 @@ export default function EditPlan() { if (!days || !workouts) return; const newWorkouts = workouts.filter(workout => workout).join(','); const newDays = days.filter(day => day).join(','); - if (typeof plan.id === 'undefined') - await addPlan({days: newDays, workouts: newWorkouts}); - else - await updatePlan({ - days: newDays, - workouts: newWorkouts, - id: plan.id, - }); + await planRepo.save({days: newDays, workouts: newWorkouts, id: plan.id}); navigation.goBack(); }, [days, workouts, plan, navigation]); diff --git a/EditSet.tsx b/EditSet.tsx index a346ddb..ecca964 100644 --- a/EditSet.tsx +++ b/EditSet.tsx @@ -2,10 +2,10 @@ import {RouteProp, useNavigation, useRoute} from '@react-navigation/native'; import {useCallback} from 'react'; import {NativeModules, View} from 'react-native'; import {PADDING} from './constants'; +import {getNow, setRepo} from './db'; +import GymSet from './gym-set'; import {HomePageParams} from './home-page-params'; import {useSnackbar} from './MassiveSnack'; -import Set from './set'; -import {addSet, getSet, updateSet} from './set.service'; import SetForm from './SetForm'; import StackHeader from './StackHeader'; import {useSettings} from './use-settings'; @@ -20,7 +20,7 @@ export default function EditSet() { const startTimer = useCallback( async (name: string) => { if (!settings.alarm) return; - const {minutes, seconds} = await getSet(name); + const {minutes, seconds} = await setRepo.findOne({where: {name}}); const milliseconds = (minutes ?? 3) * 60 * 1000 + (seconds ?? 0) * 1000; NativeModules.AlarmModule.timer( milliseconds, @@ -32,37 +32,32 @@ export default function EditSet() { [settings], ); - const update = useCallback( - async (value: Set) => { - console.log(`${EditSet.name}.update`, value); - await updateSet(value); - navigation.goBack(); - }, - [navigation], - ); - const add = useCallback( - async (value: Set) => { - console.log(`${EditSet.name}.add`, {set: value}); + async (value: GymSet) => { startTimer(value.name); - await addSet(value); - if (!settings.notify) return navigation.goBack(); + const [{now}] = await getNow(); + value.created = now; + value.hidden = false; + console.log(`${EditSet.name}.add`, {set: value}); + const result = await setRepo.save(value); + console.log({result}); + if (!settings.notify) return; if ( value.weight > set.weight || (value.reps > set.reps && value.weight === set.weight) ) toast("Great work King! That's a new record.", 3000); - navigation.goBack(); }, - [navigation, startTimer, set, toast, settings], + [startTimer, set, toast, settings], ); const save = useCallback( - async (value: Set) => { - if (typeof set.id === 'number') return update(value); - return add(value); + async (value: GymSet) => { + if (typeof set.id === 'number') await setRepo.save(value); + else await add(value); + navigation.goBack(); }, - [update, add, set.id], + [add, set.id, navigation], ); return ( diff --git a/EditWorkout.tsx b/EditWorkout.tsx index 6a6f09d..206f8d0 100644 --- a/EditWorkout.tsx +++ b/EditWorkout.tsx @@ -3,12 +3,12 @@ import {useCallback, useRef, useState} from 'react'; import {ScrollView, TextInput, View} from 'react-native'; import DocumentPicker from 'react-native-document-picker'; import {Button, Card, TouchableRipple} from 'react-native-paper'; +import {Like} from 'typeorm'; import ConfirmDialog from './ConfirmDialog'; import {MARGIN, PADDING} from './constants'; +import {getNow, planRepo, setRepo} from './db'; import MassiveInput from './MassiveInput'; import {useSnackbar} from './MassiveSnack'; -import {updatePlanWorkouts} from './plan.service'; -import {addSet, updateManySet, updateSetImage} from './set.service'; import StackHeader from './StackHeader'; import {useSettings} from './use-settings'; import {WorkoutsPageParams} from './WorkoutsPage'; @@ -36,21 +36,29 @@ export default function EditWorkout() { const {settings} = useSettings(); const update = async () => { - await updateManySet({ - oldName: params.value.name, - newName: name || params.value.name, - sets: sets ?? '3', - seconds: seconds?.toString() ?? '30', - minutes: minutes?.toString() ?? '3', - steps, - }); - await updatePlanWorkouts(params.value.name, name || params.value.name); - if (uri || removeImage) await updateSetImage(params.value.name, uri || ''); + await setRepo.update( + {name: params.value.name}, + { + name: name || params.value.name, + sets: Number(sets), + minutes: +minutes, + seconds: +seconds, + steps, + image: removeImage ? '' : uri, + }, + ); + await planRepo.query( + `UPDATE plans + SET workouts = REPLACE(workouts, $1, $2) + WHERE workouts LIKE $3`, + [params.value.name, name, `%${params.value.name}%`], + ); navigation.goBack(); }; const add = async () => { - await addSet({ + const [{now}] = await getNow(); + await setRepo.save({ name, reps: 0, weight: 0, @@ -60,6 +68,7 @@ export default function EditWorkout() { seconds: seconds ? +seconds : 30, sets: sets ? +sets : 3, steps, + created: now, }); navigation.goBack(); }; diff --git a/PlanItem.tsx b/PlanItem.tsx index 1e15568..22c559a 100644 --- a/PlanItem.tsx +++ b/PlanItem.tsx @@ -7,9 +7,9 @@ import {useCallback, useMemo, useState} from 'react'; import {GestureResponderEvent, Text} from 'react-native'; import {Divider, List, Menu} from 'react-native-paper'; import {getBestSet} from './best.service'; +import {planRepo} from './db'; import {Plan} from './plan'; import {PlanPageParams} from './plan-page-params'; -import {deletePlan} from './plan.service'; import {DAYS} from './time'; export default function PlanItem({ @@ -33,7 +33,7 @@ export default function PlanItem({ ); const remove = useCallback(async () => { - if (typeof item.id === 'number') await deletePlan(item.id); + if (typeof item.id === 'number') await planRepo.delete(item.id); setShow(false); onRemove(); }, [setShow, item.id, onRemove]); @@ -42,6 +42,7 @@ export default function PlanItem({ const workouts = item.workouts.split(','); const first = workouts[0]; const set = await getBestSet(first); + console.log(`${PlanItem.name}.start:`, {set}); setShow(false); navigation.navigate('StartPlan', {plan: item, set}); }, [item, navigation]); diff --git a/PlanList.tsx b/PlanList.tsx index 81d3cc6..0153169 100644 --- a/PlanList.tsx +++ b/PlanList.tsx @@ -6,11 +6,12 @@ import { import {useCallback, useState} from 'react'; import {FlatList} from 'react-native'; import {List} from 'react-native-paper'; +import {Like} from 'typeorm'; +import {planRepo} from './db'; import DrawerHeader from './DrawerHeader'; import Page from './Page'; import {Plan} from './plan'; import {PlanPageParams} from './plan-page-params'; -import {getPlans} from './plan.service'; import PlanItem from './PlanItem'; export default function PlanList() { @@ -19,7 +20,11 @@ export default function PlanList() { const navigation = useNavigation>(); const refresh = useCallback(async (value: string) => { - getPlans(value).then(setPlans); + planRepo + .find({ + where: [{days: Like(`%${value}%`)}, {workouts: Like(`%${value}%`)}], + }) + .then(setPlans); }, []); useFocusEffect( diff --git a/SetForm.tsx b/SetForm.tsx index 3d72a4b..23c9c0d 100644 --- a/SetForm.tsx +++ b/SetForm.tsx @@ -4,18 +4,18 @@ import DocumentPicker from 'react-native-document-picker'; import {Button, Card, TouchableRipple} from 'react-native-paper'; import ConfirmDialog from './ConfirmDialog'; import {MARGIN} from './constants'; +import {setRepo} from './db'; +import GymSet from './gym-set'; import MassiveInput from './MassiveInput'; import {useSnackbar} from './MassiveSnack'; -import Set from './set'; -import {getSets} from './set.service'; import {useSettings} from './use-settings'; export default function SetForm({ save, set, }: { - set: Set; - save: (set: Set) => void; + set: GymSet; + save: (set: GymSet) => void; }) { const [name, setName] = useState(set.name); const [reps, setReps] = useState(set.reps.toString()); @@ -39,9 +39,8 @@ export default function SetForm({ if (!name) return; let image = newImage; if (!newImage && !removeImage) - image = await getSets({term: name, limit: 1, offset: 0}).then( - ([gotSet]) => gotSet?.image, - ); + image = await setRepo.findOne({where: {name}}).then(s => s.image); + console.log(`${SetForm.name}.handleSubmit:`, {image}); save({ name, diff --git a/SetItem.tsx b/SetItem.tsx index eaa3fc8..da84ed3 100644 --- a/SetItem.tsx +++ b/SetItem.tsx @@ -2,9 +2,9 @@ import {NavigationProp, useNavigation} from '@react-navigation/native'; import {useCallback, useState} from 'react'; import {GestureResponderEvent, Image} from 'react-native'; import {Divider, List, Menu, Text} from 'react-native-paper'; +import {setRepo} from './db'; +import GymSet from './gym-set'; import {HomePageParams} from './home-page-params'; -import Set from './set'; -import {deleteSet} from './set.service'; import {format} from './time'; import useDark from './use-dark'; import {useSettings} from './use-settings'; @@ -13,7 +13,7 @@ export default function SetItem({ item, onRemove, }: { - item: Set; + item: GymSet; onRemove: () => void; }) { const [showMenu, setShowMenu] = useState(false); @@ -23,13 +23,13 @@ export default function SetItem({ const navigation = useNavigation>(); const remove = useCallback(async () => { - if (typeof item.id === 'number') await deleteSet(item.id); + if (typeof item.id === 'number') await setRepo.delete(item.id); setShowMenu(false); onRemove(); }, [setShowMenu, onRemove, item.id]); const copy = useCallback(() => { - const set: Set = {...item}; + const set: GymSet = {...item}; delete set.id; setShowMenu(false); navigation.navigate('EditSet', {set}); diff --git a/SetList.tsx b/SetList.tsx index f8179fa..92a9927 100644 --- a/SetList.tsx +++ b/SetList.tsx @@ -3,35 +3,37 @@ import { useFocusEffect, useNavigation, } from '@react-navigation/native'; -import {useCallback, useState} from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; import {FlatList} from 'react-native'; import {List} from 'react-native-paper'; +import {Like} from 'typeorm'; +import {getNow, setRepo} from './db'; import DrawerHeader from './DrawerHeader'; +import GymSet from './gym-set'; import {HomePageParams} from './home-page-params'; import Page from './Page'; -import Set from './set'; -import {defaultSet, getSets, getToday} from './set.service'; import SetItem from './SetItem'; const limit = 15; export default function SetList() { - const [sets, setSets] = useState(); - const [set, setSet] = useState(); + const [sets, setSets] = useState([]); + const [set, setSet] = useState(); const [offset, setOffset] = useState(0); const [term, setTerm] = useState(''); const [end, setEnd] = useState(false); const navigation = useNavigation>(); + useEffect(() => console.log({sets}), [sets]); + const refresh = useCallback(async (value: string) => { - const todaysSet = await getToday(); - if (todaysSet) setSet({...todaysSet}); - const newSets = await getSets({ - term: `%${value}%`, - limit, - offset: 0, + const newSets = await setRepo.find({ + where: {name: Like(`%${value}%`), hidden: 0 as any}, + take: limit, + skip: 0, + order: {created: 'DESC'}, }); - console.log(`${SetList.name}.refresh:`, {newSets}); + setSet(newSets[0]); if (newSets.length === 0) return setSets([]); setSets(newSets); setOffset(0); @@ -45,7 +47,7 @@ export default function SetList() { ); const renderItem = useCallback( - ({item}: {item: Set}) => ( + ({item}: {item: GymSet}) => ( refresh(term)} /> ), [refresh, term], @@ -55,22 +57,33 @@ export default function SetList() { if (end) return; const newOffset = offset + limit; console.log(`${SetList.name}.next:`, {offset, newOffset, term}); - const newSets = await getSets({ - term: `%${term}%`, - limit, - offset: newOffset, + const newSets = await setRepo.find({ + where: {name: Like(`%${term}%`), hidden: 0 as any}, + take: limit, + skip: newOffset, + order: {created: 'DESC'}, }); if (newSets.length === 0) return setEnd(true); if (!sets) return; - setSets([...sets, ...newSets]); + // setSets([...sets, ...newSets]); if (newSets.length < limit) return setEnd(true); setOffset(newOffset); }, [term, end, offset, sets]); const onAdd = useCallback(async () => { console.log(`${SetList.name}.onAdd`, {set}); + const [{now}] = await getNow(); navigation.navigate('EditSet', { - set: set || {...defaultSet}, + set: set || { + hidden: false, + minutes: 3, + name: '', + reps: 0, + seconds: 30, + sets: 3, + weight: 0, + created: now, + }, }); }, [navigation, set]); @@ -96,7 +109,10 @@ export default function SetList() { data={sets} style={{flex: 1}} renderItem={renderItem} - keyExtractor={s => s.id!.toString()} + getItem={(data: any, index: number) => { + console.log({data, index}); + return data[index]; + }} onEndReached={next} /> )} diff --git a/SettingsPage.tsx b/SettingsPage.tsx index 4cb4872..def0f63 100644 --- a/SettingsPage.tsx +++ b/SettingsPage.tsx @@ -8,12 +8,12 @@ import {useColor} from './color'; import {darkColors, lightColors} from './colors'; import ConfirmDialog from './ConfirmDialog'; import {MARGIN} from './constants'; +import {settingsRepo} from './db'; import DrawerHeader from './DrawerHeader'; import Input from './input'; import {useSnackbar} from './MassiveSnack'; import Page from './Page'; import Settings from './settings'; -import {updateSettings} from './settings.service'; import Switch from './Switch'; import {useSettings} from './use-settings'; @@ -50,8 +50,8 @@ export default function SettingsPage() { const update = useCallback( (value: boolean, field: keyof Settings) => { - updateSettings({...settings, [field]: +value}); - setSettings({...settings, [field]: +value}); + settingsRepo.update({}, {[field]: value}); + setSettings({...settings, [field]: value}); }, [settings, setSettings], ); @@ -81,7 +81,7 @@ export default function SettingsPage() { copyTo: 'documentDirectory', }); if (!fileCopyUri) return; - updateSettings({sound: fileCopyUri} as Settings); + settingsRepo.update({}, {sound: fileCopyUri}); setSettings({...settings, sound: fileCopyUri}); toast('This song will now play after rest timers complete.', 4000); }, [toast, setSettings, settings]); @@ -150,28 +150,28 @@ export default function SettingsPage() { ); const switches: Input[] = [ - {name: 'Rest timers', value: !!alarm, onChange: changeAlarmEnabled}, - {name: 'Vibrate', value: !!vibrate, onChange: changeVibrate}, - {name: 'Disable sound', value: !!noSound, onChange: changeNoSound}, - {name: 'Record notifications', value: !!notify, onChange: changeNotify}, - {name: 'Show images', value: !!images, onChange: changeImages}, - {name: 'Show unit', value: !!showUnit, onChange: changeUnit}, - {name: 'Show steps', value: !!steps, onChange: changeSteps}, - {name: 'Show date', value: !!showDate, onChange: changeShowDate}, - {name: 'Show sets', value: !!showSets, onChange: changeShowSets}, + {name: 'Rest timers', value: alarm, onChange: changeAlarmEnabled}, + {name: 'Vibrate', value: vibrate, onChange: changeVibrate}, + {name: 'Disable sound', value: noSound, onChange: changeNoSound}, + {name: 'Record notifications', value: notify, onChange: changeNotify}, + {name: 'Show images', value: images, onChange: changeImages}, + {name: 'Show unit', value: showUnit, onChange: changeUnit}, + {name: 'Show steps', value: steps, onChange: changeSteps}, + {name: 'Show date', value: showDate, onChange: changeShowDate}, + {name: 'Show sets', value: showSets, onChange: changeShowSets}, ]; const changeTheme = useCallback( (value: string) => { - updateSettings({...settings, theme: value as any}); - setSettings({...settings, theme: value as any}); + settingsRepo.update({}, {theme: value}); + setSettings({...settings, theme: value}); }, [settings, setSettings], ); const changeDate = useCallback( (value: string) => { - updateSettings({...settings, date: value as any}); + settingsRepo.update({}, {date: value}); setSettings({...settings, date: value as any}); }, [settings, setSettings], diff --git a/StartPlan.tsx b/StartPlan.tsx index 2598f6a..68361e5 100644 --- a/StartPlan.tsx +++ b/StartPlan.tsx @@ -6,11 +6,12 @@ import {Button} from 'react-native-paper'; import {getBestSet} from './best.service'; import {PADDING} from './constants'; import CountMany from './count-many'; +import {AppDataSource, getNow, setRepo} from './db'; +import GymSet from './gym-set'; import MassiveInput from './MassiveInput'; import {useSnackbar} from './MassiveSnack'; import {PlanPageParams} from './plan-page-params'; -import Set from './set'; -import {addSet, countMany} from './set.service'; +import {countMany} from './set.service'; import SetForm from './SetForm'; import StackHeader from './StackHeader'; import StartPlanItem from './StartPlanItem'; @@ -26,7 +27,7 @@ export default function StartPlan() { const {toast} = useSnackbar(); const [minutes, setMinutes] = useState(set.minutes); const [seconds, setSeconds] = useState(set.seconds); - const [best, setBest] = useState(set); + const [best, setBest] = useState(set); const [selected, setSelected] = useState(0); const {settings} = useSettings(); const [counts, setCounts] = useState(); @@ -41,10 +42,26 @@ export default function StartPlan() { }); const refresh = useCallback(() => { - return countMany(workouts).then(newCounts => { - setCounts(newCounts); - console.log(`${StartPlan.name}.focus:`, {newCounts}); - }); + const questions = workouts.map(_ => '(?)').join(','); + const condition = ` + sets.name = workouts.name + AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime') + AND NOT sets.hidden + `; + return AppDataSource.manager + .createQueryBuilder() + .select('COUNT(sets.id)', 'total') + .addSelect('workouts') + .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]); useFocusEffect( @@ -55,7 +72,8 @@ export default function StartPlan() { const handleSubmit = async () => { console.log(`${SetForm.name}.handleSubmit:`, {reps, weight, unit, best}); - await addSet({ + const [{now}] = await getNow(); + await setRepo.save({ name, weight: +weight, reps: +reps, @@ -64,6 +82,7 @@ export default function StartPlan() { steps: set.steps, image: set.image, unit, + created: now, }); await refresh(); if ( @@ -92,11 +111,12 @@ export default function StartPlan() { const select = useCallback( async (index: number) => { setSelected(index); - console.log(`${StartPlan.name}.next:`, {name}); + 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); diff --git a/StartPlanItem.tsx b/StartPlanItem.tsx index ba9b291..d618b84 100644 --- a/StartPlanItem.tsx +++ b/StartPlanItem.tsx @@ -3,7 +3,7 @@ import {GestureResponderEvent, ListRenderItemInfo, View} from 'react-native'; import {List, Menu, RadioButton} from 'react-native-paper'; import {useColor} from './color'; import CountMany from './count-many'; -import {deleteFirst} from './set.service'; +import {setRepo} from './db'; interface Props extends ListRenderItemInfo { onSelect: (index: number) => void; @@ -18,10 +18,15 @@ export default function StartPlanItem(props: Props) { const [showMenu, setShowMenu] = useState(false); const undo = useCallback(async () => { - await deleteFirst(item.name); + const first = await setRepo.findOne({ + where: {name: item.name, hidden: 0 as any}, + order: {created: 'desc'}, + }); + console.log({first}); + await setRepo.delete(first.id); setShowMenu(false); onUndo(); - }, [setShowMenu, item.name, onUndo]); + }, [setShowMenu, onUndo, item.name]); const longPress = useCallback( (e: GestureResponderEvent) => { diff --git a/ViewBest.tsx b/ViewBest.tsx index a9ca740..ae25a8a 100644 --- a/ViewBest.tsx +++ b/ViewBest.tsx @@ -2,13 +2,14 @@ import {Picker} from '@react-native-picker/picker'; import {RouteProp, useRoute} from '@react-navigation/native'; import {useEffect, useState} from 'react'; import {View} from 'react-native'; -import {getOneRepMax, getVolumes, getWeightsBy} from './best.service'; +import {getOneRepMax} from './best.service'; import {BestPageParams} from './BestPage'; import Chart from './Chart'; import {PADDING} from './constants'; +import {setRepo} from './db'; +import GymSet from './gym-set'; import {Metrics} from './metrics'; import {Periods} from './periods'; -import Set from './set'; import StackHeader from './StackHeader'; import {formatMonth} from './time'; import useDark from './use-dark'; @@ -17,7 +18,7 @@ import Volume from './volume'; export default function ViewBest() { const {params} = useRoute>(); const dark = useDark(); - const [weights, setWeights] = useState([]); + const [weights, setWeights] = useState([]); const [volumes, setVolumes] = useState([]); const [metric, setMetric] = useState(Metrics.Weight); const [period, setPeriod] = useState(Periods.Monthly); @@ -25,12 +26,34 @@ export default function ViewBest() { useEffect(() => { console.log(`${ViewBest.name}.useEffect`, {metric}); console.log(`${ViewBest.name}.useEffect`, {period}); + 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 builder = setRepo + .createQueryBuilder() + .select("STRFTIME('%Y-%m-%d', created)", 'created') + .addSelect('unit') + .where('name = :name', {name: params.best.name}) + .andWhere('NOT hidden') + .andWhere("DATE(created) >= DATE('now', 'weekday 0', :difference)", { + difference, + }) + .groupBy('name') + .addGroupBy(`STRFTIME('${group}', created)`); switch (metric) { case Metrics.Weight: - getWeightsBy(params.best.name, period).then(setWeights); + builder + .addSelect('MAX(weight)', 'weight') + .getRawMany() + .then(setWeights); break; case Metrics.Volume: - getVolumes(params.best.name, period).then(setVolumes); + builder + .addSelect('SUM(weight * reps)', 'value') + .getRawMany() + .then(setVolumes); break; default: getOneRepMax({name: params.best.name, period}).then(setWeights); diff --git a/WorkoutItem.tsx b/WorkoutItem.tsx index faa2bab..6132b0e 100644 --- a/WorkoutItem.tsx +++ b/WorkoutItem.tsx @@ -3,8 +3,8 @@ import {useCallback, useMemo, useState} from 'react'; import {GestureResponderEvent, Image} from 'react-native'; import {List, Menu, Text} from 'react-native-paper'; import ConfirmDialog from './ConfirmDialog'; -import Set from './set'; -import {deleteSetsBy} from './set.service'; +import {setRepo} from './db'; +import GymSet from './gym-set'; import {useSettings} from './use-settings'; import {WorkoutsPageParams} from './WorkoutsPage'; @@ -12,7 +12,7 @@ export default function WorkoutItem({ item, onRemove, }: { - item: Set; + item: GymSet; onRemove: () => void; }) { const [showMenu, setShowMenu] = useState(false); @@ -22,7 +22,7 @@ export default function WorkoutItem({ const navigation = useNavigation>(); const remove = useCallback(async () => { - await deleteSetsBy(item.name); + await setRepo.delete({name: item.name}); setShowMenu(false); onRemove(); }, [setShowMenu, onRemove, item.name]); diff --git a/WorkoutList.tsx b/WorkoutList.tsx index 0ef07aa..ca5e7f5 100644 --- a/WorkoutList.tsx +++ b/WorkoutList.tsx @@ -8,27 +8,30 @@ import {FlatList} from 'react-native'; import {List} from 'react-native-paper'; import DrawerHeader from './DrawerHeader'; import Page from './Page'; -import Set from './set'; -import {getDistinctSets} from './set.service'; +import GymSet from './gym-set'; import SetList from './SetList'; import WorkoutItem from './WorkoutItem'; import {WorkoutsPageParams} from './WorkoutsPage'; +import {setRepo} from './db'; const limit = 15; export default function WorkoutList() { - const [workouts, setWorkouts] = useState(); + const [workouts, setWorkouts] = useState(); const [offset, setOffset] = useState(0); const [term, setTerm] = useState(''); const [end, setEnd] = useState(false); const navigation = useNavigation>(); const refresh = useCallback(async (value: string) => { - const newWorkouts = await getDistinctSets({ - term: `%${value}%`, - limit, - offset: 0, - }); + const newWorkouts = await setRepo + .createQueryBuilder() + .select() + .where('name LIKE :name', {name: `%${value}%`}) + .groupBy('name') + .orderBy('name') + .limit(limit) + .getMany(); console.log(`${WorkoutList.name}`, {newWorkout: newWorkouts[0]}); setWorkouts(newWorkouts); setOffset(0); @@ -42,7 +45,7 @@ export default function WorkoutList() { ); const renderItem = useCallback( - ({item}: {item: Set}) => ( + ({item}: {item: GymSet}) => ( refresh(term)} /> ), [refresh, term], @@ -57,11 +60,15 @@ export default function WorkoutList() { newOffset, term, }); - const newWorkouts = await getDistinctSets({ - term: `%${term}%`, - limit, - offset: newOffset, - }); + const newWorkouts = await setRepo + .createQueryBuilder() + .select() + .where('name LIKE :name', {name: `%${term}%`}) + .groupBy('name') + .orderBy('name') + .limit(limit) + .offset(newOffset) + .getMany(); if (newWorkouts.length === 0) return setEnd(true); if (!workouts) return; setWorkouts([...workouts, ...newWorkouts]); @@ -71,7 +78,7 @@ export default function WorkoutList() { const onAdd = useCallback(async () => { navigation.navigate('EditWorkout', { - value: {name: '', sets: 3, image: '', steps: '', reps: 0, weight: 0}, + value: new GymSet(), }); }, [navigation]); diff --git a/WorkoutsPage.tsx b/WorkoutsPage.tsx index 8b5268e..35cb780 100644 --- a/WorkoutsPage.tsx +++ b/WorkoutsPage.tsx @@ -1,12 +1,12 @@ import {createStackNavigator} from '@react-navigation/stack'; import EditWorkout from './EditWorkout'; -import Set from './set'; +import GymSet from './gym-set'; import WorkoutList from './WorkoutList'; export type WorkoutsPageParams = { WorkoutList: {}; EditWorkout: { - value: Set; + value: GymSet; }; }; diff --git a/babel.config.js b/babel.config.js index 232b6fc..9a82bd1 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,12 @@ module.exports = { presets: ['module:metro-react-native-babel-preset'], - plugins: ['react-native-reanimated/plugin', 'react-native-paper/babel'], + plugins: [ + '@babel/plugin-transform-flow-strip-types', + ['@babel/plugin-proposal-class-properties', { loose: true }], + ['@babel/plugin-proposal-decorators', { legacy: true }], + 'react-native-reanimated/plugin', + 'react-native-paper/babel', + ], env: { production: { plugins: ['transform-remove-console'], diff --git a/best.service.ts b/best.service.ts index 8ff71af..e4d696f 100644 --- a/best.service.ts +++ b/best.service.ts @@ -1,8 +1,6 @@ -import {db} from './db'; +import {db, setRepo} from './db'; +import GymSet from './gym-set'; import {Periods} from './periods'; -import Set from './set'; -import {defaultSet} from './set.service'; -import Volume from './volume'; export const getOneRepMax = async ({ name, @@ -29,89 +27,15 @@ export const getOneRepMax = async ({ return result.rows.raw(); }; -export const getBestSet = async (name: string): Promise => { - const bestWeight = ` - SELECT name, reps, unit, MAX(weight) AS weight - FROM sets - WHERE name = ? - GROUP BY name; - `; - const bestReps = ` - SELECT name, MAX(reps) as reps, unit, weight, sets, minutes, seconds, image - FROM sets - WHERE name = ? AND weight = ? - 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 => { - 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(?, 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 getVolumes = async ( - name: string, - period: Periods, -): Promise => { - 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 => { - 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 => { - const select = ` - SELECT name, MAX(reps) as reps, unit, weight, image - 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 getBestSet = async (name: string): Promise => { + return setRepo + .createQueryBuilder() + .select() + .addSelect('MAX(weight)', 'weight') + .where('name = :name', {name}) + .groupBy('name') + .addGroupBy('reps') + .orderBy('weight', 'DESC') + .addOrderBy('reps', 'DESC') + .getOne(); }; diff --git a/db.ts b/db.ts index 7ee8fcc..df7c64c 100644 --- a/db.ts +++ b/db.ts @@ -3,6 +3,10 @@ import { openDatabase, SQLiteDatabase, } from 'react-native-sqlite-storage'; +import {DataSource} from 'typeorm'; +import GymSet from './gym-set'; +import {Plan} from './plan'; +import Settings from './settings'; enablePromise(true); @@ -127,7 +131,25 @@ const migrations = [ 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 planRepo = AppDataSource.manager.getRepository(Plan); +export const settingsRepo = AppDataSource.manager.getRepository(Settings); + +export const getNow = (): Promise<{now: string}[]> => { + return AppDataSource.manager.query( + "SELECT STRFTIME('%Y-%m-%dT%H:%M:%S','now','localtime') AS now", + ); +}; + export const runMigrations = async () => { + await AppDataSource.initialize(); db = await openDatabase({name: 'massive.db'}); await db.executeSql(` CREATE TABLE IF NOT EXISTS migrations( diff --git a/gym-set.ts b/gym-set.ts new file mode 100644 index 0000000..ad51509 --- /dev/null +++ b/gym-set.ts @@ -0,0 +1,40 @@ +import {Column, Entity, PrimaryGeneratedColumn} from 'typeorm'; + +@Entity('sets') +export default class GymSet { + @PrimaryGeneratedColumn() + id?: number; + + @Column('text') + name: string; + + @Column('int') + reps: number; + + @Column('int') + weight: number; + + @Column('int') + sets = 3; + + @Column('int') + minutes = 3; + + @Column('int') + seconds = 30; + + @Column('boolean') + hidden = false; + + @Column('text') + created?: string; + + @Column('text') + unit?: string; + + @Column('text') + image?: string; + + @Column('text') + steps?: string; +} diff --git a/home-page-params.ts b/home-page-params.ts index 50bcefe..a19a8d7 100644 --- a/home-page-params.ts +++ b/home-page-params.ts @@ -1,8 +1,8 @@ -import Set from './set'; +import GymSet from './gym-set'; export type HomePageParams = { Sets: {}; EditSet: { - set: Set; + set: GymSet; }; }; diff --git a/index.js b/index.js index 5a97e4a..7b2f6c7 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ -import {AppRegistry} from 'react-native'; -import 'react-native-gesture-handler'; -import 'react-native-sqlite-storage'; -import App from './App'; -import {name as appName} from './app.json'; +import {AppRegistry} from 'react-native' +import 'react-native-gesture-handler' +import 'react-native-sqlite-storage' +import App from './App' +import {name as appName} from './app.json' -AppRegistry.registerComponent(appName, () => App); +AppRegistry.registerComponent(appName, () => App) diff --git a/package.json b/package.json index a3df5d8..c144335 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "lint": "eslint . --ext .js,.jsx,.ts,.tsx --quiet" }, "dependencies": { + "@babel/plugin-transform-flow-strip-types": "^7.19.0", "@babel/preset-env": "^7.19.1", "@react-native-masked-view/masked-view": "^0.2.7", "@react-native-picker/picker": "^2.4.4", @@ -45,12 +46,15 @@ "react-native-svg-charts": "^5.4.0", "react-native-vector-icons": "^9.2.0", "react-native-view-shot": "^3.4.0", - "react-test-renderer": "^18.2.0" + "react-test-renderer": "^18.2.0", + "typeorm": "^0.3.10" }, "devDependencies": { "@babel/core": "^7.12.9", + "@babel/plugin-proposal-decorators": "^7.20.0", "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^2.0.0", + "@types/node": "^18.11.7", "@types/react-native": "^0.69.0", "@types/react-test-renderer": "^18.0.0", "@typescript-eslint/eslint-plugin": "^5.29.0", diff --git a/plan-page-params.ts b/plan-page-params.ts index 4861a8d..86fbb0e 100644 --- a/plan-page-params.ts +++ b/plan-page-params.ts @@ -1,5 +1,5 @@ import {Plan} from './plan'; -import Set from './set'; +import GymSet from './gym-set'; export type PlanPageParams = { PlanList: {}; @@ -8,6 +8,6 @@ export type PlanPageParams = { }; StartPlan: { plan: Plan; - set: Set; + set: GymSet; }; }; diff --git a/plan.service.ts b/plan.service.ts deleted file mode 100644 index 0062fc7..0000000 --- a/plan.service.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {db} from './db'; -import {Plan} from './plan'; -import {DAYS} from './time'; - -export const getPlans = async (search: string): Promise => { - 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 => { - 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 updatePlanWorkouts = 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 updatePlan = 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 => { - const select = `SELECT * from plans`; - const [result] = await db.executeSql(select); - return result.rows.raw(); -}; diff --git a/plan.ts b/plan.ts index bc46c99..2012639 100644 --- a/plan.ts +++ b/plan.ts @@ -1,5 +1,13 @@ -export interface Plan { +import {Column, Entity, PrimaryGeneratedColumn} from 'typeorm'; + +@Entity('plans') +export class Plan { + @PrimaryGeneratedColumn() id?: number; + + @Column('text') days: string; + + @Column('text') workouts: string; } diff --git a/set.service.ts b/set.service.ts index 82d70b5..8b904c9 100644 --- a/set.service.ts +++ b/set.service.ts @@ -1,163 +1,5 @@ import CountMany from './count-many'; import {db} from './db'; -import Set from './set'; - -export const updateSet = async (value: Set) => { - const update = ` - UPDATE sets - SET name = ?, reps = ?, weight = ?, unit = ?, image = ? - WHERE id = ? - `; - return db.executeSql(update, [ - value.name, - value.reps, - value.weight, - value.unit, - value.image, - value.id, - ]); -}; - -export const addSets = async (columns: string, values: string) => { - console.log({columns, values}); - const insert = ` - INSERT INTO sets(${columns}) - VALUES ${values} - `; - return db.executeSql(insert); -}; - -export const addSet = async (value: Set) => { - const keys = Object.keys(value) as (keyof Set)[]; - const questions = keys.map(() => '?').join(','); - const insert = ` - INSERT INTO sets(${keys.join(',')},created) - VALUES (${questions},strftime('%Y-%m-%dT%H:%M:%S','now','localtime')) - `; - const values = keys.map(key => value[key]); - return db.executeSql(insert, values); -}; - -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 => { - const select = `SELECT * from sets`; - const [result] = await db.executeSql(select); - return result.rows.raw(); -}; - -interface PageParams { - term: string; - limit: number; - offset: number; -} - -export const getSet = async (name: string): Promise => { - const select = ` - SELECT * - FROM sets - WHERE name = ? - LIMIT 1 - `; - const [result] = await db.executeSql(select, [name]); - return result.rows.item(0); -}; - -export const getSets = async ({ - term, - limit, - offset, -}: PageParams): Promise => { - const select = ` - SELECT id, name, reps, weight, sets, minutes, seconds, - created, unit, image, steps - FROM sets - WHERE name LIKE ? AND NOT hidden - ORDER BY STRFTIME('%Y-%m-%d %H:%M', created) DESC - LIMIT ? OFFSET ? - `; - const [result] = await db.executeSql(select, [`%${term}%`, limit, offset]); - return result.rows.raw(); -}; - -export const defaultSet: Set = { - name: '', - reps: 10, - weight: 20, - unit: 'kg', -}; - -export const updateManySet = async ({ - oldName, - newName, - minutes, - seconds, - sets, - steps, -}: { - oldName: string; - newName: string; - minutes: string; - seconds: string; - sets: string; - steps?: string; -}) => { - const update = ` - UPDATE sets SET name = ?, minutes = ?, seconds = ?, sets = ?, steps = ? - WHERE name = ? - `; - return db.executeSql(update, [ - newName, - minutes, - seconds, - sets, - steps, - oldName, - ]); -}; - -export const updateSetImage = async (name: string, image: string) => { - const update = `UPDATE sets SET image = ? WHERE name = ?`; - return db.executeSql(update, [image, name]); -}; - -export const getNames = async (): Promise => { - const [result] = await db.executeSql('SELECT DISTINCT name FROM sets'); - const values: {name: string}[] = result.rows.raw(); - return values.map(value => value.name); -}; - -export const getToday = async (): Promise => { - const select = ` - SELECT name, reps, weight, sets, minutes, seconds, unit, image FROM sets - WHERE NOT hidden - AND created LIKE strftime('%Y-%m-%d%%', 'now', 'localtime') - ORDER BY created DESC - LIMIT 1 - `; - const [result] = await db.executeSql(select); - return result.rows.item(0); -}; - -export const countToday = async (name: string): Promise => { - const select = ` - SELECT COUNT(*) as total FROM sets - WHERE created LIKE strftime('%Y-%m-%d%%', 'now', 'localtime') - AND name = ? AND NOT hidden - `; - const [result] = await db.executeSql(select, [name]); - return Number(result.rows.item(0)?.total); -}; export const countMany = async (names: string[]): Promise => { const questions = names.map(_ => '(?)').join(','); @@ -175,32 +17,3 @@ export const countMany = async (names: string[]): Promise => { const [result] = await db.executeSql(select, names); return result.rows.raw(); }; - -export const getDistinctSets = async ({ - term, - limit, - offset, -}: PageParams): Promise => { - const select = ` - SELECT name, image, sets, minutes, seconds, steps - FROM sets - WHERE sets.name LIKE ? - GROUP BY sets.name - ORDER BY sets.name - LIMIT ? OFFSET ? - `; - const [result] = await db.executeSql(select, [term, limit, offset]); - return result.rows.raw(); -}; - -export const deleteFirst = async (name: string) => { - const remove = ` - DELETE FROM sets WHERE id IN ( - SELECT id FROM sets - WHERE name = ? - ORDER BY created DESC - LIMIT 1 - ) - `; - return db.executeSql(remove, [name]); -}; diff --git a/set.ts b/set.ts deleted file mode 100644 index 4d7be6d..0000000 --- a/set.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default interface Set { - id?: number; - name: string; - reps: number; - weight: number; - sets?: number; - minutes?: number; - seconds?: number; - created?: string; - unit?: string; - hidden?: boolean; - image?: string; - steps?: string; -} diff --git a/settings.service.ts b/settings.service.ts deleted file mode 100644 index 7aafb18..0000000 --- a/settings.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {db} from './db'; -import Settings from './settings'; - -export const getSettings = async (): Promise => { - const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`); - return result.rows.item(0); -}; - -export const updateSettings = async (value: Settings) => { - console.log(`${updateSettings.name}`, {value}); - const keys = Object.keys(value) as (keyof Settings)[]; - const sets = keys.map(key => `${key}=?`).join(','); - const update = `UPDATE settings SET ${sets}`; - const values = keys.map(key => value[key]); - return db.executeSql(update, values); -}; - -export const getNext = async (): Promise => { - const [result] = await db.executeSql( - `SELECT nextAlarm FROM settings LIMIT 1`, - ); - return result.rows.item(0)?.nextAlarm; -}; diff --git a/settings.ts b/settings.ts index 4c4715f..283353b 100644 --- a/settings.ts +++ b/settings.ts @@ -1,15 +1,43 @@ -export default interface Settings { - alarm: number; - vibrate: number; +import {Column, Entity, PrimaryColumn} from 'typeorm'; + +@Entity() +export default class Settings { + @PrimaryColumn('boolean') + alarm: boolean; + + @Column('boolean') + vibrate: boolean; + + @Column('text') sound: string; - notify: number; - images: number; - showUnit: number; + + @Column('boolean') + notify: boolean; + + @Column('boolean') + images: boolean; + + @Column('boolean') + showUnit: boolean; + + @Column('text') color: string; - steps: number; + + @Column('boolean') + steps: boolean; + + @Column('text') date: string; - showDate: number; - theme: 'system' | 'dark' | 'light'; - showSets: number; - noSound: number; + + @Column('boolean') + showDate: boolean; + + @Column('text') + theme: string; + + @Column('boolean') + showSets: boolean; + + @Column('boolean') + noSound: boolean; } diff --git a/tsconfig.json b/tsconfig.json index 42d610a..20e816c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,8 +13,10 @@ "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true + "strict": false, + "skipLibCheck": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true }, "exclude": [ "node_modules", diff --git a/yarn.lock b/yarn.lock index 72a4add..c3a9b47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -242,7 +242,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.18.6, @babel/helper-replace-supers@npm:^7.18.9": +"@babel/helper-replace-supers@npm:^7.18.6, @babel/helper-replace-supers@npm:^7.18.9, @babel/helper-replace-supers@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-replace-supers@npm:7.19.1" dependencies: @@ -409,6 +409,21 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-proposal-decorators@npm:^7.20.0": + version: 7.20.0 + resolution: "@babel/plugin-proposal-decorators@npm:7.20.0" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.19.0 + "@babel/helper-plugin-utils": ^7.19.0 + "@babel/helper-replace-supers": ^7.19.1 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/plugin-syntax-decorators": ^7.19.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b882bf758c9e098ead68a05e3e912f427a5b286c7174a582ccf38cf02a679ce1372282a45fb1987b2ffd7e9923fc38e6913fa54e165f5640c334c2c6a74e761f + languageName: node + linkType: hard + "@babel/plugin-proposal-dynamic-import@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-proposal-dynamic-import@npm:7.18.6" @@ -615,6 +630,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-decorators@npm:^7.19.0": + version: 7.19.0 + resolution: "@babel/plugin-syntax-decorators@npm:7.19.0" + dependencies: + "@babel/helper-plugin-utils": ^7.19.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 105a13d581a8643ba145d4d0d31f34a492b352defa5b155e785702da6ce9c3ff0c1843ba9bee176e35f6e38afa19dc7bd12c120220af0495de4b128f1dd27f6e + languageName: node + linkType: hard + "@babel/plugin-syntax-dynamic-import@npm:^7.0.0, @babel/plugin-syntax-dynamic-import@npm:^7.8.3": version: 7.8.3 resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" @@ -924,7 +950,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-flow-strip-types@npm:^7.0.0, @babel/plugin-transform-flow-strip-types@npm:^7.18.6": +"@babel/plugin-transform-flow-strip-types@npm:^7.0.0, @babel/plugin-transform-flow-strip-types@npm:^7.18.6, @babel/plugin-transform-flow-strip-types@npm:^7.19.0": version: 7.19.0 resolution: "@babel/plugin-transform-flow-strip-types@npm:7.19.0" dependencies: @@ -2342,6 +2368,13 @@ __metadata: languageName: node linkType: hard +"@sqltools/formatter@npm:^1.2.2": + version: 1.2.5 + resolution: "@sqltools/formatter@npm:1.2.5" + checksum: 9b8354e715467d660daa5afe044860b5686bbb1a5cb67a60866b932effafbf5e8b429f19a8ae67cd412065a4f067161f227e182f3664a0245339d5eb1e26e355 + languageName: node + linkType: hard + "@testing-library/jest-native@npm:^5.1.2": version: 5.1.2 resolution: "@testing-library/jest-native@npm:5.1.2" @@ -2544,7 +2577,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": +"@types/node@npm:*, @types/node@npm:^18.11.7": version: 18.11.7 resolution: "@types/node@npm:18.11.7" checksum: 69d630825cf6fbf580d08d76a4d4836ef8c34ed4fe0842221ade87d275f517099cbfabe8e22397208e564bd24926db97699ab9db5c091383269a432b336665e2 @@ -3054,6 +3087,13 @@ __metadata: languageName: node linkType: hard +"any-promise@npm:^1.0.0": + version: 1.3.0 + resolution: "any-promise@npm:1.3.0" + checksum: 0ee8a9bdbe882c90464d75d1f55cf027f5458650c4bd1f0467e65aec38ccccda07ca5844969ee77ed46d04e7dded3eaceb027e8d32f385688523fe305fa7e1de + languageName: node + linkType: hard + "anymatch@npm:^3.0.3": version: 3.1.2 resolution: "anymatch@npm:3.1.2" @@ -3064,6 +3104,13 @@ __metadata: languageName: node linkType: hard +"app-root-path@npm:^3.0.0": + version: 3.1.0 + resolution: "app-root-path@npm:3.1.0" + checksum: e3db3957aee197143a0f6c75e39fe89b19e7244f28b4f2944f7276a9c526d2a7ab2d115b4b2d70a51a65a9a3ca17506690e5b36f75a068a7e5a13f8c092389ba + languageName: node + linkType: hard + "appdirsjs@npm:^1.2.4": version: 1.2.7 resolution: "appdirsjs@npm:1.2.7" @@ -3538,6 +3585,16 @@ __metadata: languageName: node linkType: hard +"buffer@npm:^6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: ^1.3.1 + ieee754: ^1.2.1 + checksum: 5ad23293d9a731e4318e420025800b42bf0d264004c0286c8cc010af7a270c7a0f6522e84f54b9ad65cbd6db20b8badbfd8d2ebf4f80fa03dab093b89e68c3f9 + languageName: node + linkType: hard + "bytes@npm:3.0.0": version: 3.0.0 resolution: "bytes@npm:3.0.0" @@ -3735,6 +3792,22 @@ __metadata: languageName: node linkType: hard +"cli-highlight@npm:^2.1.11": + version: 2.1.11 + resolution: "cli-highlight@npm:2.1.11" + dependencies: + chalk: ^4.0.0 + highlight.js: ^10.7.1 + mz: ^2.4.0 + parse5: ^5.1.1 + parse5-htmlparser2-tree-adapter: ^6.0.0 + yargs: ^16.0.0 + bin: + highlight: bin/highlight + checksum: 0a60e60545e39efea78c1732a25b91692017ec40fb6e9497208dc0eeeae69991d3923a8d6e4edd0543db3c395ed14529a33dd4d0353f1679c5b6dded792a8496 + languageName: node + linkType: hard + "cli-spinners@npm:^2.5.0": version: 2.7.0 resolution: "cli-spinners@npm:2.7.0" @@ -4186,6 +4259,13 @@ __metadata: languageName: node linkType: hard +"date-fns@npm:^2.28.0": + version: 2.29.3 + resolution: "date-fns@npm:2.29.3" + checksum: e01cf5b62af04e05dfff921bb9c9933310ed0e1ae9a81eb8653452e64dc841acf7f6e01e1a5ae5644d0337e9a7f936175fd2cb6819dc122fdd9c5e86c56be484 + languageName: node + linkType: hard + "dayjs@npm:^1.8.15": version: 1.11.6 resolution: "dayjs@npm:1.11.6" @@ -4417,6 +4497,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.0.0": + version: 16.0.3 + resolution: "dotenv@npm:16.0.3" + checksum: afcf03f373d7a6d62c7e9afea6328e62851d627a4e73f2e12d0a8deae1cd375892004f3021883f8aec85932cd2834b091f568ced92b4774625b321db83b827f8 + languageName: node + linkType: hard + "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -5425,7 +5512,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -5622,6 +5709,13 @@ __metadata: languageName: node linkType: hard +"highlight.js@npm:^10.7.1": + version: 10.7.3 + resolution: "highlight.js@npm:10.7.3" + checksum: defeafcd546b535d710d8efb8e650af9e3b369ef53e28c3dc7893eacfe263200bba4c5fcf43524ae66d5c0c296b1af0870523ceae3e3104d24b7abf6374a4fea + languageName: node + linkType: hard + "hoist-non-react-statics@npm:^3.3.0": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" @@ -5704,7 +5798,7 @@ __metadata: languageName: node linkType: hard -"ieee754@npm:^1.1.13": +"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e @@ -5790,7 +5884,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 @@ -7182,6 +7276,8 @@ __metadata: resolution: "massive@workspace:." dependencies: "@babel/core": ^7.12.9 + "@babel/plugin-proposal-decorators": ^7.20.0 + "@babel/plugin-transform-flow-strip-types": ^7.19.0 "@babel/preset-env": ^7.19.1 "@babel/runtime": ^7.12.5 "@react-native-community/eslint-config": ^2.0.0 @@ -7194,6 +7290,7 @@ __metadata: "@testing-library/react-native": ^11.3.0 "@types/d3-shape": ^3.1.0 "@types/jest": ^29.2.0 + "@types/node": ^18.11.7 "@types/react-native": ^0.69.0 "@types/react-native-sqlite-storage": ^5.0.2 "@types/react-native-svg-charts": ^5.0.12 @@ -7225,6 +7322,7 @@ __metadata: react-native-vector-icons: ^9.2.0 react-native-view-shot: ^3.4.0 react-test-renderer: ^18.2.0 + typeorm: ^0.3.10 typescript: ^4.8.4 languageName: unknown linkType: soft @@ -7848,6 +7946,17 @@ __metadata: languageName: node linkType: hard +"mz@npm:^2.4.0": + version: 2.7.0 + resolution: "mz@npm:2.7.0" + dependencies: + any-promise: ^1.0.0 + object-assign: ^4.0.1 + thenify-all: ^1.0.0 + checksum: 8427de0ece99a07e9faed3c0c6778820d7543e3776f9a84d22cf0ec0a8eb65f6e9aee9c9d353ff9a105ff62d33a9463c6ca638974cc652ee8140cd1e35951c87 + languageName: node + linkType: hard + "nanoid@npm:^3.1.23": version: 3.3.4 resolution: "nanoid@npm:3.3.4" @@ -8046,7 +8155,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.1.1": +"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f @@ -8340,6 +8449,29 @@ __metadata: languageName: node linkType: hard +"parse5-htmlparser2-tree-adapter@npm:^6.0.0": + version: 6.0.1 + resolution: "parse5-htmlparser2-tree-adapter@npm:6.0.1" + dependencies: + parse5: ^6.0.1 + checksum: 1848378b355d027915645c13f13f982e60502d201f53bc2067a508bf2dba4aac08219fc781dcd160167f5f50f0c73f58d20fa4fb3d90ee46762c20234fa90a6d + languageName: node + linkType: hard + +"parse5@npm:^5.1.1": + version: 5.1.1 + resolution: "parse5@npm:5.1.1" + checksum: 613a714af4c1101d1cb9f7cece2558e35b9ae8a0c03518223a4a1e35494624d9a9ad5fad4c13eab66a0e0adccd9aa3d522fc8f5f9cc19789e0579f3fa0bdfc65 + languageName: node + linkType: hard + +"parse5@npm:^6.0.1": + version: 6.0.1 + resolution: "parse5@npm:6.0.1" + checksum: 7d569a176c5460897f7c8f3377eff640d54132b9be51ae8a8fa4979af940830b2b0c296ce75e5bd8f4041520aadde13170dbdec44889975f906098ea0002f4bd + languageName: node + linkType: hard + "parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -9021,6 +9153,13 @@ __metadata: languageName: node linkType: hard +"reflect-metadata@npm:^0.1.13": + version: 0.1.13 + resolution: "reflect-metadata@npm:0.1.13" + checksum: 798d379a7b6f6455501145419505c97dd11cbc23857a386add2b9ef15963ccf15a48d9d15507afe01d4cd74116df8a213247200bac00320bd7c11ddeaa5e8fb4 + languageName: node + linkType: hard + "regenerate-unicode-properties@npm:^10.1.0": version: 10.1.0 resolution: "regenerate-unicode-properties@npm:10.1.0" @@ -9326,7 +9465,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:~5.2.0": +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 @@ -9360,6 +9499,13 @@ __metadata: languageName: node linkType: hard +"sax@npm:>=0.6.0": + version: 1.2.4 + resolution: "sax@npm:1.2.4" + checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe + languageName: node + linkType: hard + "scheduler@npm:^0.22.0": version: 0.22.0 resolution: "scheduler@npm:0.22.0" @@ -9480,6 +9626,18 @@ __metadata: languageName: node linkType: hard +"sha.js@npm:^2.4.11": + version: 2.4.11 + resolution: "sha.js@npm:2.4.11" + dependencies: + inherits: ^2.0.1 + safe-buffer: ^5.0.1 + bin: + sha.js: ./bin.js + checksum: ebd3f59d4b799000699097dadb831c8e3da3eb579144fd7eb7a19484cbcbb7aca3c68ba2bb362242eb09e33217de3b4ea56e4678184c334323eca24a58e3ad07 + languageName: node + linkType: hard + "shallow-clone@npm:^3.0.0": version: 3.0.1 resolution: "shallow-clone@npm:3.0.1" @@ -10031,6 +10189,24 @@ __metadata: languageName: node linkType: hard +"thenify-all@npm:^1.0.0": + version: 1.6.0 + resolution: "thenify-all@npm:1.6.0" + dependencies: + thenify: ">= 3.1.0 < 4" + checksum: dba7cc8a23a154cdcb6acb7f51d61511c37a6b077ec5ab5da6e8b874272015937788402fd271fdfc5f187f8cb0948e38d0a42dcc89d554d731652ab458f5343e + languageName: node + linkType: hard + +"thenify@npm:>= 3.1.0 < 4": + version: 3.3.1 + resolution: "thenify@npm:3.3.1" + dependencies: + any-promise: ^1.0.0 + checksum: 84e1b804bfec49f3531215f17b4a6e50fd4397b5f7c1bccc427b9c656e1ecfb13ea79d899930184f78bc2f57285c54d9a50a590c8868f4f0cef5c1d9f898b05e + languageName: node + linkType: hard + "throat@npm:^5.0.0": version: 5.0.0 resolution: "throat@npm:5.0.0" @@ -10123,7 +10299,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1": +"tslib@npm:^2.0.1, tslib@npm:^2.3.1": version: 2.4.0 resolution: "tslib@npm:2.4.0" checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 @@ -10178,6 +10354,88 @@ __metadata: languageName: node linkType: hard +"typeorm@npm:^0.3.10": + version: 0.3.10 + resolution: "typeorm@npm:0.3.10" + dependencies: + "@sqltools/formatter": ^1.2.2 + app-root-path: ^3.0.0 + buffer: ^6.0.3 + chalk: ^4.1.0 + cli-highlight: ^2.1.11 + date-fns: ^2.28.0 + debug: ^4.3.3 + dotenv: ^16.0.0 + glob: ^7.2.0 + js-yaml: ^4.1.0 + mkdirp: ^1.0.4 + reflect-metadata: ^0.1.13 + sha.js: ^2.4.11 + tslib: ^2.3.1 + uuid: ^8.3.2 + xml2js: ^0.4.23 + yargs: ^17.3.1 + peerDependencies: + "@google-cloud/spanner": ^5.18.0 + "@sap/hana-client": ^2.12.25 + better-sqlite3: ^7.1.2 + hdb-pool: ^0.1.6 + ioredis: ^5.0.4 + mongodb: ^3.6.0 + mssql: ^7.3.0 + mysql2: ^2.2.5 + oracledb: ^5.1.0 + pg: ^8.5.1 + pg-native: ^3.0.0 + pg-query-stream: ^4.0.0 + redis: ^3.1.1 || ^4.0.0 + sql.js: ^1.4.0 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 + typeorm-aurora-data-api-driver: ^2.0.0 + peerDependenciesMeta: + "@google-cloud/spanner": + optional: true + "@sap/hana-client": + optional: true + better-sqlite3: + optional: true + hdb-pool: + optional: true + ioredis: + optional: true + mongodb: + optional: true + mssql: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + redis: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + ts-node: + optional: true + typeorm-aurora-data-api-driver: + optional: true + bin: + typeorm: cli.js + typeorm-ts-node-commonjs: cli-ts-node-commonjs.js + typeorm-ts-node-esm: cli-ts-node-esm.js + checksum: 8a4ce43b427e9224d9e8f278d8c490d116f04d3cd7cd3ac9e4ed7e0541f82b3c88925194cbf38533dc6d9adf40886778f3caf0565aa50998454bb2047e8afe1f + languageName: node + linkType: hard + "typescript@npm:^4.8.4": version: 4.8.4 resolution: "typescript@npm:4.8.4" @@ -10374,6 +10632,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + "v8-to-istanbul@npm:^9.0.1": version: 9.0.1 resolution: "v8-to-istanbul@npm:9.0.1" @@ -10580,6 +10847,23 @@ __metadata: languageName: node linkType: hard +"xml2js@npm:^0.4.23": + version: 0.4.23 + resolution: "xml2js@npm:0.4.23" + dependencies: + sax: ">=0.6.0" + xmlbuilder: ~11.0.0 + checksum: ca0cf2dfbf6deeaae878a891c8fbc0db6fd04398087084edf143cdc83d0509ad0fe199b890f62f39c4415cf60268a27a6aed0d343f0658f8779bd7add690fa98 + languageName: node + linkType: hard + +"xmlbuilder@npm:~11.0.0": + version: 11.0.1 + resolution: "xmlbuilder@npm:11.0.1" + checksum: 7152695e16f1a9976658215abab27e55d08b1b97bca901d58b048d2b6e106b5af31efccbdecf9b07af37c8377d8e7e821b494af10b3a68b0ff4ae60331b415b0 + languageName: node + linkType: hard + "xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" @@ -10651,7 +10935,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^16.1.1": +"yargs@npm:^16.0.0, yargs@npm:^16.1.1": version: 16.2.0 resolution: "yargs@npm:16.2.0" dependencies: