fix: resolve build, lint, and type errors - add paramName support to CRUD builder
This commit is contained in:
+13
-9
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { Elysia, t } from "elysia"
|
import { Elysia, t } from "elysia"
|
||||||
import { db } from "@/lib/db/index"
|
import { db } from "@/lib/db/index"
|
||||||
import { getTableColumns } from "drizzle-orm"
|
import { getTableColumns } from "drizzle-orm"
|
||||||
@@ -44,6 +45,7 @@ export type CrudAuthConfig = {
|
|||||||
* @param config.filter - Exact-match filter configuration
|
* @param config.filter - Exact-match filter configuration
|
||||||
* @param config.name - Human-readable name for error messages
|
* @param config.name - Human-readable name for error messages
|
||||||
* @param config.primaryKey - Column name used as primary key (default: "id")
|
* @param config.primaryKey - Column name used as primary key (default: "id")
|
||||||
|
* @param config.paramName - URL parameter name (defaults to primaryKey)
|
||||||
* @param config.softDelete - If true, DELETE sets isRemoved=true instead of deleting
|
* @param config.softDelete - If true, DELETE sets isRemoved=true instead of deleting
|
||||||
*/
|
*/
|
||||||
export function createCrudRoutes<T extends AnyPgTable>(
|
export function createCrudRoutes<T extends AnyPgTable>(
|
||||||
@@ -55,6 +57,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
filter?: CrudFilterConfig
|
filter?: CrudFilterConfig
|
||||||
name?: string
|
name?: string
|
||||||
primaryKey?: string
|
primaryKey?: string
|
||||||
|
paramName?: string
|
||||||
softDelete?: boolean
|
softDelete?: boolean
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
@@ -65,6 +68,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
filter,
|
filter,
|
||||||
name = "resource",
|
name = "resource",
|
||||||
primaryKey = "id",
|
primaryKey = "id",
|
||||||
|
paramName = primaryKey,
|
||||||
softDelete = false,
|
softDelete = false,
|
||||||
} = config
|
} = config
|
||||||
|
|
||||||
@@ -152,9 +156,9 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
|
|
||||||
// ── GET BY ID ─────────────────────────────────────────────────────
|
// ── GET BY ID ─────────────────────────────────────────────────────
|
||||||
routes.get(
|
routes.get(
|
||||||
`/:${primaryKey}`,
|
`/:${paramName}`,
|
||||||
async ({ params, set }) => {
|
async ({ params, set }) => {
|
||||||
const id = (params as any)[primaryKey]
|
const id = (params as any)[paramName]
|
||||||
|
|
||||||
const [record] = await db
|
const [record] = await db
|
||||||
.select()
|
.select()
|
||||||
@@ -171,7 +175,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
params: t.Object({
|
params: t.Object({
|
||||||
[primaryKey]: t.String(),
|
[paramName]: t.String(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -206,7 +210,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
|
|
||||||
// ── UPDATE ────────────────────────────────────────────────────────
|
// ── UPDATE ────────────────────────────────────────────────────────
|
||||||
routes.patch(
|
routes.patch(
|
||||||
`/:${primaryKey}`,
|
`/:${paramName}`,
|
||||||
async ({ params, body, request, set }) => {
|
async ({ params, body, request, set }) => {
|
||||||
const roleMap: Record<string, string[]> = {
|
const roleMap: Record<string, string[]> = {
|
||||||
user: ["user", "contributor", "admin"],
|
user: ["user", "contributor", "admin"],
|
||||||
@@ -221,7 +225,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
return { error: guard.error }
|
return { error: guard.error }
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = (params as any)[primaryKey]
|
const id = (params as any)[paramName]
|
||||||
|
|
||||||
// Add updatedAt if column exists
|
// Add updatedAt if column exists
|
||||||
const updateData = columns["updatedAt"]
|
const updateData = columns["updatedAt"]
|
||||||
@@ -243,7 +247,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
params: t.Object({
|
params: t.Object({
|
||||||
[primaryKey]: t.String(),
|
[paramName]: t.String(),
|
||||||
}),
|
}),
|
||||||
body: t.Record(t.String(), t.Any()),
|
body: t.Record(t.String(), t.Any()),
|
||||||
},
|
},
|
||||||
@@ -251,7 +255,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
|
|
||||||
// ── DELETE ────────────────────────────────────────────────────────
|
// ── DELETE ────────────────────────────────────────────────────────
|
||||||
routes.delete(
|
routes.delete(
|
||||||
`/:${primaryKey}`,
|
`/:${paramName}`,
|
||||||
async ({ params, request, set }) => {
|
async ({ params, request, set }) => {
|
||||||
const guard = await requireRole(request.headers, [authConfig.delete])
|
const guard = await requireRole(request.headers, [authConfig.delete])
|
||||||
|
|
||||||
@@ -260,7 +264,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
return { error: guard.error }
|
return { error: guard.error }
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = (params as any)[primaryKey]
|
const id = (params as any)[paramName]
|
||||||
|
|
||||||
if (softDelete && columns["isRemoved"]) {
|
if (softDelete && columns["isRemoved"]) {
|
||||||
const [updated] = (await db
|
const [updated] = (await db
|
||||||
@@ -291,7 +295,7 @@ export function createCrudRoutes<T extends AnyPgTable>(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
params: t.Object({
|
params: t.Object({
|
||||||
[primaryKey]: t.String(),
|
[paramName]: t.String(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export const gamesRoutes = createCrudRoutes(games, {
|
|||||||
auth: { read: "public", write: "contributor", delete: "admin" },
|
auth: { read: "public", write: "contributor", delete: "admin" },
|
||||||
search: { fields: ["title", "developer", "publisher"] },
|
search: { fields: ["title", "developer", "publisher"] },
|
||||||
filter: { fields: ["source", "onlineMultiplayerStatus", "syncStatus"] },
|
filter: { fields: ["source", "onlineMultiplayerStatus", "syncStatus"] },
|
||||||
|
paramName: "gameId",
|
||||||
})
|
})
|
||||||
|
|
||||||
// ── Game Versions (nested under /games/:gameId/versions) ──────────
|
// ── Game Versions (nested under /games/:gameId/versions) ──────────
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Elysia, t } from "elysia"
|
|||||||
import { createCrudRoutes } from "./crud-builder"
|
import { createCrudRoutes } from "./crud-builder"
|
||||||
import { performanceEntries, games, gameVersions } from "@/lib/db/schema"
|
import { performanceEntries, games, gameVersions } from "@/lib/db/schema"
|
||||||
import { db } from "@/lib/db/index"
|
import { db } from "@/lib/db/index"
|
||||||
import { eq, and, desc, sql } from "drizzle-orm"
|
import { eq, and, sql } from "drizzle-orm"
|
||||||
import { requireRole } from "@/lib/auth/guard"
|
import { requireRole } from "@/lib/auth/guard"
|
||||||
|
|
||||||
// ── Performance Entries CRUD ──────────────────────────────────────
|
// ── Performance Entries CRUD ──────────────────────────────────────
|
||||||
@@ -84,7 +84,7 @@ export const performanceVerifyRoutes = new Elysia({
|
|||||||
conditions.push(eq(performanceEntries.hardwareSlug, hardwareSlug))
|
conditions.push(eq(performanceEntries.hardwareSlug, hardwareSlug))
|
||||||
}
|
}
|
||||||
if (fsrVersion) {
|
if (fsrVersion) {
|
||||||
conditions.push(eq(performanceEntries.fsrVersion, fsrVersion as any))
|
conditions.push(eq(performanceEntries.fsrVersion, fsrVersion as any)) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join through gameVersions to get to games
|
// Join through gameVersions to get to games
|
||||||
|
|||||||
+5
-4
@@ -12,11 +12,12 @@ export const presetsRoutes = createCrudRoutes(communityPresets, {
|
|||||||
auth: { read: "public", write: "user", delete: "admin" },
|
auth: { read: "public", write: "user", delete: "admin" },
|
||||||
search: { fields: ["name", "description"] },
|
search: { fields: ["name", "description"] },
|
||||||
filter: { fields: ["gameId", "hardwareSlug"] },
|
filter: { fields: ["gameId", "hardwareSlug"] },
|
||||||
|
paramName: "presetId",
|
||||||
})
|
})
|
||||||
|
|
||||||
// ── Upvote endpoint ───────────────────────────────────────────────
|
// ── Upvote endpoint ───────────────────────────────────────────────
|
||||||
export const presetUpvoteRoutes = new Elysia({ prefix: "/presets" }).post(
|
export const presetUpvoteRoutes = new Elysia({ prefix: "/presets" }).post(
|
||||||
"/:id/upvote",
|
"/:presetId/upvote",
|
||||||
async ({ params, request, set }) => {
|
async ({ params, request, set }) => {
|
||||||
const guard = await requireRole(request.headers, [
|
const guard = await requireRole(request.headers, [
|
||||||
"user",
|
"user",
|
||||||
@@ -31,7 +32,7 @@ export const presetUpvoteRoutes = new Elysia({ prefix: "/presets" }).post(
|
|||||||
const [preset] = await db
|
const [preset] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(communityPresets)
|
.from(communityPresets)
|
||||||
.where(eq(communityPresets.id, params.id))
|
.where(eq(communityPresets.id, params.presetId))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
|
|
||||||
if (!preset) {
|
if (!preset) {
|
||||||
@@ -45,13 +46,13 @@ export const presetUpvoteRoutes = new Elysia({ prefix: "/presets" }).post(
|
|||||||
upvotes: sql`${communityPresets.upvotes} + 1`,
|
upvotes: sql`${communityPresets.upvotes} + 1`,
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
})
|
})
|
||||||
.where(eq(communityPresets.id, params.id))
|
.where(eq(communityPresets.id, params.presetId))
|
||||||
.returning()
|
.returning()
|
||||||
|
|
||||||
return updated
|
return updated
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
params: t.Object({ id: t.String() }),
|
params: t.Object({ presetId: t.String() }),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { Elysia, t } from "elysia"
|
import { Elysia } from "elysia"
|
||||||
import { createCrudRoutes } from "./crud-builder"
|
import { createCrudRoutes } from "./crud-builder"
|
||||||
import { settingCategories, settingDefinitions } from "@/lib/db/schema"
|
import { settingCategories, settingDefinitions } from "@/lib/db/schema"
|
||||||
import { db } from "@/lib/db/index"
|
import { db } from "@/lib/db/index"
|
||||||
import { eq, asc } from "drizzle-orm"
|
import { asc } from "drizzle-orm"
|
||||||
|
|
||||||
// ── Setting Categories CRUD ───────────────────────────────────────
|
// ── Setting Categories CRUD ───────────────────────────────────────
|
||||||
export const settingCategoriesRoutes = createCrudRoutes(settingCategories, {
|
export const settingCategoriesRoutes = createCrudRoutes(settingCategories, {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const gameComments = pgTable(
|
|||||||
userId: text("user_id")
|
userId: text("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => user.id, { onDelete: "cascade" }),
|
.references(() => user.id, { onDelete: "cascade" }),
|
||||||
parentId: text("parent_id").references((): any => gameComments.id, {
|
parentId: text("parent_id").references((): any => gameComments.id, { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
// Tiptap JSON document
|
// Tiptap JSON document
|
||||||
|
|||||||
Reference in New Issue
Block a user