Files
haex-hub-mirror/src/stores/passwords/items.ts
2025-07-04 12:22:41 +02:00

362 lines
9.8 KiB
TypeScript

import { eq, isNull } from 'drizzle-orm'
import {
haexPasswordsGroupItems,
haexPasswordsItemDetails,
haexPasswordsItemHistory,
haexPasswordsItemKeyValues,
type InsertHaexPasswordsItemDetails,
type InserthaexPasswordsItemKeyValues,
type SelectHaexPasswordsGroupItems,
type SelectHaexPasswordsGroups,
type SelectHaexPasswordsItemDetails,
type SelectHaexPasswordsItemKeyValues,
} from '~~/src-tauri/database/schemas/vault'
export const usePasswordItemStore = defineStore('passwordItemStore', () => {
const currentItemId = computed({
get: () =>
getSingleRouteParam(useRouter().currentRoute.value.params.itemId),
set: (entryId) => {
console.log('set entryId', entryId)
useRouter().currentRoute.value.params.entryId = entryId ?? ''
},
})
const currentItem = computedAsync(() => readAsync(currentItemId.value))
const items = ref<
{
haex_passwords_item_details: SelectHaexPasswordsItemDetails
haex_passwords_group_items: SelectHaexPasswordsGroupItems
}[]
>([])
const syncItemsAsync = async () => {
const { currentVault } = useVaultStore()
items.value = await currentVault.drizzle
.select()
.from(haexPasswordsItemDetails)
.innerJoin(
haexPasswordsGroupItems,
eq(haexPasswordsItemDetails.id, haexPasswordsGroupItems.itemId),
)
}
return {
currentItemId,
currentItem,
addAsync,
addKeyValueAsync,
addKeyValuesAsync,
deleteAsync,
deleteKeyValueAsync,
items,
readByGroupIdAsync,
readAsync,
readKeyValuesAsync,
syncItemsAsync,
updateAsync,
}
})
const addAsync = async (
details: SelectHaexPasswordsItemDetails,
keyValues: SelectHaexPasswordsItemKeyValues[],
group?: SelectHaexPasswordsGroups | null,
) => {
const { currentVault } = useVaultStore()
console.log('addItem', details, group)
const newDetails: InsertHaexPasswordsItemDetails = {
id: crypto.randomUUID(),
icon: details.icon || group?.icon || null,
note: details.note,
password: details.password,
tags: details.tags,
title: details.title,
url: details.url,
username: details.username,
}
const newKeyValues: InserthaexPasswordsItemKeyValues[] = keyValues.map(
(keyValue) => ({
id: crypto.randomUUID(),
itemId: newDetails.id,
key: keyValue.key,
value: keyValue.value,
}),
)
try {
await currentVault?.drizzle.transaction(async (tx) => {
await tx.insert(haexPasswordsItemDetails).values(newDetails)
await tx
.insert(haexPasswordsGroupItems)
.values({ itemId: newDetails.id, groupId: group?.id ?? null })
if (newKeyValues.length)
await tx.insert(haexPasswordsItemKeyValues).values(newKeyValues)
})
} catch (error) {
console.error('ERROR addItem', error)
}
return newDetails.id
}
const addKeyValueAsync = async (
item?: InserthaexPasswordsItemKeyValues | null,
itemId?: string,
) => {
const newKeyValue: InserthaexPasswordsItemKeyValues = {
id: crypto.randomUUID(),
itemId: item?.itemId || itemId,
key: item?.key,
value: item?.value,
}
try {
const { currentVault } = useVaultStore()
return await currentVault?.drizzle
.insert(haexPasswordsItemKeyValues)
.values(newKeyValue)
} catch (error) {
console.error('ERROR addItem', error)
}
}
const addKeyValuesAsync = async (
items: InserthaexPasswordsItemKeyValues[],
itemId?: string,
) => {
const { currentVault } = useVaultStore()
console.log('addKeyValues', items, itemId)
const newKeyValues: InserthaexPasswordsItemKeyValues[] = items?.map(
(item) => ({
id: crypto.randomUUID(),
itemId: item.itemId || itemId,
key: item.key,
value: item.value,
}),
)
try {
return await currentVault?.drizzle
.insert(haexPasswordsItemKeyValues)
.values(newKeyValues)
} catch (error) {
console.error('ERROR addItem', error)
}
}
const readByGroupIdAsync = async (groupId?: string | null) => {
try {
const { currentVault } = useVaultStore()
console.log('get entries by groupId', groupId || null)
if (groupId) {
const entries = await currentVault.drizzle
.select()
.from(haexPasswordsGroupItems)
.innerJoin(
haexPasswordsItemDetails,
eq(haexPasswordsItemDetails.id, haexPasswordsGroupItems.itemId),
)
.where(eq(haexPasswordsGroupItems.groupId, groupId))
console.log('found entries by groupId', entries)
return entries.map((entry) => entry.haex_passwords_item_details)
} else {
const entries = await currentVault.drizzle
.select()
.from(haexPasswordsGroupItems)
.innerJoin(
haexPasswordsItemDetails,
eq(haexPasswordsItemDetails.id, haexPasswordsGroupItems.itemId),
)
.where(isNull(haexPasswordsGroupItems.groupId))
console.log('found entries', entries)
return entries.map((entry) => entry.haex_passwords_item_details)
}
} catch (error) {
console.error(error)
return []
}
}
const readAsync = async (itemId: string | null) => {
if (!itemId) return null
try {
const { currentVault } = useVaultStore()
const details =
await currentVault.drizzle.query.haexPasswordsItemDetails.findFirst({
where: eq(haexPasswordsItemDetails.id, itemId),
})
console.log('readAsync details', details)
if (!details) return null
const history = (await usePasswordHistoryStore().getAsync(itemId)) ?? []
const keyValues = (await readKeyValuesAsync(itemId)) ?? []
console.log('found item by id', { details, history, keyValues })
return { details, history, keyValues }
} catch (error) {
console.error(error)
throw error
}
}
const readKeyValuesAsync = async (itemId: string | null) => {
if (!itemId) return null
const { currentVault } = useVaultStore()
const keyValues =
await currentVault.drizzle.query.haexPasswordsItemKeyValues.findMany({
where: eq(haexPasswordsGroupItems.itemId, itemId),
})
return keyValues
}
const updateAsync = async ({
details,
keyValues,
keyValuesAdd,
keyValuesDelete,
groupId,
}: {
details: SelectHaexPasswordsItemDetails
keyValues: SelectHaexPasswordsItemKeyValues[]
keyValuesAdd: SelectHaexPasswordsItemKeyValues[]
keyValuesDelete: SelectHaexPasswordsItemKeyValues[]
groupId: string | null
}) => {
const { currentVault } = useVaultStore()
if (!details.id) return
const newDetails: InsertHaexPasswordsItemDetails = {
id: details.id,
icon: details.icon,
note: details.note,
password: details.password,
tags: details.tags,
title: details.title,
url: details.url,
username: details.username,
}
const newKeyValues: InserthaexPasswordsItemKeyValues[] = keyValues
.map((keyValue) => ({
id: keyValue.id,
itemId: newDetails.id,
key: keyValue.key,
value: keyValue.value,
}))
.filter((keyValue) => keyValue.id)
const newKeyValuesAdd: InserthaexPasswordsItemKeyValues[] = keyValuesAdd.map(
(keyValue) => ({
id: keyValue.id || crypto.randomUUID(),
itemId: newDetails.id,
key: keyValue.key,
value: keyValue.value,
}),
)
console.log('update item', newDetails, newKeyValues, newKeyValuesAdd, groupId)
return await currentVault?.drizzle.transaction(async (tx) => {
await tx
.update(haexPasswordsItemDetails)
.set(newDetails)
.where(eq(haexPasswordsItemDetails.id, newDetails.id))
await tx
.update(haexPasswordsGroupItems)
.set({ itemId: newDetails.id, groupId })
.where(eq(haexPasswordsGroupItems.itemId, newDetails.id))
const promises = newKeyValues.map((keyValue) =>
tx
.update(haexPasswordsItemKeyValues)
.set(keyValue)
.where(eq(haexPasswordsItemKeyValues.id, keyValue.id)),
)
await Promise.all(promises)
if (newKeyValuesAdd.length)
await tx.insert(haexPasswordsItemKeyValues).values(newKeyValuesAdd)
const promisesDelete = keyValuesDelete.map((keyValue) =>
tx
.delete(haexPasswordsItemKeyValues)
.where(eq(haexPasswordsItemKeyValues.id, keyValue.id)),
)
await Promise.all(promisesDelete)
return newDetails.id
})
}
const deleteAsync = async (itemId: string, final: boolean = false) => {
const { currentVault } = useVaultStore()
const { createTrashIfNotExistsAsync, trashId } = usePasswordGroupStore()
console.log('deleteAsync', itemId, final)
if (final)
await currentVault?.drizzle.transaction(async (tx) => {
await tx
.delete(haexPasswordsItemKeyValues)
.where(eq(haexPasswordsItemKeyValues.itemId, itemId))
await tx
.delete(haexPasswordsItemHistory)
.where(eq(haexPasswordsItemHistory.itemId, itemId))
await tx
.delete(haexPasswordsGroupItems)
.where(eq(haexPasswordsGroupItems.itemId, itemId))
await tx
.delete(haexPasswordsItemDetails)
.where(eq(haexPasswordsItemDetails.id, itemId))
})
else {
if (await createTrashIfNotExistsAsync())
await currentVault.drizzle
.update(haexPasswordsGroupItems)
.set({ groupId: trashId })
.where(eq(haexPasswordsGroupItems.itemId, itemId))
}
}
const deleteKeyValueAsync = async (id: string) => {
console.log('deleteKeyValueAsync', id)
const { currentVault } = useVaultStore()
return await currentVault.drizzle
.delete(haexPasswordsItemKeyValues)
.where(eq(haexPasswordsItemKeyValues.id, id))
}
const areItemsEqual = (
groupA: unknown | unknown[] | null,
groupB: unknown | unknown[] | null,
) => {
if (groupA === null && groupB === null) return true
if (Array.isArray(groupA) && Array.isArray(groupB)) {
console.log('compare object arrays', groupA, groupB)
if (groupA.length === groupB.length) return true
return groupA.some((group, index) => {
return areObjectsEqual(group, groupA[index])
})
}
return areObjectsEqual(groupA, groupB)
}