feat(db): add automatic Drizzle migration on app startup

This commit is contained in:
2026-08-07 12:58:47 +02:00
parent 11f0d16515
commit 16a8970d29
6 changed files with 92 additions and 17 deletions
+52 -2
View File
@@ -1,7 +1,58 @@
// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo // This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo
import journal from './meta/_journal.json'; import journal from './meta/_journal.json';
import m0000 from './0000_mushy_groot.sql';
const m0000 = `
CREATE TABLE \`laps\` (
\`id\` text PRIMARY KEY NOT NULL,
\`workout_id\` text NOT NULL,
\`set_position\` integer NOT NULL,
\`rep_number\` integer NOT NULL,
\`distance\` integer NOT NULL,
\`duration\` real NOT NULL,
\`stroke_count\` integer,
\`heart_rate\` integer,
\`swolf\` real,
FOREIGN KEY (\`workout_id\`) REFERENCES \`workouts\`(\`id\`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE \`sets\` (
\`id\` text PRIMARY KEY NOT NULL,
\`workout_id\` text NOT NULL,
\`position\` integer NOT NULL,
\`stroke\` text NOT NULL,
\`distance_per_rep\` integer NOT NULL,
\`rep_count\` integer NOT NULL,
\`rest_type\` text DEFAULT 'fixed_rest' NOT NULL,
\`rest_duration\` real DEFAULT 0 NOT NULL,
\`target_time\` real,
FOREIGN KEY (\`workout_id\`) REFERENCES \`workouts\`(\`id\`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE \`templates\` (
\`id\` text PRIMARY KEY NOT NULL,
\`name\` text NOT NULL,
\`description\` text,
\`pool_length\` real DEFAULT 25 NOT NULL,
\`json_data\` text NOT NULL,
\`is_favorite\` integer DEFAULT false NOT NULL,
\`created_at\` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE \`workouts\` (
\`id\` text PRIMARY KEY NOT NULL,
\`name\` text,
\`template_id\` text,
\`pool_length\` real DEFAULT 25 NOT NULL,
\`started_at\` text NOT NULL,
\`finished_at\` text,
\`total_distance\` integer,
\`total_duration\` real,
\`calories\` real,
\`avg_heart_rate\` integer,
\`source\` text DEFAULT 'manual' NOT NULL
);
`;
export default { export default {
journal, journal,
@@ -9,4 +60,3 @@ import m0000 from './0000_mushy_groot.sql';
m0000 m0000
} }
} }
+12 -1
View File
@@ -6,4 +6,15 @@ const config = getDefaultConfig(__dirname);
config.resolver.sourceExts.push("sql"); config.resolver.sourceExts.push("sql");
module.exports = withNativewind(config); // Exclude .sql files from CSS/PostCSS processing
config.transformer.getTransformOptions = async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
});
module.exports = withNativewind(config, {
// Ensure .sql files are not processed as CSS
inlineRem: false,
});
+1 -1
View File
@@ -54,7 +54,7 @@ public class WatchConnectivityModule: Module {
} }
AsyncFunction("getApplicationContext") { () -> [String: Any]? in AsyncFunction("getApplicationContext") { () -> [String: Any]? in
return WCSession.default.receivedApplicationContext as? [String: Any] return WCSession.default.receivedApplicationContext as [String: Any]
} }
AsyncFunction("updateApplicationContext") { (context: [String: Any]) in AsyncFunction("updateApplicationContext") { (context: [String: Any]) in
+10
View File
@@ -1,9 +1,19 @@
import { openDatabaseSync } from "expo-sqlite"; import { openDatabaseSync } from "expo-sqlite";
import { drizzle } from "drizzle-orm/expo-sqlite"; import { drizzle } from "drizzle-orm/expo-sqlite";
import { migrate } from "drizzle-orm/expo-sqlite/migrator";
import * as schema from "./schema"; import * as schema from "./schema";
import migrations from "../../drizzle/migrations";
export const DATABASE_NAME = "swimbuddy.db"; export const DATABASE_NAME = "swimbuddy.db";
const expoDb = openDatabaseSync(DATABASE_NAME, { enableChangeListener: true }); const expoDb = openDatabaseSync(DATABASE_NAME, { enableChangeListener: true });
export const db = drizzle(expoDb, { schema }); export const db = drizzle(expoDb, { schema });
// Run migrations on first load
let migrated = false;
export async function ensureMigrations() {
if (migrated) return;
await migrate(db, migrations);
migrated = true;
}
+2 -1
View File
@@ -1,9 +1,10 @@
import { SQLiteProvider } from "expo-sqlite"; import { SQLiteProvider } from "expo-sqlite";
import { DATABASE_NAME } from "../db/client"; import { DATABASE_NAME } from "../db/client";
import { ensureMigrations } from "../db/client";
export function DatabaseProvider({ children }: { children: React.ReactNode }) { export function DatabaseProvider({ children }: { children: React.ReactNode }) {
return ( return (
<SQLiteProvider databaseName={DATABASE_NAME} useSuspense> <SQLiteProvider databaseName={DATABASE_NAME} useSuspense onInit={ensureMigrations}>
{children} {children}
</SQLiteProvider> </SQLiteProvider>
); );
+4 -1
View File
@@ -1,10 +1,13 @@
/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */ /** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = (config) => ({ module.exports = (config) => ({
name: config.name,
type: "watch", type: "watch",
icon: "../../assets/icon.png", icon: "../../assets/icon.png",
deploymentTarget: "10.0", deploymentTarget: "10.0",
entitlements: { entitlements: {
"com.apple.security.application-groups": "com.apple.security.application-groups":
config.ios?.entitlements?.["com.apple.security.application-groups"] ?? [], config.ios?.entitlements?.[
"com.apple.security.application-groups"
] ?? [],
}, },
}); });