Skip to content

Commit

Permalink
feat: duplicate table
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Aug 16, 2024
1 parent c2799cc commit 26695bc
Show file tree
Hide file tree
Showing 25 changed files with 315 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
import { Button } from "$lib/components/ui/button"
import * as Form from "$lib/components/ui/form"
import { Input } from "$lib/components/ui/input"
import { closeModal } from "$lib/store/modal.store"
import { getTable } from "$lib/store/table.store"
import { trpc } from "$lib/trpc/client"
import { createMutation, useQueryClient } from "@tanstack/svelte-query"
import { createFieldDTO, FieldIdVo, type FieldType } from "@undb/table"
import { createFieldDTO, type FieldType } from "@undb/table"
import { toast } from "svelte-sonner"
import { derived } from "svelte/store"
import SuperDebug, { defaults, superForm } from "sveltekit-superforms"
import { defaults, superForm } from "sveltekit-superforms"
import { zodClient } from "sveltekit-superforms/adapters"
import FieldOptions from "../field-options/field-options.svelte"
import FieldTypePicker from "../field-picker/field-type-picker.svelte"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<script lang="ts">
import { goto, invalidateAll } from "$app/navigation"
import Button from "$lib/components/ui/button/button.svelte"
import * as Dialog from "$lib/components/ui/dialog"
import { closeModal, DUPLICATE_TABLE_MODAL, isModalOpen } from "$lib/store/modal.store"
import { trpc } from "$lib/trpc/client"
import { createMutation } from "@tanstack/svelte-query"
import type { TableDo } from "@undb/table"
import { LoaderCircleIcon } from "lucide-svelte"
import { toast } from "svelte-sonner"
export let table: TableDo
const duplicateTableMutation = createMutation({
mutationFn: trpc.table.duplicate.mutate,
onSuccess: async (data) => {
await invalidateAll()
closeModal(DUPLICATE_TABLE_MODAL)
await goto(`/t/${data}`)
},
onError: (error) => {
toast.error(error.message)
},
})
</script>

<Dialog.Root
open={$isModalOpen(DUPLICATE_TABLE_MODAL)}
onOpenChange={(open) => {
if (!open) {
closeModal(DUPLICATE_TABLE_MODAL)
}
}}
>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Duplicate Table {table.name.value}</Dialog.Title>
<Dialog.Description>
Create a new table with the same structure as {table.name.value}
</Dialog.Description>
</Dialog.Header>

