Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions components/charts/ExerciseProgressionChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,12 +260,12 @@ export const ExerciseProgressionChart: React.FC<
exercise.tracking_type === null ||
exercise.tracking_type === "weight" ||
exercise.tracking_type === "assisted";
const baselineValue =
preRangeBaseline != null
? isWeightTypePre
? preRangeBaseline * conversionFactor
: preRangeBaseline
: undefined;
const rawBaseline = preRangeBaseline != null
? isWeightTypePre
? preRangeBaseline * conversionFactor
: preRangeBaseline
: undefined;
const baselineValue = rawBaseline != null && rawBaseline > 0 ? rawBaseline : undefined;
for (let i = 0; i < buckets.length; i++) {
if (buckets[i].value === null && baselineValue !== undefined) {
buckets[i] = { ...buckets[i], value: baselineValue };
Expand All @@ -278,7 +278,7 @@ export const ExerciseProgressionChart: React.FC<
prValue != null && prValue > 0 ? prValue * conversionFactor : undefined;

return buckets.map((bucket) => {
const metric = bucket.value as number;
const metric = bucket.value ?? 0;
const isPR =
bucket.hasData &&
convertedPR != null &&
Expand Down
2 changes: 1 addition & 1 deletion jestSetupFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jest.mock("expo-file-system/legacy", () => ({
documentDirectory: "/mock/document/directory/",
getInfoAsync: jest.fn((path) =>
Promise.resolve({
exists: path.includes("appData2.db"),
exists: path.includes("appData3.db"),
isDirectory: false,
}),
),
Expand Down
57 changes: 36 additions & 21 deletions utils/__tests__/initAppDataDB.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,44 @@ const mockDatabase = {

describe("initializeAppData", () => {
let mockDirCreate: jest.Mock;
let mockDbFileCopy: jest.Mock;
let mockOldDbFileDelete: jest.Mock;
let mockDbFileDelete: jest.Mock;
let mockOldDb1FileDelete: jest.Mock;
let mockOldDb2FileDelete: jest.Mock;
let mockAssetFileCopy: jest.Mock;

beforeEach(() => {
jest.clearAllMocks();
(openDatabase as jest.Mock).mockReturnValue(mockDatabase);

mockDirCreate = jest.fn();
mockDbFileCopy = jest.fn();
mockOldDbFileDelete = jest.fn();
mockDbFileDelete = jest.fn();
mockOldDb1FileDelete = jest.fn();
mockOldDb2FileDelete = jest.fn();
mockAssetFileCopy = jest.fn();

MockDirectory.mockImplementation(() => ({ create: mockDirCreate }));
});

const setupFileMocks = (dbExists: boolean, oldDbExists: boolean) => {
const setupFileMocks = (
dbExists: boolean,
oldDb1Exists: boolean,
oldDb2Exists: boolean,
) => {
MockFile.mockImplementationOnce(() => ({
exists: dbExists,
copy: mockDbFileCopy,
uri: "/mock/document/directory/SQLite/appData2.db",
delete: mockDbFileDelete,
uri: "/mock/document/directory/SQLite/appData3.db",
})); // dbFile
MockFile.mockImplementationOnce(() => ({
exists: oldDbExists,
delete: mockOldDbFileDelete,
exists: oldDb1Exists,
delete: mockOldDb1FileDelete,
uri: "/mock/document/directory/SQLite/appData1.db",
})); // oldDbFile
})); // oldDbFile1
MockFile.mockImplementationOnce(() => ({
exists: oldDb2Exists,
delete: mockOldDb2FileDelete,
uri: "/mock/document/directory/SQLite/appData2.db",
})); // oldDbFile2
MockFile.mockImplementation(() => ({
exists: true,
copy: mockAssetFileCopy,
Expand All @@ -47,7 +58,7 @@ describe("initializeAppData", () => {
};

it("should not copy database if it exists and dataVersion is sufficient", async () => {
setupFileMocks(true, false);
setupFileMocks(true, false, false);
mockDatabase.getFirstAsync.mockResolvedValue({ value: "2.0" });

await initializeAppData();
Expand All @@ -57,26 +68,28 @@ describe("initializeAppData", () => {
idempotent: true,
});
expect(mockAssetFileCopy).not.toHaveBeenCalled();
expect(mockOldDbFileDelete).not.toHaveBeenCalled();
expect(mockOldDb1FileDelete).not.toHaveBeenCalled();
expect(mockOldDb2FileDelete).not.toHaveBeenCalled();
});

it("should copy database if it does not exist", async () => {
setupFileMocks(false, false);
setupFileMocks(false, false, false);
mockDatabase.getFirstAsync.mockResolvedValue({ value: "2.0" });

await initializeAppData();

expect(Asset.fromModule).toHaveBeenCalled();
expect(mockAssetFileCopy).toHaveBeenCalledWith(
expect.objectContaining({
uri: "/mock/document/directory/SQLite/appData2.db",
uri: "/mock/document/directory/SQLite/appData3.db",
}),
);
expect(mockOldDbFileDelete).not.toHaveBeenCalled();
expect(mockOldDb1FileDelete).not.toHaveBeenCalled();
expect(mockOldDb2FileDelete).not.toHaveBeenCalled();
});

it("should copy database if dataVersion is outdated", async () => {
setupFileMocks(true, false);
setupFileMocks(true, false, false);
mockDatabase.getFirstAsync.mockResolvedValue({ value: "1.5" });

await initializeAppData();
Expand All @@ -85,18 +98,19 @@ describe("initializeAppData", () => {
expect(mockAssetFileCopy).toHaveBeenCalled();
});

it("should delete old database if it exists", async () => {
setupFileMocks(true, true);
it("should delete old database files if they exist", async () => {
setupFileMocks(true, true, true);
mockDatabase.getFirstAsync.mockResolvedValue({ value: "2.0" });

await initializeAppData();

expect(mockAssetFileCopy).not.toHaveBeenCalled();
expect(mockOldDbFileDelete).toHaveBeenCalled();
expect(mockOldDb1FileDelete).toHaveBeenCalled();
expect(mockOldDb2FileDelete).toHaveBeenCalled();
});

it("should proceed if dataVersion retrieval fails", async () => {
setupFileMocks(false, false);
setupFileMocks(false, false, false);
mockDatabase.getFirstAsync.mockRejectedValue(
new Error("Table does not exist"),
);
Expand All @@ -105,6 +119,7 @@ describe("initializeAppData", () => {

expect(Asset.fromModule).toHaveBeenCalled();
expect(mockAssetFileCopy).toHaveBeenCalled();
expect(mockOldDbFileDelete).not.toHaveBeenCalled();
expect(mockOldDb1FileDelete).not.toHaveBeenCalled();
expect(mockOldDb2FileDelete).not.toHaveBeenCalled();
});
});
8 changes: 4 additions & 4 deletions utils/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const updateAppExerciseIds = async (): Promise<void> => {
};

export const copyDataFromAppDataToUserData = async (): Promise<void> => {
const appDataDB = await openDatabase("appData2.db");
const appDataDB = await openDatabase("appData3.db");
const userDataDB = await openDatabase("userData.db");

interface ExerciseCheckResult {
Expand Down Expand Up @@ -306,9 +306,9 @@ export const syncExerciseFlagsFromAppData = async (): Promise<void> => {
const versionResult = await userDataDB.getFirstAsync<SettingsEntry>(
"SELECT value FROM settings WHERE key = 'dataVersion'",
);
if (Number(versionResult?.value) >= 1.9) return;
if (Number(versionResult?.value) >= 2.0) return;

const appDataDB = await openDatabase("appData2.db");
const appDataDB = await openDatabase("appData3.db");
const appExercises = await appDataDB.getAllAsync<{
exercise_id: number;
is_unilateral: number;
Expand All @@ -325,7 +325,7 @@ export const syncExerciseFlagsFromAppData = async (): Promise<void> => {
}
await userDataDB.runAsync(
"INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)",
["dataVersion", "1.9"],
["dataVersion", "2.0"],
);
await userDataDB.execAsync("COMMIT");
} catch (err) {
Expand Down
33 changes: 25 additions & 8 deletions utils/initAppDataDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { File, Directory, Paths } from "expo-file-system";
import { Asset } from "expo-asset";
import { openDatabase } from "./database";

const DATABASE_NAME = "appData2.db";
const DATABASE_NAME = "appData3.db";

const copyDatabase = async (): Promise<void> => {
const dbFolder = new Directory(Paths.document, "SQLite");
const dbFile = new File(Paths.document, "SQLite", DATABASE_NAME);
const oldDbFile = new File(Paths.document, "SQLite", "appData1.db");
const oldDbFile1 = new File(Paths.document, "SQLite", "appData1.db");
const oldDbFile2 = new File(Paths.document, "SQLite", "appData2.db");
const userDataDB = await openDatabase("userData.db");

dbFolder.create({ intermediates: true, idempotent: true });
Expand All @@ -27,17 +28,33 @@ const copyDatabase = async (): Promise<void> => {
);
}

if (!dbFile.exists || dataVersion === null || dataVersion < 1.9) {
console.log("Copying appData2.db ...");
if (!dbFile.exists || dataVersion === null || dataVersion < 2.0) {
console.log(`Copying ${DATABASE_NAME} ...`);
const tempFile = new File(Paths.document, "SQLite", `${DATABASE_NAME}.tmp`);
if (tempFile.exists) {
tempFile.delete();
}
// eslint-disable-next-line @typescript-eslint/no-require-imports
const asset = Asset.fromModule(require(`../assets/db/${DATABASE_NAME}`));
await asset.downloadAsync();
new File(asset.localUri!).copy(dbFile);
new File(asset.localUri!).copy(tempFile);
if (!tempFile.exists) {
throw new Error(`Failed to stage ${DATABASE_NAME} to temp file`);
}
if (dbFile.exists) {
dbFile.delete();
}
tempFile.move(dbFile);
}

if (oldDbFile.exists) {
console.log("Removing outdated appData1.db ...");
oldDbFile.delete();
if (oldDbFile1.exists) {
console.log(`Removing outdated ${oldDbFile1.name} ...`);
oldDbFile1.delete();
}

if (oldDbFile2.exists) {
console.log(`Removing outdated ${oldDbFile2.name} ...`);
oldDbFile2.delete();
}
};

Expand Down
Loading