Added Paginated Endpoint

Reformatted Code
This commit is contained in:
2025-10-27 17:39:25 +01:00
parent d4fe665462
commit 5d3cdeb960

View File

@@ -335,7 +335,8 @@ const dataTypes: any[] = {
redirect: true, redirect: true,
showTabs: [ showTabs: [
{ {
label: 'Informationen',} label: 'Informationen',
}
] ]
}, },
profiles: { profiles: {
@@ -472,6 +473,7 @@ const dataTypes: any[] = {
} }
export default async function resourceRoutes(server: FastifyInstance) { export default async function resourceRoutes(server: FastifyInstance) {
//Liste //Liste
server.get("/resource/:resource", async (req, reply) => { server.get("/resource/:resource", async (req, reply) => {
if (!req.user?.tenant_id) { if (!req.user?.tenant_id) {
@@ -499,18 +501,173 @@ export default async function resourceRoutes(server: FastifyInstance) {
return sorted; return sorted;
}); });
// Liste Paginated
server.get("/resource/:resource/paginated", async (req, reply) => {
if (!req.user?.tenant_id) {
return reply.code(400).send({error: "No tenant selected"});
}
const {resource} = req.params as { resource: string }
const {queryConfig} = req
const {pagination, sort, filters, paginationDisabled} = queryConfig
const {select, search, searchColumns,distinctColumns} = req.query as {
select?: string, search?: string, searchColumns?: string, distinctColumns?: string
}
console.log(queryConfig)
// --- Supabase-Basisabfrage ---
let baseQuery = server.supabase
.from(resource)
.select(select ? select : "*", {count: "exact"}) // 👈 Zählt Ergebnisse direkt mit
.eq("tenant", req.user.tenant_id)
// --- 🔍 Serverseitige Suche über angegebene Spalten ---
if (search && search.trim().length > 0) {
const cols = searchColumns
? searchColumns.split(',').map(c => c.trim()).filter(Boolean)
: []
if (cols.length > 0) {
const searchValue = `%${search.trim()}%`
// JSONB-Unterfelder umwandeln in "->>" Syntax
const formattedCols = cols.map(c => {
if (c.includes('.')) {
const [jsonField, jsonKey] = c.split('.')
return `${jsonField}->>${jsonKey}`
}
return c
})
// or() Query dynamisch zusammenbauen
const orConditions = formattedCols
.map(f => `${f}.ilike.${searchValue}`)
.join(',')
baseQuery = baseQuery.or(orConditions)
}
}
// --- Filterung (intelligente Typ-Erkennung) ---
for (const [key, val] of Object.entries(queryConfig.filters)) {
if (Array.isArray(val)) {
baseQuery = baseQuery.in(key, val)
//@ts-ignore
} else if (val === true || val === false || val === null) {
baseQuery = baseQuery.is(key, val)
} else {
baseQuery = baseQuery.eq(key, val)
}
}
// --- Sortierung ---
if (sort.length > 0) {
for (const s of sort) {
baseQuery = baseQuery.order(s.field, {ascending: s.direction === "asc"})
}
}
// --- Pagination ---
if (!paginationDisabled && pagination) {
const {offset, limit} = pagination
baseQuery = baseQuery.range(offset, offset + limit - 1)
}
// --- Abfrage ausführen ---
const {data, error, count} = await baseQuery
if (error) {
server.log.error(error)
return reply.code(400).send({error: error.message})
}
// --- Distinct-Werte ermitteln ---
const distinctValues: Record<string, any[]> = {}
if (distinctColumns) {
const cols = distinctColumns.split(",").map(c => c.trim()).filter(Boolean)
for (const col of cols) {
const isJson = col.includes(".")
const {data: allRows, error: distinctErr} = await server.supabase
.from(resource)
.select(isJson ? "*" : col)
.eq("tenant", req.user.tenant_id)
if (distinctErr) continue
const values = (allRows || [])
.map(row => {
if (isJson) {
const [jsonField, jsonKey] = col.split(".")
return row?.[jsonField]?.[jsonKey] ?? null
}
return row?.[col] ?? null
})
.filter(v => v !== null && v !== undefined && v !== "")
distinctValues[col] = [...new Set(values)].sort()
}
}
// --- Gesamtanzahl & Seitenberechnung ---
const total = count
const totalPages =
!paginationDisabled && pagination?.limit
? Math.ceil(total / pagination.limit)
: 1
// --- queryConfig erweitern ---
const enrichedConfig = {
...queryConfig,
total,
totalPages,
distinctValues,
search: search || null
}
return {
data: data,
queryConfig: enrichedConfig
}
/*const { data, error } = await server.supabase
.from(resource)
//@ts-ignore
.select(select || dataTypes[resource].supabaseSelectWithInformation)
.eq("tenant", req.user.tenant_id)
if (error) {
console.log(error)
return reply.code(400).send({ error: error.message });
}
const sorted =sortData(data,sort,asc === "true" ? true : false)
return sorted;*/
});
// Detail // Detail
server.get("/resource/:resource/:id/:with_information?", async (req, reply) => { server.get("/resource/:resource/:id/:with_information?", async (req, reply) => {
if (!req.user?.tenant_id) { if (!req.user?.tenant_id) {
return reply.code(400).send({error: "No tenant selected"}); return reply.code(400).send({error: "No tenant selected"});
} }
const { resource, id, with_information } = req.params as { resource: string; id: string, with_information: boolean }; const {resource, id, with_information} = req.params as {
resource: string;
id: string,
with_information: boolean
};
const {select} = req.query as { select?: string } const {select} = req.query as { select?: string }
// @ts-ignore // @ts-ignore
const { data, error } = await server.supabase.from(resource).select(with_information ? dataTypes[resource].supabaseSelectWithInformation : (select ? select : "*")) const {
data,
error
} = await server.supabase.from(resource).select(with_information ? dataTypes[resource].supabaseSelectWithInformation : (select ? select : "*"))
.eq("id", id) .eq("id", id)
.eq("tenant", req.user.tenant_id) .eq("tenant", req.user.tenant_id)
.single(); .single();
@@ -601,7 +758,6 @@ export default async function resourceRoutes(server: FastifyInstance) {
const diffs = diffObjects(oldItem, newItem); const diffs = diffObjects(oldItem, newItem);
for (const d of diffs) { for (const d of diffs) {
await insertHistoryItem(server, { await insertHistoryItem(server, {
entity: resource, entity: resource,