mirror of
https://github.com/ajnart/homarr.git
synced 2026-01-20 06:22:15 +01:00
✨ Add reusable db queries
This commit is contained in:
@@ -13,6 +13,11 @@ export const getWidgetsForSectionsAsync = async (sectionIds: string[]) => {
|
||||
return await db.query.widgets.findMany({
|
||||
with: {
|
||||
options: true,
|
||||
integrations: {
|
||||
with: {
|
||||
integration: true,
|
||||
},
|
||||
},
|
||||
item: {
|
||||
with: {
|
||||
layouts: {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { IconKey, IconPassword, IconUser, TablerIconsProps } from '@tabler/icons-react';
|
||||
import { objectEntries, objectKeys } from '~/tools/object';
|
||||
import widgets from '~/widgets';
|
||||
|
||||
import { objectEntries, objectKeys } from '../../tools/object';
|
||||
|
||||
type IntegrationTypeDefinition = {
|
||||
secrets: IntegrationSecretKey[];
|
||||
iconUrl: string;
|
||||
@@ -48,6 +49,14 @@ export const widgetOptionTypes = [
|
||||
'array',
|
||||
'null',
|
||||
] as const;
|
||||
export const boardBackgroundImageAttachmentTypes = ['fixed', 'scroll'] as const;
|
||||
export const boardBackgroundImageRepeatTypes = [
|
||||
'repeat',
|
||||
'repeat-x',
|
||||
'repeat-y',
|
||||
'no-repeat',
|
||||
] as const;
|
||||
export const boardBackgroundImageSizeTypes = ['cover', 'contain'] as const;
|
||||
export const appNamePositions = ['right', 'left', 'top', 'bottom'] as const;
|
||||
export const appNameStyles = ['normal', 'hide', 'hover'] as const;
|
||||
export const statusCodeTypes = [
|
||||
@@ -159,6 +168,10 @@ export type IntegrationSecretVisibility = (typeof integrationSecretVisibility)[n
|
||||
export type IntegrationSecretKey = keyof typeof integrationSecrets;
|
||||
export type WidgetSort = (typeof widgetSorts)[number];
|
||||
export type WidgetOptionType = (typeof widgetOptionTypes)[number];
|
||||
export type BoardBackgroundImageAttachmentType =
|
||||
(typeof boardBackgroundImageAttachmentTypes)[number];
|
||||
export type BoardBackgroundImageRepeatType = (typeof boardBackgroundImageRepeatTypes)[number];
|
||||
export type BoardBackgroundImageSizeType = (typeof boardBackgroundImageSizeTypes)[number];
|
||||
export type AppNamePosition = (typeof appNamePositions)[number];
|
||||
export type AppNameStyle = (typeof appNameStyles)[number];
|
||||
export type StatusCodeType = (typeof statusCodeTypes)[number];
|
||||
|
||||
31
src/server/db/queries/app.ts
Normal file
31
src/server/db/queries/app.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { User } from 'next-auth';
|
||||
|
||||
import { db } from '..';
|
||||
import { boards, items } from '../schema';
|
||||
|
||||
export const getAppAsync = async (boardId: string, id: string, user: User | null | undefined) => {
|
||||
return await db.query.items.findFirst({
|
||||
where: and(
|
||||
eq(items.boardId, boardId),
|
||||
eq(items.id, id),
|
||||
user ? undefined : eq(boards.allowGuests, true)
|
||||
),
|
||||
with: {
|
||||
app: {
|
||||
with: {
|
||||
statusCodes: {
|
||||
columns: {
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
board: {
|
||||
columns: {
|
||||
allowGuests: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
67
src/server/db/queries/integrations.ts
Normal file
67
src/server/db/queries/integrations.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { and, eq, inArray } from 'drizzle-orm';
|
||||
import { User } from 'next-auth';
|
||||
|
||||
import { db } from '..';
|
||||
import { IntegrationSecretKey, IntegrationType } from '../items';
|
||||
import { boards, integrations, items } from '../schema';
|
||||
|
||||
export async function getIntegrations<TIntegrations extends IntegrationType>(
|
||||
boardId: string,
|
||||
sorts: TIntegrations[],
|
||||
user: User | null | undefined
|
||||
) {
|
||||
return await getIntegrationsForWidget(boardId, sorts, user, 'ignore');
|
||||
}
|
||||
|
||||
export const getIntegrationsForWidget = async <TIntegrations extends IntegrationType>(
|
||||
boardId: string,
|
||||
sorts: TIntegrations[],
|
||||
|
||||
user: User | null | undefined,
|
||||
widgetId: 'ignore' | (string & {})
|
||||
) => {
|
||||
const widgetItems = await db.query.items.findMany({
|
||||
where: and(
|
||||
eq(items.boardId, boardId),
|
||||
user ? undefined : eq(boards.allowGuests, true),
|
||||
sorts.length >= 1 ? inArray(integrations.sort, sorts) : undefined,
|
||||
widgetId !== 'ignore' ? eq(items.id, widgetId) : undefined
|
||||
),
|
||||
with: {
|
||||
widget: {
|
||||
with: {
|
||||
integrations: {
|
||||
with: {
|
||||
integration: {
|
||||
with: {
|
||||
secrets: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return widgetItems
|
||||
.flatMap((x) => x.widget?.integrations ?? [])
|
||||
.map((x) => ({ ...x.integration, sort: x.integration.sort as TIntegrations }));
|
||||
};
|
||||
|
||||
export async function getIntegrationAsync(integrationId: string) {
|
||||
return await db.query.integrations.findFirst({
|
||||
where: eq(integrations.id, integrationId),
|
||||
with: {
|
||||
secrets: true,
|
||||
widgets: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function getSecret(
|
||||
integration: Awaited<ReturnType<typeof getIntegrations>>[number],
|
||||
key: IntegrationSecretKey
|
||||
) {
|
||||
return integration.secrets.find((s) => s.key === key)?.value ?? '';
|
||||
}
|
||||
71
src/server/db/queries/widget.ts
Normal file
71
src/server/db/queries/widget.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { User } from 'next-auth';
|
||||
import { mapWidgetOptions } from '~/server/api/routers/board/mapping/options';
|
||||
import { objectEntries } from '~/tools/object';
|
||||
import widgetDefinitions from '~/widgets';
|
||||
import { InferWidgetOptions } from '~/widgets/widgets';
|
||||
|
||||
import { db } from '..';
|
||||
import { boards, items, widgets } from '../schema';
|
||||
|
||||
export const getWidgetAsync = async <TSort extends keyof typeof widgetDefinitions>(
|
||||
boardId: string,
|
||||
id: string,
|
||||
user: User | null | undefined,
|
||||
sort: TSort
|
||||
) => {
|
||||
const widgetItem = await db.query.items.findFirst({
|
||||
where: and(
|
||||
eq(items.boardId, boardId),
|
||||
eq(items.id, id),
|
||||
user ? undefined : eq(boards.allowGuests, true),
|
||||
eq(widgets.sort, sort)
|
||||
),
|
||||
with: {
|
||||
widget: {
|
||||
with: {
|
||||
integrations: {
|
||||
with: {
|
||||
integration: {
|
||||
with: {
|
||||
secrets: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: true,
|
||||
},
|
||||
},
|
||||
board: {
|
||||
columns: {
|
||||
allowGuests: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!widgetItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const mappedOptions = mapWidgetOptions(
|
||||
widgetItem.widget!.options.sort((a, b) => a.path.localeCompare(b.path))
|
||||
);
|
||||
objectEntries(widgetDefinitions[sort].options).forEach(([key, definition]) => {
|
||||
mappedOptions[key] = mappedOptions[key] ?? definition.defaultValue;
|
||||
});
|
||||
|
||||
return {
|
||||
id: widgetItem.id,
|
||||
sort: widgetItem.widget!.sort,
|
||||
options: mappedOptions as InferWidgetOptions<(typeof widgetDefinitions)[TSort]>,
|
||||
integrations: widgetItem.widget!.integrations.map((i) => ({
|
||||
...i.integration,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
export type WidgetIntegration = Exclude<
|
||||
Awaited<ReturnType<typeof getWidgetAsync>>,
|
||||
null
|
||||
>['integrations'][number];
|
||||
Reference in New Issue
Block a user