Skip to content

Commit

Permalink
feat: delete base
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Aug 19, 2024
1 parent 723b8c4 commit 0e5f874
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 6 deletions.
60 changes: 58 additions & 2 deletions apps/frontend/src/lib/components/blocks/base/base-setting.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { toggleModal } from "$lib/store/modal.store"
import * as AlertDialog from "$lib/components/ui/alert-dialog/index.js"
import { trpc } from "$lib/trpc/client"
import { createMutation } from "@tanstack/svelte-query"
import type { IBaseDTO } from "@undb/base"
Expand All @@ -9,8 +9,13 @@
import * as Form from "$lib/components/ui/form"
import { Switch } from "$lib/components/ui/switch"
import Input from "$lib/components/ui/input/input.svelte"
import { hasPermission } from "$lib/store/space-member.store"
import { Button } from "$lib/components/ui/button"
import { toast } from "svelte-sonner"
import { goto, invalidateAll } from "$app/navigation"
export let base: Omit<IBaseDTO, "spaceId">
let deleteConfirm = ""
const updateBaseMutation = createMutation({
mutationKey: ["base", base.id, "updateBase"],
Expand Down Expand Up @@ -40,9 +45,18 @@
},
)
const { enhance, form: formData } = form
const deleteSpaceMutation = createMutation({
mutationFn: trpc.base.delete.mutate,
async onSuccess() {
toast.success("Base deleted successfully")
await invalidateAll()
goto("/")
},
})
</script>

<section>
<section class="space-y-6">
<form class="max-w-4xl space-y-4" method="POST" use:enhance>
<legend class="mb-4 text-lg font-medium"> Base Setting </legend>
<Form.Field {form} name="name" class="rounded-lg border p-4">
Expand Down Expand Up @@ -76,4 +90,46 @@

<Form.Button size="sm">Submit</Form.Button>
</form>

<div class="max-w-4xl space-y-3 rounded-md border-2 border-red-500 p-4">
<p class="text-red-500">Danger Zone</p>
<div>Delete Base</div>

<AlertDialog.Root>
<AlertDialog.Trigger asChild let:builder>
<Button variant="destructive" builders={[builder]} disabled={!$hasPermission("base:delete")}>
Delete Base
</Button>
</AlertDialog.Trigger>
<AlertDialog.Content>
<AlertDialog.Header>
<AlertDialog.Title>Are you absolutely sure to delete base?</AlertDialog.Title>
<AlertDialog.Description>
This action cannot be undone. This will permanently delete your database state and remove your data from our
servers.
</AlertDialog.Description>
</AlertDialog.Header>

<p>Please type <span class="text-red-500">DELETE</span> to confirm.</p>
<Input bind:value={deleteConfirm} placeholder="DELETE" />

<AlertDialog.Footer>
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
<AlertDialog.Action let:builder asChild>
<Button
variant="destructive"
builders={[builder]}
disabled={//
$deleteSpaceMutation.isPending || deleteConfirm !== "DELETE" || !$hasPermission("space:delete")}
on:click={async () => {
await $deleteSpaceMutation.mutateAsync({ id: base.id })
}}
>
Delete Base
</Button>
</AlertDialog.Action>
</AlertDialog.Footer>
</AlertDialog.Content>
</AlertDialog.Root>
</div>
</section>
8 changes: 8 additions & 0 deletions packages/base/src/dto/delete-base.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from "@undb/zod"
import { baseIdSchema } from "../value-objects"

export const deleteBaseDTO = z.object({
id: baseIdSchema,
})

export type IDeleteBaseDTO = z.infer<typeof deleteBaseDTO>
1 change: 1 addition & 0 deletions packages/base/src/dto/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./base.dto"
export * from "./create-base.dto"
export * from "./delete-base.dto"
export * from "./duplicate-base.dto"
export * from "./update-base.dto"
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { injectBaseRepository, type IBaseRepository } from "@undb/base"
import { DeleteBaseCommand } from "@undb/commands"
import { commandHandler } from "@undb/cqrs"
import { singleton } from "@undb/di"
import { type ICommandHandler } from "@undb/domain"

