wip: libsql migration

This commit is contained in:
Meier Lukas committed 2025-12-19 22:11:35 +01:00
1 parent 2ea0437a97
commit 8889537ff8
19 files changed
+255 -465

No files matched your search

+10 -8
View File
@@ -5,7 +5,7 @@ import { createId } from "@homarr/common";
import { asc, eq, inArray, like } from "@homarr/db";
import { apps } from "@homarr/db/schema";
import { selectAppSchema } from "@homarr/db/validationSchemas";
import { getIconForName } from "@homarr/icons";
import { getIconForNameAsync } from "@homarr/icons";
import { appCreateManySchema, appEditSchema, appManageSchema } from "@homarr/validation/app";
import { byIdSchema, paginatedSchema } from "@homarr/validation/common";
@@ -141,13 +141,15 @@ export const appRouter = createTRPCRouter({
.output(z.void())
.mutation(async ({ ctx, input }) => {
await ctx.db.insert(apps).values(
input.map((app) => ({
id: createId(),
name: app.name,
description: app.description,
iconUrl: app.iconUrl ?? getIconForName(ctx.db, app.name).sync()?.url ?? defaultIcon,
href: app.href,
})),
await Promise.all(
input.map(async (app) => ({
id: createId(),
name: app.name,
description: app.description,
iconUrl: app.iconUrl ?? (await getIconForNameAsync(ctx.db, app.name))?.url ?? defaultIcon,
href: app.href,
})),
),
);
}),
update: permissionRequiredProcedure
-287
View File
@@ -477,47 +477,6 @@ export const boardRouter = createTRPCRouter({
}
});
},
handleSync(db) {
db.transaction((transaction) => {
transaction
.insert(boards)
.values({
...boardProps,
id: newBoardId,
name: input.name,
creatorId: ctx.session.user.id,
})
.run();
if (layoutsToInsert.length > 0) {
transaction.insert(layouts).values(layoutsToInsert).run();
}
if (sectionsToInsert.length > 0) {
transaction.insert(sections).values(sectionsToInsert).run();
}
if (sectionLayoutsToInsert.length > 0) {
transaction.insert(sectionLayouts).values(sectionLayoutsToInsert).run();
}
if (sectionCollapseStatesToInsert.length > 0) {
transaction.insert(sectionCollapseStates).values(sectionCollapseStatesToInsert).run();
}
if (itemsToInsert.length > 0) {
transaction.insert(items).values(itemsToInsert).run();
}
if (itemLayoutsToInsert.length > 0) {
transaction.insert(itemLayouts).values(itemLayoutsToInsert).run();
}
if (itemIntegrationsToInsert.length > 0) {
transaction.insert(integrationItems).values(itemIntegrationsToInsert).run();
}
});
},
});
}),
renameBoard: protectedProcedure.input(boardRenameSchema).mutation(async ({ ctx, input }) => {
@@ -954,216 +913,6 @@ export const boardRouter = createTRPCRouter({
}
});
},
handleSync(db) {
db.transaction((transaction) => {
const addedSections = filterAddedItems(input.sections, dbBoard.sections);
if (addedSections.length > 0) {
transaction
.insert(sections)
.values(
addedSections.map((section) => ({
id: section.id,
kind: section.kind,
yOffset: section.kind !== "dynamic" ? section.yOffset : null,
xOffset: section.kind === "dynamic" ? null : 0,
options: section.kind === "dynamic" ? superjson.stringify(section.options) : emptySuperJSON,
name: "name" in section ? section.name : null,
boardId: dbBoard.id,
})),
)
.run();
if (addedSections.some((section) => section.kind === "dynamic")) {
transaction
.insert(sectionLayouts)
.values(
addedSections
.filter((section) => section.kind === "dynamic")
.flatMap((section) =>
section.layouts.map(
(sectionLayout): InferInsertModel<typeof sectionLayouts> => ({
layoutId: sectionLayout.layoutId,
sectionId: section.id,
parentSectionId: sectionLayout.parentSectionId,
height: sectionLayout.height,
width: sectionLayout.width,
xOffset: sectionLayout.xOffset,
yOffset: sectionLayout.yOffset,
}),
),
),
)
.run();
}
}
const addedItems = filterAddedItems(input.items, dbBoard.items);
if (addedItems.length > 0) {
transaction
.insert(items)
.values(
addedItems.map((item) => ({
id: item.id,
kind: item.kind,
options: superjson.stringify(item.options),
advancedOptions: superjson.stringify(item.advancedOptions),
boardId: dbBoard.id,
})),
)
.run();
transaction
.insert(itemLayouts)
.values(
addedItems.flatMap((item) =>
item.layouts.map(
(layoutSection): InferInsertModel<typeof itemLayouts> => ({
layoutId: layoutSection.layoutId,
sectionId: layoutSection.sectionId,
itemId: item.id,
height: layoutSection.height,
width: layoutSection.width,
xOffset: layoutSection.xOffset,
yOffset: layoutSection.yOffset,
}),
),
),
)
.run();
}
const inputIntegrationRelations = input.items.flatMap(({ integrationIds, id: itemId }) =>
integrationIds.map((integrationId) => ({
integrationId,
itemId,
})),
);
const dbIntegrationRelations = dbBoard.items.flatMap(({ integrationIds, id: itemId }) =>
integrationIds.map((integrationId) => ({
integrationId,
itemId,
})),
);
const addedIntegrationRelations = inputIntegrationRelations.filter(
(inputRelation) =>
!dbIntegrationRelations.some(
(dbRelation) =>
dbRelation.itemId === inputRelation.itemId &&
dbRelation.integrationId === inputRelation.integrationId,
),
);
if (addedIntegrationRelations.length > 0) {
transaction
.insert(integrationItems)
.values(
addedIntegrationRelations.map((relation) => ({
itemId: relation.itemId,
integrationId: relation.integrationId,
})),
)
.run();
}
const updatedItems = filterUpdatedItems(input.items, dbBoard.items);
for (const item of updatedItems) {
transaction
.update(items)
.set({
kind: item.kind,
options: superjson.stringify(item.options),
advancedOptions: superjson.stringify(item.advancedOptions),
})
.where(eq(items.id, item.id))
.run();
for (const itemSectionLayout of item.layouts) {
transaction
.update(itemLayouts)
.set({
height: itemSectionLayout.height,
width: itemSectionLayout.width,
xOffset: itemSectionLayout.xOffset,
yOffset: itemSectionLayout.yOffset,
sectionId: itemSectionLayout.sectionId,
})
.where(and(eq(itemLayouts.itemId, item.id), eq(itemLayouts.layoutId, itemSectionLayout.layoutId)))
.run();
}
}
const updatedSections = filterUpdatedItems(input.sections, dbBoard.sections);
for (const section of updatedSections) {
const prev = dbBoard.sections.find((dbSection) => dbSection.id === section.id);
transaction
.update(sections)
.set({
yOffset: prev?.kind !== "dynamic" && "yOffset" in section ? section.yOffset : null,
xOffset: prev?.kind !== "dynamic" && "yOffset" in section ? 0 : null,
options: section.kind === "dynamic" ? superjson.stringify(section.options) : emptySuperJSON,
name: prev?.kind === "category" && "name" in section ? section.name : null,
})
.where(eq(sections.id, section.id))
.run();
if (section.kind !== "dynamic") continue;
for (const sectionLayout of section.layouts) {
transaction
.update(sectionLayouts)
.set({
height: sectionLayout.height,
width: sectionLayout.width,
xOffset: sectionLayout.xOffset,
yOffset: sectionLayout.yOffset,
parentSectionId: sectionLayout.parentSectionId,
})
.where(
and(eq(sectionLayouts.sectionId, section.id), eq(sectionLayouts.layoutId, sectionLayout.layoutId)),
)
.run();
}
}
const removedIntegrationRelations = dbIntegrationRelations.filter(
(dbRelation) =>
!inputIntegrationRelations.some(
(inputRelation) =>
dbRelation.itemId === inputRelation.itemId &&
dbRelation.integrationId === inputRelation.integrationId,
),
);
for (const relation of removedIntegrationRelations) {
transaction
.delete(integrationItems)
.where(
and(
eq(integrationItems.itemId, relation.itemId),
eq(integrationItems.integrationId, relation.integrationId),
),
)
.run();
}
const removedItems = filterRemovedItems(input.items, dbBoard.items);
const itemIds = removedItems.map((item) => item.id);
if (itemIds.length > 0) {
transaction.delete(items).where(inArray(items.id, itemIds)).run();
}
const removedSections = filterRemovedItems(input.sections, dbBoard.sections);
const sectionIds = removedSections.map((section) => section.id);
if (sectionIds.length > 0) {
transaction.delete(sections).where(inArray(sections.id, sectionIds)).run();
}
});
},
});
}),
getBoardPermissions: protectedProcedure.input(byIdSchema).query(async ({ input, ctx }) => {
@@ -1256,24 +1005,6 @@ export const boardRouter = createTRPCRouter({
);
});
},
handleSync(db) {
db.transaction((transaction) => {
transaction.delete(boardUserPermissions).where(eq(boardUserPermissions.boardId, input.entityId)).run();
if (input.permissions.length === 0) {
return;
}
transaction
.insert(boardUserPermissions)
.values(
input.permissions.map((permission) => ({
userId: permission.principalId,
permission: permission.permission,
boardId: input.entityId,
})),
)
.run();
});
},
});
}),
saveGroupBoardPermissions: protectedProcedure.input(boardSavePermissionsSchema).mutation(async ({ input, ctx }) => {
@@ -1297,24 +1028,6 @@ export const boardRouter = createTRPCRouter({
);
});
},
handleSync(db) {
db.transaction((transaction) => {
transaction.delete(boardGroupPermissions).where(eq(boardGroupPermissions.boardId, input.entityId)).run();
if (input.permissions.length === 0) {
return;
}
transaction
.insert(boardGroupPermissions)
.values(
input.permissions.map((permission) => ({
groupId: permission.principalId,
permission: permission.permission,
boardId: input.entityId,
})),
)
.run();
});
},
});
}),
importOldmarrConfig: permissionRequiredProcedure
@@ -91,7 +91,7 @@ export const certificateRouter = createTRPCRouter({
hostname: input.hostname,
thumbprint: input.thumbprint,
});
const dbResult = await ctx.db
await ctx.db
.delete(trustedCertificateHostnames)
.where(
and(
@@ -103,7 +103,6 @@ export const certificateRouter = createTRPCRouter({
logger.info("Removed trusted hostname", {
hostname: input.hostname,
thumbprint: input.thumbprint,
count: dbResult.changes,
});
}),
removeCertificate: permissionRequiredProcedure
-7
View File
@@ -260,13 +260,6 @@ export const groupRouter = createTRPCRouter({
}
});
},
handleSync: (db) => {
db.transaction((trx) => {
for (const { id, position } of positions) {
trx.update(groups).set({ position }).where(eq(groups.id, id)).run();
}
});
},
});
}),
savePermissions: permissionRequiredProcedure
@@ -541,27 +541,6 @@ export const integrationRouter = createTRPCRouter({
);
});
},
handleSync(db) {
db.transaction((transaction) => {
transaction
.delete(integrationUserPermissions)
.where(eq(integrationUserPermissions.integrationId, input.entityId))
.run();
if (input.permissions.length === 0) {
return;
}
transaction
.insert(integrationUserPermissions)
.values(
input.permissions.map((permission) => ({
userId: permission.principalId,
permission: permission.permission,
integrationId: input.entityId,
})),
)
.run();
});
},
});
}),
saveGroupIntegrationPermissions: protectedProcedure
@@ -587,27 +566,6 @@ export const integrationRouter = createTRPCRouter({
);
});
},
handleSync(db) {
db.transaction((transaction) => {
transaction
.delete(integrationGroupPermissions)
.where(eq(integrationGroupPermissions.integrationId, input.entityId))
.run();
if (input.permissions.length === 0) {
return;
}
transaction
.insert(integrationGroupPermissions)
.values(
input.permissions.map((permission) => ({
groupId: permission.principalId,
permission: permission.permission,
integrationId: input.entityId,
})),
)
.run();
});
},
});
}),
searchInIntegration: protectedProcedure