Skip to content

Commit

Permalink
feat: create from template
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Sep 21, 2024
1 parent 919ad55 commit b106abf
Show file tree
Hide file tree
Showing 21 changed files with 223 additions and 40 deletions.
25 changes: 25 additions & 0 deletions apps/frontend/src/lib/components/blocks/nav/nav-tools.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,24 @@
import SpaceDropdown from "../space/space-dropdown.svelte"
import type { ISpaceDTO } from "@undb/space"
import { preferences } from "$lib/store/persisted.store"
import { createMutation } from "@tanstack/svelte-query"
import { trpc } from "$lib/trpc/client"
import { toast } from "svelte-sonner"
import { goto, invalidateAll } from "$app/navigation"
export let space: ISpaceDTO | undefined | null
export let me: any
const createFromTemplateMutation = createMutation({
mutationFn: trpc.template.createFromTemplate.mutate,
onSuccess: async (data) => {
await invalidateAll()
toast.success("Base created successfully")
if (data.baseIds.length > 0) {
goto(`/bases/${data.baseIds[0]}`)
}
},
})
</script>

<div class="w-full space-y-1">
Expand Down Expand Up @@ -67,5 +82,15 @@
<PlusIcon class="mr-2 h-3 w-3" />
Create New Base
</Button>

<!-- <Button
class="w-full justify-start text-left"
on:click={() => $createFromTemplateMutation.mutate({ templateName: "test" })}
variant="link"
size="sm"
>
<PlusIcon class="mr-2 h-3 w-3" />
Create New Base
</Button> -->
{/if}
</div>
1 change: 1 addition & 0 deletions packages/command-handlers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@undb/cqrs": "workspace:*",
"@undb/di": "workspace:*",
"@undb/logger": "workspace:*",
"@undb/template": "workspace:*",
"@undb/openapi": "workspace:*",
"@undb/user": "workspace:*",
"ts-pattern": "^5.3.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { CreateFromTemplateCommand, type ICreateFromTemplateCommandOutput } from "@undb/commands"
import { mustGetCurrentSpaceId } from "@undb/context/server"
import { commandHandler } from "@undb/cqrs"
import { singleton } from "@undb/di"
import { type ICommandHandler } from "@undb/domain"
import { createLogger } from "@undb/logger"
import { injectTemplateService, type ITemplateService, templates } from "@undb/template"