@commandHandler(DeleteBaseCommand)
@singleton()
export class DeleteBaseCommandHandler implements ICommandHandler<DeleteBaseCommand, any> {
constructor(
@injectBaseRepository()
private readonly repository: IBaseRepository,
) {}

async execute(command: DeleteBaseCommand): Promise<any> {
const base = (await this.repository.findOneById(command.id)).expect("base not found")

await this.repository.deleteOneById(base.id.value)

return base.id.value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export class DuplicateBaseCommandHandler implements ICommandHandler<DuplicateBas
async execute(command: DuplicateBaseCommand): Promise<any> {
const base = (await this.baseRepository.findOneById(command.id)).expect("Base not found")

const duplicatedBase = await this.tableService.duplicateBase(base, mustGetCurrentSpaceId(), command)
const spaceId = mustGetCurrentSpaceId()
const duplicatedBase = await this.tableService.duplicateBase(base, spaceId, spaceId, command)

return duplicatedBase.id.value
}
Expand Down
2 changes: 2 additions & 0 deletions packages/command-handlers/src/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CreateTableFormCommandHandler } from "./create-table-form.command-handl
import { CreateTableViewCommandHandler } from "./create-table-view.command-handler"
import { CreateTableCommandHandler } from "./create-table.command-handler"
import { CreateWebhookCommandHandler } from "./create-webhook.command-handler"
import { DeleteBaseCommandHandler } from "./delete-base.command-handler"
import { DeleteInvitationCommandHandler } from "./delete-invitation.command-handler"
import { DeleteRecordCommandHandler } from "./delete-record.command-handler"
import { DeleteSpaceCommandHandler } from "./delete-space.command-handler"
Expand Down Expand Up @@ -94,4 +95,5 @@ export const commandHandlers = [
DeleteWebhookCommandHandler,
DuplicateTableCommandHandler,
DuplicateBaseCommandHandler,
DeleteBaseCommandHandler,
]
16 changes: 16 additions & 0 deletions packages/commands/src/delete-base.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { deleteBaseDTO } from "@undb/base"
import { Command, type CommandProps } from "@undb/domain"
import { z } from "@undb/zod"

export const deleteBaseCommand = deleteBaseDTO

export type IDeleteBaseCommand = z.infer<typeof deleteBaseCommand>

export class DeleteBaseCommand extends Command implements IDeleteBaseCommand {
public readonly id: string

constructor(props: CommandProps<IDeleteBaseCommand>) {
super(props)
this.id = props.id
}
}
1 change: 1 addition & 0 deletions packages/commands/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export * from "./create-table-form.command"
export * from "./create-table-view.command"
export * from "./create-table.command"
export * from "./create-webhook.command"
export * from "./delete-base.command"
export * from "./delete-invitation.command"
export * from "./delete-record.command"
export * from "./delete-space.command"
Expand Down
42 changes: 39 additions & 3 deletions packages/persistence/src/base/base.repository.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
injectBaseOutboxService,
WithBaseId,
WithBaseSpaceId,
injectBaseOutboxService,
type Base,
type IBaseOutboxService,
type IBaseRepository,
Expand All @@ -10,9 +10,11 @@ import {
import { executionContext, mustGetCurrentSpaceId } from "@undb/context/server"
import { inject, singleton } from "@undb/di"
import { None, Some, type Option } from "@undb/domain"
import { injectTableRepository, TableBaseIdSpecification, type ITableRepository } from "@undb/table"
import { getCurrentTransaction } from "../ctx"
import type { IQueryBuilder } from "../qb"
import { injectQueryBuilder } from "../qb.provider"
import { UnderlyingTableService } from "../underlying/underlying-table.service"
import { BaseFilterVisitor } from "./base.filter-visitor"
import { BaseMapper } from "./base.mapper"
import { BaseMutateVisitor } from "./base.mutate-visitor"
Expand All @@ -26,6 +28,10 @@ export class BaseRepository implements IBaseRepository {
private readonly outboxService: IBaseOutboxService,
@injectQueryBuilder()
private readonly qb: IQueryBuilder,
@injectTableRepository()
private readonly tableRepository: ITableRepository,
@inject(UnderlyingTableService)
private readonly underlyingTableService: UnderlyingTableService,
) {}

async find(spec: IBaseSpecification): Promise<Base[]> {
Expand Down Expand Up @@ -101,7 +107,37 @@ export class BaseRepository implements IBaseRepository {
await this.outboxService.save(base)
}

deleteOneById(id: string): Promise<void> {
throw new Error("Method not implemented.")
async deleteOneById(id: string): Promise<void> {
const trx = getCurrentTransaction()

const tables = await this.tableRepository.find(Some(new TableBaseIdSpecification(id)))
const tableIds = tables.map((t) => t.id.value)

await trx
.deleteFrom("undb_table_id_mapping")
.where((eb) => eb.eb("table_id", "in", tableIds))
.execute()

await trx
.deleteFrom("undb_rollup_id_mapping")
.where((eb) => eb.eb("table_id", "in", tableIds))
.execute()

await trx
.deleteFrom("undb_reference_id_mapping")
.where((eb) => eb.eb("table_id", "in", tableIds))
.execute()

await trx
.deleteFrom("undb_table")
.where((eb) => eb.eb("id", "in", tableIds))
.execute()

await trx
.deleteFrom("undb_base")
.where((eb) => eb.eb("id", "=", id))
.execute()

await this.underlyingTableService.deleteTables(tables)
}
}
12 changes: 12 additions & 0 deletions packages/persistence/src/underlying/underlying-table.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createLogger } from "@undb/logger"
import type { TableComositeSpecification, TableDo } from "@undb/table"
import type { CompiledQuery } from "kysely"
import { getAnonymousTransaction, getCurrentTransaction } from "../ctx"
import { JoinTable } from "./reference/join-table"
import { UnderlyingTable } from "./underlying-table"
import { UnderlyingTableFieldVisitor } from "./underlying-table-field.visitor"
import { UnderlyingTableSpecVisitor } from "./underlying-table-spec.visitor"
Expand Down Expand Up @@ -46,5 +47,16 @@ export class UnderlyingTableService {
const t = new UnderlyingTable(table)
const trx = getCurrentTransaction()
await trx.schema.dropTable(t.name).execute()
const referenceFields = table.schema.getReferenceFields()
for (const field of referenceFields) {
const joinTable = new JoinTable(table, field)
await trx.schema.dropTable(joinTable.getTableName()).execute()
}
}

async deleteTables(tables: TableDo[]) {
for (const table of tables) {
await this.delete(table)
}
}
}
6 changes: 6 additions & 0 deletions packages/trpc/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
CreateTableFormCommand,
CreateTableViewCommand,
CreateWebhookCommand,
DeleteBaseCommand,
DeleteInvitationCommand,
DeleteRecordCommand,
DeleteTableCommand,
Expand Down Expand Up @@ -58,6 +59,7 @@ import {
createTableFormCommand,
createTableViewCommand,
createWebhookCommand,
deleteBaseCommand,
deleteInvitationCommand,
deleteRecordCommand,
deleteTableCommand,
Expand Down Expand Up @@ -322,6 +324,10 @@ const baseRouter = t.router({
.use(authz("base:update"))
.input(updateBaseCommand)
.mutation(({ input }) => commandBus.execute(new UpdateBaseCommand(input))),
delete: privateProcedure
.use(authz("base:delete"))
.input(deleteBaseCommand)
.mutation(({ input }) => commandBus.execute(new DeleteBaseCommand(input))),
})

const shareRouter = t.router({
Expand Down

0 comments on commit 0e5f874

Please sign in to comment.