mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 01:35:39 -04:00
refactor: replace Biome with oxlint + oxfmt
Migrate the entire monorepo from Biome 2.4.7 to oxlint 1.56.0 (linter) and oxfmt 0.41.0 (formatter) for faster lint/format and broader rule coverage. - Add `.oxlintrc.json` with React, TypeScript, unicorn, import plugins and correctness/suspicious categories - Add `.oxfmtrc.json` with 2-space indent, import sorting, and Tailwind class sorting (all 30+ custom className attributes migrated) - Add `docs/.oxlintrc.json` and `docs/.oxfmtrc.json` with Next.js plugin - Update all 12 workspace package.json scripts: `oxlint`, `oxfmt`, `oxfmt --check` - Add `format:check` turbo task and CI step - Update VS Code settings/extensions to use `oxc.oxc-vscode` - Update CI path triggers from `biome.json` to new config files - Remove all `biome-ignore` comments and fix shadowed variables - Delete `biome.json` and `docs/biome.json` - Reformat entire codebase with oxfmt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import { Database } from "bun:sqlite";
|
||||
import { DATABASE_URL } from "@sofa/config";
|
||||
import { createLogger } from "@sofa/logger";
|
||||
|
||||
import type { Logger } from "drizzle-orm";
|
||||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||
|
||||
import { DATABASE_URL } from "@sofa/config";
|
||||
import { createLogger } from "@sofa/logger";
|
||||
|
||||
import * as schema from "./schema";
|
||||
|
||||
const log = createLogger("drizzle");
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import path from "node:path";
|
||||
import { createLogger } from "@sofa/logger";
|
||||
|
||||
import { migrate } from "drizzle-orm/bun-sqlite/migrator";
|
||||
|
||||
import { createLogger } from "@sofa/logger";
|
||||
|
||||
import { db } from "./client";
|
||||
|
||||
const log = createLogger("db");
|
||||
|
||||
export function runMigrations(
|
||||
migrationsFolder = path.join(import.meta.dir, "../drizzle"),
|
||||
) {
|
||||
export function runMigrations(migrationsFolder = path.join(import.meta.dir, "../drizzle")) {
|
||||
log.info("Running database migrations...");
|
||||
migrate(db, { migrationsFolder });
|
||||
log.info("Database migrations complete");
|
||||
|
||||
+15
-64
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
index,
|
||||
int,
|
||||
real,
|
||||
sqliteTable,
|
||||
text,
|
||||
uniqueIndex,
|
||||
} from "drizzle-orm/sqlite-core";
|
||||
import { index, int, real, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
||||
|
||||
// Helper for UUID primary keys
|
||||
const uuidPk = () =>
|
||||
@@ -19,9 +12,7 @@ export const user = sqliteTable("user", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
email: text("email").notNull().unique(),
|
||||
emailVerified: int("emailVerified", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
emailVerified: int("emailVerified", { mode: "boolean" }).notNull().default(false),
|
||||
image: text("image"),
|
||||
role: text("role").default("user"),
|
||||
banned: int("banned", { mode: "boolean" }).default(false),
|
||||
@@ -130,11 +121,7 @@ export const titles = sqliteTable(
|
||||
index("titles_type_releaseDate").on(table.type, table.releaseDate),
|
||||
index("titles_type_firstAirDate").on(table.type, table.firstAirDate),
|
||||
index("titles_lastFetchedAt").on(table.lastFetchedAt),
|
||||
index("titles_type_status_lastFetchedAt").on(
|
||||
table.type,
|
||||
table.status,
|
||||
table.lastFetchedAt,
|
||||
),
|
||||
index("titles_type_status_lastFetchedAt").on(table.type, table.status, table.lastFetchedAt),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -153,12 +140,7 @@ export const seasons = sqliteTable(
|
||||
airDate: text("airDate"),
|
||||
lastFetchedAt: int("lastFetchedAt", { mode: "timestamp" }),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("seasons_titleId_seasonNumber").on(
|
||||
table.titleId,
|
||||
table.seasonNumber,
|
||||
),
|
||||
],
|
||||
(table) => [uniqueIndex("seasons_titleId_seasonNumber").on(table.titleId, table.seasonNumber)],
|
||||
);
|
||||
|
||||
export const episodes = sqliteTable(
|
||||
@@ -177,10 +159,7 @@ export const episodes = sqliteTable(
|
||||
runtimeMinutes: int("runtimeMinutes"),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("episodes_seasonId_episodeNumber").on(
|
||||
table.seasonId,
|
||||
table.episodeNumber,
|
||||
),
|
||||
uniqueIndex("episodes_seasonId_episodeNumber").on(table.seasonId, table.episodeNumber),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -200,10 +179,7 @@ export const userTitleStatus = sqliteTable(
|
||||
updatedAt: int("updatedAt", { mode: "timestamp" }).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("userTitleStatus_userId_titleId").on(
|
||||
table.userId,
|
||||
table.titleId,
|
||||
),
|
||||
uniqueIndex("userTitleStatus_userId_titleId").on(table.userId, table.titleId),
|
||||
index("userTitleStatus_userId_status").on(table.userId, table.status),
|
||||
],
|
||||
);
|
||||
@@ -226,10 +202,7 @@ export const userMovieWatches = sqliteTable(
|
||||
.default("manual"),
|
||||
},
|
||||
(table) => [
|
||||
index("userMovieWatches_userId_watchedAt").on(
|
||||
table.userId,
|
||||
table.watchedAt,
|
||||
),
|
||||
index("userMovieWatches_userId_watchedAt").on(table.userId, table.watchedAt),
|
||||
index("userMovieWatches_titleId").on(table.titleId),
|
||||
index("userMovieWatches_userId_titleId").on(table.userId, table.titleId),
|
||||
],
|
||||
@@ -253,15 +226,9 @@ export const userEpisodeWatches = sqliteTable(
|
||||
.default("manual"),
|
||||
},
|
||||
(table) => [
|
||||
index("userEpisodeWatches_userId_watchedAt").on(
|
||||
table.userId,
|
||||
table.watchedAt,
|
||||
),
|
||||
index("userEpisodeWatches_userId_watchedAt").on(table.userId, table.watchedAt),
|
||||
index("userEpisodeWatches_episodeId").on(table.episodeId),
|
||||
index("userEpisodeWatches_userId_episodeId").on(
|
||||
table.userId,
|
||||
table.episodeId,
|
||||
),
|
||||
index("userEpisodeWatches_userId_episodeId").on(table.userId, table.episodeId),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -277,9 +244,7 @@ export const userRatings = sqliteTable(
|
||||
ratingStars: int("ratingStars").notNull(),
|
||||
ratedAt: int("ratedAt", { mode: "timestamp" }).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("userRatings_userId_titleId").on(table.userId, table.titleId),
|
||||
],
|
||||
(table) => [uniqueIndex("userRatings_userId_titleId").on(table.userId, table.titleId)],
|
||||
);
|
||||
|
||||
export const availabilityOffers = sqliteTable(
|
||||
@@ -385,10 +350,7 @@ export const titleCast = sqliteTable(
|
||||
table.department,
|
||||
table.character,
|
||||
),
|
||||
index("titleCast_titleId_displayOrder").on(
|
||||
table.titleId,
|
||||
table.displayOrder,
|
||||
),
|
||||
index("titleCast_titleId_displayOrder").on(table.titleId, table.displayOrder),
|
||||
index("titleCast_personId").on(table.personId),
|
||||
],
|
||||
);
|
||||
@@ -409,10 +371,7 @@ export const personFilmography = sqliteTable(
|
||||
displayOrder: int("displayOrder").notNull().default(0),
|
||||
},
|
||||
(table) => [
|
||||
index("personFilmography_personId_displayOrder").on(
|
||||
table.personId,
|
||||
table.displayOrder,
|
||||
),
|
||||
index("personFilmography_personId_displayOrder").on(table.personId, table.displayOrder),
|
||||
index("personFilmography_titleId").on(table.titleId),
|
||||
],
|
||||
);
|
||||
@@ -434,10 +393,7 @@ export const integrations = sqliteTable(
|
||||
lastEventAt: int("lastEventAt", { mode: "timestamp" }),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("integrations_userId_provider").on(
|
||||
table.userId,
|
||||
table.provider,
|
||||
),
|
||||
uniqueIndex("integrations_userId_provider").on(table.userId, table.provider),
|
||||
uniqueIndex("integrations_token").on(table.token),
|
||||
],
|
||||
);
|
||||
@@ -459,10 +415,7 @@ export const integrationEvents = sqliteTable(
|
||||
receivedAt: int("receivedAt", { mode: "timestamp" }).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index("integrationEvents_integrationId_receivedAt").on(
|
||||
table.integrationId,
|
||||
table.receivedAt,
|
||||
),
|
||||
index("integrationEvents_integrationId_receivedAt").on(table.integrationId, table.receivedAt),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -481,9 +434,7 @@ export const cronRuns = sqliteTable(
|
||||
durationMs: int("durationMs"),
|
||||
errorMessage: text("errorMessage"),
|
||||
},
|
||||
(table) => [
|
||||
index("cronRuns_jobName_startedAt").on(table.jobName, table.startedAt),
|
||||
],
|
||||
(table) => [index("cronRuns_jobName_startedAt").on(table.jobName, table.startedAt)],
|
||||
);
|
||||
|
||||
// ─── Import Jobs ────────────────────────────────────────────────────
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||
import { migrate } from "drizzle-orm/bun-sqlite/migrator";
|
||||
|
||||
import * as schema from "./schema";
|
||||
|
||||
const {
|
||||
@@ -28,9 +30,7 @@ export function applyMigrations() {
|
||||
|
||||
export function clearAllTables() {
|
||||
const tables = testClient
|
||||
.query(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '__drizzle%'",
|
||||
)
|
||||
.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '__drizzle%'")
|
||||
.all() as { name: string }[];
|
||||
testClient.run("PRAGMA foreign_keys = OFF");
|
||||
for (const { name } of tables) {
|
||||
@@ -79,20 +79,12 @@ export function insertTitle(
|
||||
return id;
|
||||
}
|
||||
|
||||
export function insertTvShow(
|
||||
titleId = "tv-1",
|
||||
tmdbId = 99999,
|
||||
seasonCount = 1,
|
||||
epsPerSeason = 3,
|
||||
) {
|
||||
export function insertTvShow(titleId = "tv-1", tmdbId = 99999, seasonCount = 1, epsPerSeason = 3) {
|
||||
insertTitle({ id: titleId, tmdbId, type: "tv", title: "Test Show" });
|
||||
const episodeIds: string[] = [];
|
||||
for (let s = 1; s <= seasonCount; s++) {
|
||||
const seasonId = `${titleId}-s${s}`;
|
||||
testDb
|
||||
.insert(seasons)
|
||||
.values({ id: seasonId, titleId, seasonNumber: s })
|
||||
.run();
|
||||
testDb.insert(seasons).values({ id: seasonId, titleId, seasonNumber: s }).run();
|
||||
for (let e = 1; e <= epsPerSeason; e++) {
|
||||
const epId = `${titleId}-s${s}e${e}`;
|
||||
testDb
|
||||
@@ -110,11 +102,7 @@ export function insertTvShow(
|
||||
return { titleId, episodeIds };
|
||||
}
|
||||
|
||||
export function insertMovieWatch(
|
||||
userId: string,
|
||||
titleId: string,
|
||||
watchedAt?: Date,
|
||||
) {
|
||||
export function insertMovieWatch(userId: string, titleId: string, watchedAt?: Date) {
|
||||
testDb
|
||||
.insert(userMovieWatches)
|
||||
.values({
|
||||
@@ -126,11 +114,7 @@ export function insertMovieWatch(
|
||||
.run();
|
||||
}
|
||||
|
||||
export function insertEpisodeWatch(
|
||||
userId: string,
|
||||
episodeId: string,
|
||||
watchedAt?: Date,
|
||||
) {
|
||||
export function insertEpisodeWatch(userId: string, episodeId: string, watchedAt?: Date) {
|
||||
testDb
|
||||
.insert(userEpisodeWatches)
|
||||
.values({
|
||||
@@ -147,22 +131,15 @@ export function insertStatus(
|
||||
titleId: string,
|
||||
status: "watchlist" | "in_progress" | "completed",
|
||||
) {
|
||||
const now = new Date();
|
||||
const timestamp = new Date();
|
||||
testDb
|
||||
.insert(userTitleStatus)
|
||||
.values({ userId, titleId, status, addedAt: now, updatedAt: now })
|
||||
.values({ userId, titleId, status, addedAt: timestamp, updatedAt: timestamp })
|
||||
.run();
|
||||
}
|
||||
|
||||
export function insertRating(
|
||||
userId: string,
|
||||
titleId: string,
|
||||
ratingStars: number,
|
||||
) {
|
||||
testDb
|
||||
.insert(userRatings)
|
||||
.values({ userId, titleId, ratingStars, ratedAt: new Date() })
|
||||
.run();
|
||||
export function insertRating(userId: string, titleId: string, ratingStars: number) {
|
||||
testDb.insert(userRatings).values({ userId, titleId, ratingStars, ratedAt: new Date() }).run();
|
||||
}
|
||||
|
||||
export function insertAvailabilityOffer(
|
||||
@@ -184,13 +161,8 @@ export function insertAvailabilityOffer(
|
||||
.run();
|
||||
}
|
||||
|
||||
export function insertIntegration(
|
||||
userId: string,
|
||||
provider: string,
|
||||
token = "test-token",
|
||||
) {
|
||||
const type =
|
||||
provider === "sonarr" || provider === "radarr" ? "list" : "webhook";
|
||||
export function insertIntegration(userId: string, provider: string, token = "test-token") {
|
||||
const type = provider === "sonarr" || provider === "radarr" ? "list" : "webhook";
|
||||
return testDb
|
||||
.insert(integrations)
|
||||
.values({
|
||||
|
||||
Reference in New Issue
Block a user