2025-02-16 22:47:47 -05:00
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
import { View, ScrollView } from 'react-native';
|
|
|
|
import { Text } from '@/components/ui/text';
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
|
|
import { AlertCircle, CheckCircle2 } from 'lucide-react-native';
|
|
|
|
import { useSQLiteContext } from 'expo-sqlite';
|
|
|
|
import { ExerciseType, ExerciseCategory, Equipment } from '@/types/exercise';
|
2025-02-16 23:53:28 -05:00
|
|
|
import { SQLTransaction, SQLResultSet, SQLError } from '@/lib/db/types';
|
2025-02-16 22:47:47 -05:00
|
|
|
|
|
|
|
interface TableInfo {
|
|
|
|
name: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface SchemaVersion {
|
|
|
|
version: number;
|
|
|
|
}
|
|
|
|
|
2025-02-16 23:53:28 -05:00
|
|
|
interface ExerciseRow {
|
|
|
|
id: string;
|
|
|
|
title: string;
|
|
|
|
type: string;
|
|
|
|
category: string;
|
|
|
|
equipment: string | null;
|
|
|
|
description: string | null;
|
|
|
|
created_at: number;
|
|
|
|
updated_at: number;
|
|
|
|
source: string;
|
|
|
|
format_json: string;
|
|
|
|
format_units_json: string;
|
|
|
|
}
|
|
|
|
|
2025-02-16 22:47:47 -05:00
|
|
|
export default function DatabaseDebug() {
|
|
|
|
const db = useSQLiteContext();
|
|
|
|
const [dbStatus, setDbStatus] = useState<{
|
|
|
|
initialized: boolean;
|
|
|
|
tables: string[];
|
|
|
|
error?: string;
|
|
|
|
}>({
|
|
|
|
initialized: false,
|
|
|
|
tables: [],
|
|
|
|
});
|
|
|
|
|
|
|
|
const [testResults, setTestResults] = useState<{
|
|
|
|
success: boolean;
|
|
|
|
message: string;
|
|
|
|
} | null>(null);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
checkDatabase();
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const checkDatabase = async () => {
|
|
|
|
try {
|
|
|
|
// Check schema_version table
|
|
|
|
const version = await db.getFirstAsync<SchemaVersion>(
|
|
|
|
'SELECT version FROM schema_version ORDER BY version DESC LIMIT 1'
|
|
|
|
);
|
|
|
|
|
|
|
|
// Get all tables
|
|
|
|
const tables = await db.getAllAsync<TableInfo>(
|
|
|
|
"SELECT name FROM sqlite_master WHERE type='table'"
|
|
|
|
);
|
|
|
|
|
|
|
|
setDbStatus({
|
|
|
|
initialized: !!version,
|
|
|
|
tables: tables.map(t => t.name),
|
|
|
|
});
|
|
|
|
} catch (error) {
|
2025-02-16 23:53:28 -05:00
|
|
|
console.error('Error checking database:', error);
|
2025-02-16 22:47:47 -05:00
|
|
|
setDbStatus(prev => ({
|
|
|
|
...prev,
|
|
|
|
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const runTestInsert = async () => {
|
|
|
|
try {
|
|
|
|
// Test exercise
|
|
|
|
const testExercise = {
|
|
|
|
title: "Test Squat",
|
|
|
|
type: "strength" as ExerciseType,
|
|
|
|
category: "Legs" as ExerciseCategory,
|
|
|
|
equipment: "barbell" as Equipment,
|
|
|
|
description: "Test exercise",
|
|
|
|
tags: ["test", "legs"],
|
|
|
|
format: {
|
|
|
|
weight: true,
|
|
|
|
reps: true
|
|
|
|
},
|
|
|
|
format_units: {
|
|
|
|
weight: "kg" as const,
|
|
|
|
reps: "count" as const
|
|
|
|
}
|
|
|
|
};
|
2025-02-16 23:53:28 -05:00
|
|
|
|
|
|
|
const timestamp = Date.now();
|
|
|
|
|
|
|
|
// Insert exercise using withTransactionAsync
|
2025-02-16 22:47:47 -05:00
|
|
|
await db.withTransactionAsync(async () => {
|
|
|
|
// Insert exercise
|
|
|
|
await db.runAsync(
|
|
|
|
`INSERT INTO exercises (
|
|
|
|
id, title, type, category, equipment, description,
|
2025-02-16 23:53:28 -05:00
|
|
|
format_json, format_units_json, created_at, updated_at
|
|
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
2025-02-16 22:47:47 -05:00
|
|
|
[
|
|
|
|
'test-1',
|
|
|
|
testExercise.title,
|
|
|
|
testExercise.type,
|
|
|
|
testExercise.category,
|
|
|
|
testExercise.equipment || null,
|
|
|
|
testExercise.description || null,
|
|
|
|
JSON.stringify(testExercise.format),
|
2025-02-16 23:53:28 -05:00
|
|
|
JSON.stringify(testExercise.format_units),
|
|
|
|
timestamp,
|
|
|
|
timestamp
|
2025-02-16 22:47:47 -05:00
|
|
|
]
|
|
|
|
);
|
2025-02-16 23:53:28 -05:00
|
|
|
|
2025-02-16 22:47:47 -05:00
|
|
|
// Insert tags
|
|
|
|
for (const tag of testExercise.tags) {
|
|
|
|
await db.runAsync(
|
|
|
|
"INSERT INTO exercise_tags (exercise_id, tag) VALUES (?, ?)",
|
|
|
|
['test-1', tag]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2025-02-16 23:53:28 -05:00
|
|
|
|
2025-02-16 22:47:47 -05:00
|
|
|
// Verify insert
|
2025-02-16 23:53:28 -05:00
|
|
|
const result = await db.getFirstAsync<ExerciseRow>(
|
|
|
|
"SELECT * FROM exercises WHERE id = ?",
|
2025-02-16 22:47:47 -05:00
|
|
|
['test-1']
|
|
|
|
);
|
2025-02-16 23:53:28 -05:00
|
|
|
|
2025-02-16 22:47:47 -05:00
|
|
|
setTestResults({
|
|
|
|
success: true,
|
|
|
|
message: `Successfully inserted and verified test exercise: ${JSON.stringify(result, null, 2)}`
|
|
|
|
});
|
2025-02-16 23:53:28 -05:00
|
|
|
|
2025-02-16 22:47:47 -05:00
|
|
|
} catch (error) {
|
2025-02-16 23:53:28 -05:00
|
|
|
console.error('Test insert error:', error);
|
2025-02-16 22:47:47 -05:00
|
|
|
setTestResults({
|
|
|
|
success: false,
|
|
|
|
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<View className="p-4 mb-4">
|
2025-02-17 11:24:17 -05:00
|
|
|
<Card className="mt-4"> {/* Add mt-4 to create spacing */}
|
2025-02-16 22:47:47 -05:00
|
|
|
<CardHeader>
|
|
|
|
<CardTitle>
|
|
|
|
<Text className="text-xl font-semibold">Database Status</Text>
|
|
|
|
</CardTitle>
|
|
|
|
</CardHeader>
|
|
|
|
<CardContent>
|
|
|
|
<View className="space-y-2">
|
|
|
|
<Text>Initialized: {dbStatus.initialized ? '✅' : '❌'}</Text>
|
|
|
|
<Text>Tables Found: {dbStatus.tables.length}</Text>
|
|
|
|
<View className="pl-4">
|
|
|
|
{dbStatus.tables.map(table => (
|
|
|
|
<Text key={table} className="text-muted-foreground">• {table}</Text>
|
|
|
|
))}
|
|
|
|
</View>
|
|
|
|
{dbStatus.error && (
|
|
|
|
<View className="mt-4 p-4 bg-destructive/10 rounded-lg border border-destructive">
|
|
|
|
<View className="flex-row items-center gap-2">
|
|
|
|
<AlertCircle className="text-destructive" size={20} />
|
|
|
|
<Text className="font-semibold text-destructive">Error</Text>
|
|
|
|
</View>
|
|
|
|
<Text className="mt-2 text-destructive">{dbStatus.error}</Text>
|
|
|
|
</View>
|
|
|
|
)}
|
|
|
|
</View>
|
|
|
|
</CardContent>
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
<Card className="mt-4">
|
|
|
|
<CardHeader>
|
|
|
|
<CardTitle>
|
|
|
|
<Text className="text-xl font-semibold">Database Tests</Text>
|
|
|
|
</CardTitle>
|
|
|
|
</CardHeader>
|
|
|
|
<CardContent>
|
|
|
|
<View className="space-y-4">
|
|
|
|
<Button
|
|
|
|
onPress={runTestInsert}
|
|
|
|
>
|
|
|
|
<Text className="text-primary-foreground">Run Test Insert</Text>
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
{testResults && (
|
|
|
|
<View className={`mt-4 p-4 rounded-lg border ${
|
|
|
|
testResults.success
|
|
|
|
? 'bg-primary/10 border-primary'
|
|
|
|
: 'bg-destructive/10 border-destructive'
|
|
|
|
}`}>
|
|
|
|
<View className="flex-row items-center gap-2">
|
|
|
|
{testResults.success ? (
|
|
|
|
<CheckCircle2
|
|
|
|
className="text-primary"
|
|
|
|
size={20}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<AlertCircle
|
|
|
|
className="text-destructive"
|
|
|
|
size={20}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<Text className={`font-semibold ${
|
|
|
|
testResults.success ? 'text-primary' : 'text-destructive'
|
|
|
|
}`}>
|
|
|
|
{testResults.success ? "Test Passed" : "Test Failed"}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
<Text className="mt-2 text-foreground">
|
|
|
|
{testResults.message}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
)}
|
|
|
|
</View>
|
|
|
|
</CardContent>
|
|
|
|
</Card>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
}
|