Prevent race condition with database migrations

This commit is contained in:
Brandon Presley 2022-08-30 23:21:25 +12:00
parent a1cd4e8080
commit 756a2089e9
16 changed files with 63 additions and 55 deletions

41
App.tsx
View File

@ -4,7 +4,7 @@ import {
DefaultTheme as NavigationDefaultTheme,
NavigationContainer,
} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
import React, {useState} from 'react';
import {useColorScheme} from 'react-native';
import {
DarkTheme as PaperDarkTheme,
@ -12,19 +12,7 @@ import {
Provider,
Snackbar,
} from 'react-native-paper';
import {SQLiteDatabase} from 'react-native-sqlite-storage';
import Ionicon from 'react-native-vector-icons/Ionicons';
import {
addHidden,
addImage,
addNotify,
addSound,
createPlans,
createSets,
createSettings,
createWorkouts,
getDb,
} from './db';
import Routes from './Routes';
export const Drawer = createDrawerNavigator<DrawerParamList>();
@ -34,9 +22,9 @@ export type DrawerParamList = {
Best: {};
Plans: {};
Workouts: {};
Loading: {};
};
export const DatabaseContext = React.createContext<SQLiteDatabase>({} as any);
export const SnackbarContext = React.createContext<{
toast: (value: string, timeout: number) => void;
}>({toast: () => null});
@ -61,32 +49,9 @@ export const CombinedDarkTheme = {
};
const App = () => {
const [db, setDb] = useState<SQLiteDatabase | null>(null);
const [snackbar, setSnackbar] = useState('');
const dark = useColorScheme() === 'dark';
useEffect(() => {
const init = async () => {
const _db = await getDb();
setDb(_db);
await _db.executeSql(createPlans);
await _db.executeSql(createSets);
await _db.executeSql(createSettings);
await _db.executeSql(addSound).catch(() => null);
await _db.executeSql(createWorkouts);
await _db.executeSql(addHidden).catch(() => null);
await _db.executeSql(addNotify).catch(() => null);
await _db.executeSql(addImage).catch(() => null);
const [result] = await _db.executeSql(`SELECT * FROM settings LIMIT 1`);
if (result.rows.length === 0)
return _db.executeSql(`
INSERT INTO settings(minutes,seconds,alarm,vibrate,predict,sets)
VALUES(3,30,false,true,true,3);
`);
};
init();
}, []);
const toast = (value: string, timeout: number) => {
setSnackbar(value);
setTimeout(() => setSnackbar(''), timeout);
@ -99,7 +64,7 @@ const App = () => {
<NavigationContainer
theme={dark ? CombinedDarkTheme : CombinedDefaultTheme}>
<SnackbarContext.Provider value={{toast}}>
<Routes db={db} />
<Routes />
</SnackbarContext.Provider>
</NavigationContainer>
<Snackbar

View File

@ -6,7 +6,7 @@ import {
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import Best from './best';
import {BestPageParams} from './BestPage';

View File

@ -3,9 +3,10 @@ import React, {useCallback, useContext, useState} from 'react';
import DocumentPicker from 'react-native-document-picker';
import {FileSystem} from 'react-native-file-access';
import {Divider, IconButton, Menu} from 'react-native-paper';
import {DatabaseContext, DrawerParamList, SnackbarContext} from './App';
import {DrawerParamList, SnackbarContext} from './App';
import ConfirmDialog from './ConfirmDialog';
import {Plan} from './plan';
import {DatabaseContext} from './Routes';
import Set from './set';
import {write} from './write';

View File

@ -8,7 +8,7 @@ import {
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {ScrollView, StyleSheet, Text, View} from 'react-native';
import {Button, IconButton} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import MassiveSwitch from './MassiveSwitch';
import {PlanPageParams} from './PlanPage';
import {DAYS} from './time';

View File

@ -7,8 +7,9 @@ import {
import React, {useCallback, useContext} from 'react';
import {NativeModules, View} from 'react-native';
import {IconButton} from 'react-native-paper';
import {DatabaseContext, SnackbarContext} from './App';
import {SnackbarContext} from './App';
import {HomePageParams} from './HomePage';
import {DatabaseContext} from './Routes';
import Set from './set';
import SetForm from './SetForm';
import Settings from './settings';

View File

@ -9,7 +9,7 @@ import {Image, ScrollView, View} from 'react-native';
import DocumentPicker from 'react-native-document-picker';
import {Button, IconButton} from 'react-native-paper';
import {set} from 'react-native-reanimated';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import MassiveInput from './MassiveInput';
import {WorkoutsPageParams} from './WorkoutsPage';

View File

@ -2,7 +2,7 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
import React, {useCallback, useContext, useState} from 'react';
import {GestureResponderEvent} from 'react-native';
import {List, Menu} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import {Plan} from './plan';
import {PlanPageParams} from './PlanPage';

View File

@ -6,7 +6,7 @@ import {
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import DrawerMenu from './DrawerMenu';
import MassiveFab from './MassiveFab';
import {Plan} from './plan';

View File

@ -1,9 +1,20 @@
import React from 'react';
import React, {useEffect, useState} from 'react';
import {useColorScheme} from 'react-native';
import {IconButton} from 'react-native-paper';
import {SQLiteDatabase} from 'react-native-sqlite-storage';
import {DatabaseContext, Drawer, DrawerParamList} from './App';
import {Drawer, DrawerParamList} from './App';
import BestPage from './BestPage';
import {
addHidden,
addImage,
addNotify,
addSound,
createPlans,
createSets,
createSettings,
createWorkouts,
getDb,
} from './db';
import HomePage from './HomePage';
import PlanPage from './PlanPage';
import SettingsPage from './SettingsPage';
@ -15,9 +26,37 @@ interface Route {
icon: string;
}
export default function Routes({db}: {db: SQLiteDatabase | null}) {
export const DatabaseContext = React.createContext<SQLiteDatabase>(null as any);
export default function Routes() {
const [db, setDb] = useState<SQLiteDatabase | null>(null);
const dark = useColorScheme() === 'dark';
useEffect(() => {
const init = async () => {
const _db = await getDb();
try {
await _db.executeSql(createPlans);
await _db.executeSql(createSets);
await _db.executeSql(createSettings);
await _db.executeSql(createWorkouts);
await _db.executeSql(addSound).catch(() => null);
await _db.executeSql(addHidden).catch(() => null);
await _db.executeSql(addNotify).catch(() => null);
await _db.executeSql(addImage).catch(() => null);
const [result] = await _db.executeSql(`SELECT * FROM settings LIMIT 1`);
if (result.rows.length === 0)
return _db.executeSql(`
INSERT INTO settings(minutes,seconds,alarm,vibrate,predict,sets)
VALUES(3,30,false,true,true,3);
`);
} finally {
setDb(_db);
}
};
init();
}, []);
if (!db) return null;
const routes: Route[] = [

View File

@ -1,7 +1,7 @@
import React, {useContext, useEffect, useRef, useState} from 'react';
import {ScrollView, Text} from 'react-native';
import {Button} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import MassiveInput from './MassiveInput';
import Set from './set';

View File

@ -2,7 +2,7 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
import React, {useCallback, useContext, useState} from 'react';
import {GestureResponderEvent, Image, Text} from 'react-native';
import {Divider, List, Menu} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import {HomePageParams} from './HomePage';
import Set from './set';

View File

@ -6,7 +6,7 @@ import {
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import DrawerMenu from './DrawerMenu';
import {HomePageParams} from './HomePage';
import MassiveFab from './MassiveFab';

View File

@ -8,10 +8,11 @@ import React, {
import {NativeModules, ScrollView, StyleSheet, Text, View} from 'react-native';
import DocumentPicker from 'react-native-document-picker';
import {Button, Searchbar} from 'react-native-paper';
import {DatabaseContext, SnackbarContext} from './App';
import {SnackbarContext} from './App';
import ConfirmDialog from './ConfirmDialog';
import MassiveInput from './MassiveInput';
import MassiveSwitch from './MassiveSwitch';
import {DatabaseContext} from './Routes';
import Settings from './settings';
export default function SettingsPage() {

View File

@ -18,8 +18,9 @@ import {IconButton} from 'react-native-paper';
import Share from 'react-native-share';
import {Grid, LineChart, XAxis, YAxis} from 'react-native-svg-charts';
import ViewShot from 'react-native-view-shot';
import {CombinedDarkTheme, CombinedDefaultTheme, DatabaseContext} from './App';
import {CombinedDarkTheme, CombinedDefaultTheme} from './App';
import {BestPageParams} from './BestPage';
import {DatabaseContext} from './Routes';
import Set from './set';
import {formatMonth} from './time';

View File

@ -2,7 +2,7 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {GestureResponderEvent, Image, Text} from 'react-native';
import {List, Menu} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import ConfirmDialog from './ConfirmDialog';
import Workout from './workout';
import {WorkoutsPageParams} from './WorkoutsPage';

View File

@ -6,7 +6,7 @@ import {
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native';
import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App';
import {DatabaseContext} from './Routes';
import MassiveFab from './MassiveFab';
import SetList from './SetList';
import Workout from './workout';