<div class="item-center flex justify-end gap-2">
<Button
on:click={() => {
closeModal(DUPLICATE_TABLE_MODAL)
}}
variant="outline"
>
Cancel
</Button>
<Button
disabled={$duplicateTableMutation.isPending}
on:click={() => {
$duplicateTableMutation.mutate({ tableId: table.id.value })
}}
>
{#if $duplicateTableMutation.isPending}
<LoaderCircleIcon class="mr-2 h-5 w-5 animate-spin" />
{/if}
Duplicate
</Button>
</div>
</Dialog.Content>
</Dialog.Root>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
FileJsonIcon,
FileTextIcon,
FileSpreadsheet,
TrashIcon,
CopyIcon,
} from "lucide-svelte"
import * as Breadcrumb from "$lib/components/ui/breadcrumb/index.js"
import { getTable } from "$lib/store/table.store"
Expand All @@ -32,13 +34,15 @@
import {
DELETE_TABLE_MODAL,
DELETE_VIEW,
DUPLICATE_TABLE_MODAL,
DUPLICATE_VIEW,
UPDATE_TABLE_MODAL,
UPDATE_VIEW,
toggleModal,
} from "$lib/store/modal.store"
import { getBaseById } from "$lib/store/base.store"
import { hasPermission } from "$lib/store/space-member.store"
import DuplicateTable from "../duplicate-table/duplicate-table.svelte"
const table = getTable()
$: base = $getBaseById($table.baseId)
Expand Down Expand Up @@ -94,12 +98,18 @@
Update table name
</DropdownMenu.Item>
{/if}
{#if $hasPermission("table:create")}
<DropdownMenu.Item class="text-xs" on:click={() => toggleModal(DUPLICATE_TABLE_MODAL)}>
<CopyIcon class="mr-2 h-3 w-3" />
Duplicate Table
</DropdownMenu.Item>
{/if}
{#if $hasPermission("table:delete")}
<DropdownMenu.Item
on:click={() => toggleModal(DELETE_TABLE_MODAL)}
class="text-xs text-red-500 hover:bg-red-50 hover:text-red-500"
>
<PencilIcon class="mr-2 h-3 w-3" />
<TrashIcon class="mr-2 h-3 w-3" />
Delete table
</DropdownMenu.Item>
{/if}
Expand Down Expand Up @@ -268,3 +278,5 @@
</Tabs.Root>
</div>
</header>

<DuplicateTable table={$table} />
2 changes: 2 additions & 0 deletions apps/frontend/src/lib/store/modal.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const modal = queryParam("modal", ssp.array<string>())

export const CREATE_TABLE_MODAL = "createTable" as const
export const UPDATE_TABLE_MODAL = "updateTable" as const
export const DUPLICATE_TABLE_MODAL = "duplicateTable" as const
export const IMPORT_TABLE_MODAL = "importTable" as const
export const CREATE_RECORD_MODAL = "createRecord" as const
export const DELETE_RECORD_MODAL = "deleteRecord" as const
Expand All @@ -23,6 +24,7 @@ type ModalType =
| typeof CREATE_TABLE_MODAL
| typeof UPDATE_TABLE_MODAL
| typeof IMPORT_TABLE_MODAL
| typeof DUPLICATE_TABLE_MODAL
| typeof DELETE_RECORD_MODAL
| typeof DUPLICATE_RECORD_MODAL
| typeof CREATE_RECORD_MODAL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { DuplicateTableCommand } from "@undb/commands"
import { commandHandler } from "@undb/cqrs"
import { singleton } from "@undb/di"
import type { ICommandHandler } from "@undb/domain"
import { injectTableService, type ITableService } from "@undb/table"

@commandHandler(DuplicateTableCommand)
@singleton()
export class DuplicateTableCommandHandler implements ICommandHandler<DuplicateTableCommand, any> {
constructor(
@injectTableService()
private readonly service: ITableService,
) {}

async execute(command: DuplicateTableCommand): Promise<any> {
const table = await this.service.duplicateTable(command.input)

return table.id.value
}
}
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 @@ -22,6 +22,7 @@ import { DeleteWebhookCommandHandler } from "./delete-webhook.command-handler"
import { DisableShareCommandHandler } from "./disable-share.command-handler"
import { DuplicateRecordCommandHandler } from "./duplicate-record.command-handler"
import { DuplicateTableFieldCommandHandler } from "./duplicate-table-field.command-handler"
import { DuplicateTableCommandHandler } from "./duplicate-table.command-handler"
import { DuplicateViewCommandHandler } from "./duplicate-view.command-handler"
import { EnableShareCommandHandler } from "./enable-share.command-handler"
import { ExportViewCommandHandler } from "./export-view.command-handler"
Expand Down Expand Up @@ -88,4 +89,5 @@ export const commandHandlers = [
UpdateSpaceCommandHandler,
DeleteSpaceCommandHandler,
DeleteWebhookCommandHandler,
DuplicateTableCommandHandler,
]
16 changes: 16 additions & 0 deletions packages/commands/src/duplicate-table.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Command, type CommandProps } from "@undb/domain"
import { duplicateTableDTO, type IDuplicateTableDTO } from "@undb/table"
import { z } from "@undb/zod"

export const duplicateTableCommand = duplicateTableDTO

export type IDuplicateTableCommand = z.infer<typeof duplicateTableCommand>

export class DuplicateTableCommand extends Command {
public readonly input: IDuplicateTableDTO

constructor(props: CommandProps<IDuplicateTableDTO>) {
super(props)
this.input = props
}
}
1 change: 1 addition & 0 deletions packages/commands/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from "./delete-webhook.command"
export * from "./disable-share.command"
export * from "./duplicate-record.command"
export * from "./duplicate-table-field.command"
export * from "./duplicate-table.command"
export * from "./duplicate-view.command"
export * from "./enable-share.command"
export * from "./export-view.command"
Expand Down
4 changes: 4 additions & 0 deletions packages/persistence/src/table/table.filter-visitor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { mustGetCurrentSpaceId } from "@undb/context/server"
import type {
DuplicatedTableSpecification,
ITableSpecVisitor,
TableBaseIdSpecification,
TableDo,
Expand Down Expand Up @@ -66,6 +67,9 @@ export class TableFilterVisitor extends AbstractQBVisitor<TableDo> implements IT
),
)
}
withDuplicatedTable(spec: DuplicatedTableSpecification): void {
throw new Error("Method not implemented.")
}
withName(name: TableNameSpecification): void {
this.addCond(this.eb.eb("name", "=", name.name.value))
}
Expand Down
2 changes: 2 additions & 0 deletions packages/persistence/src/table/table.mutation-visitor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
DuplicatedTableSpecification,
ITableSpecVisitor,
TableBaseIdSpecification,
TableDo,
Expand Down Expand Up @@ -108,6 +109,7 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I
withDuplicateField(schema: WithDuplicatedFieldSpecification): void {
// throw new Error("Method not implemented.")
}
withDuplicatedTable(spec: DuplicatedTableSpecification): void {}
withoutField(schema: WithoutFieldSpecification): void {
this.setData(tables.schema.name, json(this.table.schema.toJSON()))

Expand Down
2 changes: 2 additions & 0 deletions packages/persistence/src/table/table.reference-visitor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ISpecification } from "@undb/domain"
import type {
DuplicatedTableSpecification,
ITableSpecVisitor,
TableBaseIdSpecification,
TableComositeSpecification,
Expand Down Expand Up @@ -82,6 +83,7 @@ export class TableReferenceVisitor implements ITableSpecVisitor {
eb.and([eb.eb("undb_base.name", "=", spec.baseName), eb.eb("undb_table.name", "=", spec.tableName)]),
)
}
withDuplicatedTable(spec: DuplicatedTableSpecification): void {}
and(left: ISpecification, right: ISpecification): this {
left.accept(this)
right.accept(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export class JoinTable {
getTableName() {
const { field } = this
const { isOwner, foreignTableId } = field
return `$${isOwner ? foreignTableId : this.table.id.value}_${isOwner ? field.id.value : field.symmetricFieldId!}_join_table`
return `$${isOwner ? foreignTableId : this.table.id.value}_${isOwner ? this.table.id.value + "_" + field.id.value : field.foreignTableId + "_" + field.symmetricFieldId!}_join_table`
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,19 @@ export class UnderlyingTableFieldVisitor<TB extends CreateTableBuilder<any, any>
}
reference(field: ReferenceField): void {
const joinTable = new JoinTable(this.t.table, field)
const option = field.option.expect("expect reference option")

const isOwner = option.isOwner

if (isOwner) {
const sql = this.qb.schema
.createTable(joinTable.getTableName())
.ifNotExists()
.addColumn(joinTable.getSymmetricValueFieldId(), "varchar(10)", (b) =>
b.references(`${field.foreignTableId}.${ID_TYPE}`).notNull().onDelete("cascade"),
)
.addColumn(joinTable.getValueFieldId(), "varchar(10)", (b) =>
b.references(`${this.t.table.id.value}.${ID_TYPE}`).notNull().onDelete("cascade"),
)
.addPrimaryKeyConstraint("primary_key", [joinTable.getSymmetricValueFieldId(), joinTable.getValueFieldId()])
.compile()
this.addSql(sql)
}
const sql = this.qb.schema
.createTable(joinTable.getTableName())
.ifNotExists()
.addColumn(joinTable.getSymmetricValueFieldId(), "varchar(10)", (b) =>
b.references(`${field.foreignTableId}.${ID_TYPE}`).notNull().onDelete("cascade"),
)
.addColumn(joinTable.getValueFieldId(), "varchar(10)", (b) =>
b.references(`${this.t.table.id.value}.${ID_TYPE}`).notNull().onDelete("cascade"),
)
.addPrimaryKeyConstraint("primary_key", [joinTable.getSymmetricValueFieldId(), joinTable.getValueFieldId()])
.compile()
this.addSql(sql)
}
rollup(field: RollupField): void {}
checkbox(field: CheckboxField): void {
Expand Down
Loading

0 comments on commit 26695bc

Please sign in to comment.