@commandHandler(CreateFromTemplateCommand)
@singleton()
export class CreateFromTemplateCommandHandler
implements ICommandHandler<CreateFromTemplateCommand, ICreateFromTemplateCommandOutput>
{
private readonly logger = createLogger(CreateFromTemplateCommandHandler.name)

constructor(
@injectTemplateService()
private readonly templateService: ITemplateService,
) {}

async execute(command: CreateFromTemplateCommand): Promise<ICreateFromTemplateCommandOutput> {
this.logger.info(`create from template command received: ${command.templateName}`)

const template = templates["test"]

const spaceId = mustGetCurrentSpaceId()
const result = await this.templateService.createBase(template, spaceId)

return { baseIds: result.map(({ base }) => base.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 @@ -5,6 +5,7 @@ import { BulkUpdateRecordsCommandHandler } from "./bulk-update-records.command-h
import { CreateApiTokenCommandHandler } from "./create-api-token.command-handler"
import { CreateBaseCommandHandler } from "./create-base.command-handler"
import { CreateFromShareCommandHandler } from "./create-from-share.command-handler"
import { CreateFromTemplateCommandHandler } from "./create-from-template.command-handler"
import { CreateRecordCommandHandler } from "./create-record.command-handler"
import { CreateRecordsCommandHandler } from "./create-records.command-handler"
import { CreateSpaceCommandHandler } from "./create-space.command-handler"
Expand Down Expand Up @@ -106,4 +107,5 @@ export const commandHandlers = [
SubmitFormCommandHandler,
SetFieldWidthCommandHandler,
DuplicateTableFormCommandHandler,
CreateFromTemplateCommandHandler,
]
24 changes: 24 additions & 0 deletions packages/commands/src/create-from-template.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { baseIdSchema } from "@undb/base"
import { Command, type CommandProps } from "@undb/domain"
import { z } from "@undb/zod"

export const createFromTemplateCommand = z.object({
templateName: z.string(),
})

export type ICreateFromTemplateCommand = z.infer<typeof createFromTemplateCommand>

export const createFromTemplateCommandOutput = z.object({
baseIds: z.array(baseIdSchema),
})

export type ICreateFromTemplateCommandOutput = z.infer<typeof createFromTemplateCommandOutput>

export class CreateFromTemplateCommand extends Command implements ICreateFromTemplateCommand {
public readonly templateName: string

constructor(props: CommandProps<ICreateFromTemplateCommand>) {
super(props)
this.templateName = props.templateName
}
}
5 changes: 4 additions & 1 deletion packages/commands/src/create-table.command.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { baseIdSchema, baseNameSchema } from "@undb/base"
import { Command, type CommandProps } from "@undb/domain"
import type { ICreateSchemaDTO } from "@undb/table"
import { createTableDTO } from "@undb/table"
import { z } from "@undb/zod"

export const createTableCommand = createTableDTO.omit({ spaceId: true })
export const createTableCommand = createTableDTO
.omit({ spaceId: true })
.merge(z.object({ baseId: baseIdSchema.optional(), baseName: baseNameSchema.optional() }))

export type ICreateTableCommand = z.infer<typeof createTableCommand>

Expand Down
1 change: 1 addition & 0 deletions packages/commands/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from "./bulk-update-records.command"
export * from "./create-api-token.command"
export * from "./create-base.command"
export * from "./create-from-share.command"
export * from "./create-from-template.command"
export * from "./create-record.command"
export * from "./create-records.command"
export * from "./create-space.command"
Expand Down
6 changes: 6 additions & 0 deletions packages/persistence/src/table/table.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ export class TableRepository implements ITableRepository {
await this.outboxService.save(table)
}

async insertMany(tables: TableDo[]): Promise<void> {
for (const table of tables) {
await this.insert(table)
}
}

async bulkUpdate(updates: { table: TableDo; spec: Option<TableComositeSpecification> }[]): Promise<void> {
for (const update of updates) {
await this.#updateOneById(update.table, update.spec)
Expand Down
5 changes: 2 additions & 3 deletions packages/table/src/dto/create-table.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { baseIdSchema, baseNameSchema } from "@undb/base"
import { baseIdSchema } from "@undb/base"
import { spaceIdSchema } from "@undb/space"
import { z } from "@undb/zod"
import { createSchemaDTO } from "../modules"
Expand All @@ -8,8 +8,7 @@ import { tableName } from "../table-name.vo"
export const createTableDTO = z.object({
id: tableId.optional(),
name: tableName,
baseId: baseIdSchema.optional(),
baseName: baseNameSchema.optional(),
baseId: baseIdSchema,
spaceId: spaceIdSchema,

schema: createSchemaDTO,
Expand Down
2 changes: 2 additions & 0 deletions packages/table/src/table.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import type { TableDo } from "./table.do"

export interface ITableRepository {
insert(table: TableDo): Promise<void>
insertMany(tables: TableDo[]): Promise<void>
updateOneById(table: TableDo, spec: Option<TableComositeSpecification>): Promise<void>
bulkUpdate(updates: { table: TableDo; spec: Option<TableComositeSpecification> }[]): Promise<void>

deleteOneById(table: TableDo): Promise<void>

find(spec: Option<TableComositeSpecification>, ignoreSpace?: boolean): Promise<TableDo[]>
Expand Down
27 changes: 19 additions & 8 deletions packages/template/src/dto/template.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ import { baseNameSchema } from "@undb/base"
import { createFieldWithoutNameDTO, fieldId, tableName } from "@undb/table"
import { z } from "@undb/zod"

export const baseTemplateDTO = z.object({
name: baseNameSchema,
tables: z.record(
tableName,
z.object({
schema: z.record(fieldId, createFieldWithoutNameDTO),
}),
),
const templateSchemaDTO = z.record(fieldId, createFieldWithoutNameDTO)

const basicTemplateTableDTO = z.object({
schema: templateSchemaDTO,
})

export const baseTemplateDTO = z.record(
baseNameSchema,
z.object({
tables: z.record(tableName, basicTemplateTableDTO),
}),
)

export type IBaseTemplateDTO = z.infer<typeof baseTemplateDTO>

export const tableTemplateDTO = z
.object({
name: tableName,
})
.merge(basicTemplateTableDTO)

export type ITableTemplateDTO = z.infer<typeof tableTemplateDTO>
1 change: 1 addition & 0 deletions packages/template/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./dto"
export * from "./schema"
export * from "./service"
export * from "./templates"
1 change: 1 addition & 0 deletions packages/template/src/service/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./template.service"
export * from "./template.service.provider"
6 changes: 6 additions & 0 deletions packages/template/src/service/template.service.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { container, inject } from "@undb/di"
import { TemplateService } from "./template.service"

export const TEMPLATE_SERVICE = Symbol.for("TemplateService")
export const injectTemplateService = () => inject(TEMPLATE_SERVICE)
container.register(TEMPLATE_SERVICE, { useClass: TemplateService })
25 changes: 23 additions & 2 deletions packages/template/src/service/template.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
import { Base, injectBaseRepository, WithBaseSpaceId, type IBaseRepository } from "@undb/base"
import { singleton } from "@undb/di"
import { createLogger } from "@undb/logger"
import { injectTableRepository, TableDo, type ITableRepository } from "@undb/table"
import type { IBaseTemplateDTO } from "../dto"
import { TemplateFactory } from "../template.factory"

export interface ITemplateService {
create(dto: IBaseTemplateDTO): Promise<void>
createBase(dto: IBaseTemplateDTO, spaceId: string): Promise<{ base: Base; tables: TableDo[] }[]>
}

@singleton()
export class TemplateService implements ITemplateService {
private readonly logger = createLogger(TemplateService.name)
async create(dto: IBaseTemplateDTO): Promise<void> {

constructor(
@injectBaseRepository()
private readonly baseRepository: IBaseRepository,
@injectTableRepository()
private readonly tableRepository: ITableRepository,
) {}

async createBase(dto: IBaseTemplateDTO, spaceId: string): Promise<{ base: Base; tables: TableDo[] }[]> {
this.logger.info(dto)
const bases = await this.baseRepository.find(new WithBaseSpaceId(spaceId))
const baseNames = bases.map((base) => base.name.value)
const result = TemplateFactory.create(dto, baseNames, spaceId)

for (const { base, tables } of result) {
await this.baseRepository.insert(base)
await this.tableRepository.insertMany(tables)
}

return result
}
}
27 changes: 27 additions & 0 deletions packages/template/src/template.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Base, BaseFactory } from "@undb/base"
import { type ICreateSchemaDTO, TableCreator, TableDo } from "@undb/table"
import { getNextName } from "@undb/utils"
import { type IBaseTemplateDTO } from "./dto/template.dto"

export class TemplateFactory {
static create(template: IBaseTemplateDTO, baseNames: string[], spaceId: string): { base: Base; tables: TableDo[] }[] {
const result: { base: Base; tables: TableDo[] }[] = []
for (const [name, b] of Object.entries(template)) {
const baseName = getNextName(baseNames, name)
const base = BaseFactory.create({ name: baseName, spaceId })
const baseId = base.id.value

const tables: TableDo[] = []
for (const [name, table] of Object.entries(b.tables)) {
const schema = Object.entries(table.schema).map(([name, field]) => ({ ...field, name })) as ICreateSchemaDTO

const t = new TableCreator().create({ baseId, name, schema, spaceId })
tables.push(t)
}

result.push({ base, tables })
}

return result
}
}
6 changes: 6 additions & 0 deletions packages/template/src/templates/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { IBaseTemplateDTO } from "../dto"
import { default as test } from "./test.base.json"

const templates: Record<string, IBaseTemplateDTO> = { test } as const

export { templates }
47 changes: 24 additions & 23 deletions packages/template/src/templates/test.base.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
{
"name": "hello",
"tables": {
"world": {
"schema": {
"name": {
"type": "string",
"constraint": {
"max": 10
"hello": {
"tables": {
"world": {
"schema": {
"name": {
"type": "string",
"constraint": {
"max": 10
},
"defaultValue": "world",
"display": true
},
"defaultValue": "world",
"display": true
},
"age": {
"type": "number",
"constraint": {
"min": 0
"age": {
"type": "number",
"constraint": {
"min": 0
}
},
"parent": {
"type": "user",
"defaultValue": "@me"
},
"isActive": {
"type": "checkbox",
"defaultValue": true
}
},
"parent": {
"type": "user",
"defaultValue": "@me"
},
"isActive": {
"type": "checkbox",
"defaultValue": true
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion packages/template/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
"noPropertyAccessFromIndexSignature": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
1 change: 1 addition & 0 deletions packages/trpc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@undb/persistence": "workspace:*",
"@undb/queries": "workspace:*",
"@undb/table": "workspace:*",
"@undb/template": "workspace:*",
"@undb/zod": "workspace:*",
"zod-validation-error": "^3.3.1"
}
Expand Down
Loading

0 comments on commit b106abf

Please sign in to comment.