feat(db): add automatic Drizzle migration on app startup
This commit is contained in:
+54
-4
@@ -1,12 +1,62 @@
|
|||||||
// 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';
|
|
||||||
|
|
||||||
export default {
|
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 {
|
||||||
journal,
|
journal,
|
||||||
migrations: {
|
migrations: {
|
||||||
m0000
|
m0000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -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,
|
||||||
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
] ?? [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user