From 831a400d3836994c394441c7a052f9f0899d3373 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Sat, 21 Sep 2024 09:55:48 +0800 Subject: [PATCH 1/6] feat: create table accept base name --- packages/base/src/dto/index.ts | 1 + packages/base/src/dto/unique-base.dto.ts | 13 ++++++++++++ packages/base/src/specifications/index.ts | 20 +++++++++++++++++++ packages/commands/src/create-base.command.ts | 11 +++++++++- packages/commands/src/create-table.command.ts | 4 +++- packages/table/src/dto/create-table.dto.ts | 5 +++-- .../services/methods/create-table.method.ts | 8 ++++++-- 7 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 packages/base/src/dto/unique-base.dto.ts diff --git a/packages/base/src/dto/index.ts b/packages/base/src/dto/index.ts index 185736b43..ff94ea2ba 100644 --- a/packages/base/src/dto/index.ts +++ b/packages/base/src/dto/index.ts @@ -2,4 +2,5 @@ export * from "./base.dto" export * from "./create-base.dto" export * from "./delete-base.dto" export * from "./duplicate-base.dto" +export * from "./unique-base.dto" export * from "./update-base.dto" diff --git a/packages/base/src/dto/unique-base.dto.ts b/packages/base/src/dto/unique-base.dto.ts new file mode 100644 index 000000000..87d482ce9 --- /dev/null +++ b/packages/base/src/dto/unique-base.dto.ts @@ -0,0 +1,13 @@ +import { spaceIdSchema } from "@undb/space" +import { z } from "@undb/zod" +import { baseIdSchema, baseNameSchema } from "../value-objects" + +export const uniqueBaseDTO = z + .object({ + baseId: baseIdSchema, + baseName: baseNameSchema, + spaceId: spaceIdSchema, + }) + .partial() + +export type IUniqueBaseDTO = z.infer diff --git a/packages/base/src/specifications/index.ts b/packages/base/src/specifications/index.ts index d883b1ee4..fee4e50c1 100644 --- a/packages/base/src/specifications/index.ts +++ b/packages/base/src/specifications/index.ts @@ -2,3 +2,23 @@ export * from "./base-id.specification.js" export * from "./base-name.specification.js" export * from "./base-q.specification.js" export * from "./base-space-id.specification.js" + +import { CompositeSpecification, Err, Ok, Result } from "@undb/domain" +import type { Base } from "../base.js" +import type { IUniqueBaseDTO } from "../dto/unique-base.dto.js" +import type { IBaseSpecVisitor } from "../interface.js" +import { BaseId } from "../value-objects/base-id.vo.js" +import { WithBaseId } from "./base-id.specification.js" +import { WithBaseName } from "./base-name.specification.js" + +type BaseComositeSpecification = CompositeSpecification + +export const withUniqueBase = (dto: IUniqueBaseDTO): Result => { + if (dto.baseId) { + return Ok(new WithBaseId(new BaseId(dto.baseId))) + } + if (dto.baseName && dto.spaceId) { + return Ok(WithBaseName.fromString(dto.baseName)) + } + return Err("Invalid base specification") +} diff --git a/packages/commands/src/create-base.command.ts b/packages/commands/src/create-base.command.ts index 4421cc8b7..5dc77541c 100644 --- a/packages/commands/src/create-base.command.ts +++ b/packages/commands/src/create-base.command.ts @@ -1,8 +1,17 @@ import { createBaseDTO } from "@undb/base" import { Command, type CommandProps } from "@undb/domain" import { z } from "@undb/zod" +import { createTableCommand } from "./create-table.command" -export const createBaseCommand = createBaseDTO.omit({ id: true }) +export const createBaseCommand = createBaseDTO + .omit({ + id: true, + }) + .merge( + z.object({ + tables: createTableCommand.array().optional(), + }), + ) export type ICreateBaseCommand = z.infer diff --git a/packages/commands/src/create-table.command.ts b/packages/commands/src/create-table.command.ts index 2bc7520b9..3ef358baa 100644 --- a/packages/commands/src/create-table.command.ts +++ b/packages/commands/src/create-table.command.ts @@ -10,7 +10,8 @@ export type ICreateTableCommand = z.infer export class CreateTableCommand extends Command implements ICreateTableCommand { public readonly id?: string public readonly name: string - public readonly baseId: string + public readonly baseId?: string + public readonly baseName?: string public readonly schema: ICreateSchemaDTO constructor(props: CommandProps) { @@ -18,6 +19,7 @@ export class CreateTableCommand extends Command implements ICreateTableCommand { this.id = props.id this.name = props.name this.baseId = props.baseId + this.baseName = props.baseName this.schema = props.schema } } diff --git a/packages/table/src/dto/create-table.dto.ts b/packages/table/src/dto/create-table.dto.ts index 245b9ced3..f323f5bf6 100644 --- a/packages/table/src/dto/create-table.dto.ts +++ b/packages/table/src/dto/create-table.dto.ts @@ -1,4 +1,4 @@ -import { baseIdSchema } from "@undb/base" +import { baseIdSchema, baseNameSchema } from "@undb/base" import { spaceIdSchema } from "@undb/space" import { z } from "@undb/zod" import { createSchemaDTO } from "../modules" @@ -8,7 +8,8 @@ import { tableName } from "../table-name.vo" export const createTableDTO = z.object({ id: tableId.optional(), name: tableName, - baseId: baseIdSchema, + baseId: baseIdSchema.optional(), + baseName: baseNameSchema.optional(), spaceId: spaceIdSchema, schema: createSchemaDTO, diff --git a/packages/table/src/services/methods/create-table.method.ts b/packages/table/src/services/methods/create-table.method.ts index 86b5b31f1..f9967986c 100644 --- a/packages/table/src/services/methods/create-table.method.ts +++ b/packages/table/src/services/methods/create-table.method.ts @@ -1,3 +1,4 @@ +import { withUniqueBase } from "@undb/base" import { applyRules, Some } from "@undb/domain" import type { ICreateTableDTO } from "../../dto" import { TableNameShouldBeUnique } from "../../rules/table-name-should-be-unique.rule" @@ -6,8 +7,11 @@ import type { TableDo } from "../../table.do" import type { TableService } from "../table.service" export async function createTableMethod(this: TableService, dto: ICreateTableDTO): Promise { - const spec = new TableBaseIdSpecification(dto.baseId) - const baseTables = await this.repository.find(Some(spec)) + const spec = withUniqueBase(dto).ok() + const base = (await this.baseRepository.findOne(spec.unwrap())).expect("base not found") + + const baseIdSpec = new TableBaseIdSpecification(base.id.value) + const baseTables = await this.repository.find(Some(baseIdSpec)) const names = baseTables.map((table) => table.name.value).concat(dto.name) applyRules(new TableNameShouldBeUnique(names)) From 341f84a1e5a0d42ab47a24752fd96c46a1494526 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Sat, 21 Sep 2024 11:02:40 +0800 Subject: [PATCH 2/6] feat: add template --- .vscode/settings.json | 8 + apps/backend/package.json | 1 + apps/backend/src/app.ts | 3 + .../src/modules/template/template.module.ts | 12 ++ bun.lockb | Bin 573680 -> 574152 bytes .../base/src/value-objects/base-name.vo.ts | 2 +- .../schema/fields/condition/condition.type.ts | 10 +- .../schema/fields/dto/create-field.dto.ts | 33 +++- packages/template/.gitignore | 175 ++++++++++++++++++ packages/template/README.md | 15 ++ packages/template/package.json | 18 ++ packages/template/src/dto/index.ts | 1 + packages/template/src/dto/template.dto.ts | 14 ++ packages/template/src/index.ts | 2 + packages/template/src/schema/index.ts | 1 + .../template/src/schema/template.schema.ts | 6 + packages/template/src/templates/test.json | 17 ++ packages/template/tsconfig.json | 27 +++ 18 files changed, 335 insertions(+), 10 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 apps/backend/src/modules/template/template.module.ts create mode 100644 packages/template/.gitignore create mode 100644 packages/template/README.md create mode 100644 packages/template/package.json create mode 100644 packages/template/src/dto/index.ts create mode 100644 packages/template/src/dto/template.dto.ts create mode 100644 packages/template/src/index.ts create mode 100644 packages/template/src/schema/index.ts create mode 100644 packages/template/src/schema/template.schema.ts create mode 100644 packages/template/src/templates/test.json create mode 100644 packages/template/tsconfig.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..d4689852c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "json.schemas": [ + { + "fileMatch": ["packages/template/src/templates/*.json"], + "url": "http://localhost:3721/api/template/schema.json" + } + ] +} diff --git a/apps/backend/package.json b/apps/backend/package.json index c0507500a..9a9f176e3 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -36,6 +36,7 @@ "@undb/realtime": "workspace:*", "@undb/share": "workspace:*", "@undb/space": "workspace:*", + "@undb/template": "workspace:*", "@undb/trpc": "workspace:*", "@undb/webhook": "workspace:*", "arctic": "^1.9.2", diff --git a/apps/backend/src/app.ts b/apps/backend/src/app.ts index 09317b95e..546fa5dc5 100644 --- a/apps/backend/src/app.ts +++ b/apps/backend/src/app.ts @@ -26,12 +26,14 @@ import * as pkg from "../../../package.json" import { Auth, OpenAPI, Realtime, SpaceModule, TableModule, Web } from "./modules" import { FileService } from "./modules/file/file" import { OpenTelemetryModule } from "./modules/opentelemetry/opentelemetry.module" +import { TemplateModule } from "./modules/template/template.module" import { loggerPlugin } from "./plugins/logging" const auth = container.resolve(Auth) const web = container.resolve(Web) const openapi = container.resolve(OpenAPI) const opentelemetry = container.resolve(OpenTelemetryModule) +const template = container.resolve(TemplateModule) export const app = new Elysia() .onStart(async () => { @@ -132,6 +134,7 @@ export const app = new Elysia() .use(auth.route()) .use(web.route()) .use(openapi.route()) + .use(template.route()) .use(trpc(route)) .guard( { diff --git a/apps/backend/src/modules/template/template.module.ts b/apps/backend/src/modules/template/template.module.ts new file mode 100644 index 000000000..63dc4ac02 --- /dev/null +++ b/apps/backend/src/modules/template/template.module.ts @@ -0,0 +1,12 @@ +import { singleton } from "@undb/di" +import { templateSchema } from "@undb/template" +import Elysia from "elysia" + +@singleton() +export class TemplateModule { + route() { + return new Elysia().get("/api/template/schema.json", () => { + return templateSchema + }) + } +} diff --git a/bun.lockb b/bun.lockb index 889d213c6d42a899628e1baf329921a752de60e3..c0e652b0e5970fe3bacbeba30efdda6a334830e1 100755 GIT binary patch delta 111094 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

j&A$)C8 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≈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 diff --git a/packages/base/src/value-objects/base-name.vo.ts b/packages/base/src/value-objects/base-name.vo.ts index e135c98eb..b81117aa6 100644 --- a/packages/base/src/value-objects/base-name.vo.ts +++ b/packages/base/src/value-objects/base-name.vo.ts @@ -1,7 +1,7 @@ import { ValueObject } from "@undb/domain" import * as z from "@undb/zod" -export const baseNameSchema = z.string().min(1) +export const baseNameSchema = z.string().min(1, { message: "Base name must be at least 1 character" }) export class BaseName extends ValueObject> { static from(name: string): BaseName { diff --git a/packages/table/src/modules/schema/fields/condition/condition.type.ts b/packages/table/src/modules/schema/fields/condition/condition.type.ts index 209d15ce0..962b59d9a 100644 --- a/packages/table/src/modules/schema/fields/condition/condition.type.ts +++ b/packages/table/src/modules/schema/fields/condition/condition.type.ts @@ -29,12 +29,16 @@ export type MaybeConditionGroupChildren = Maybe export function createConditionGroup( optionType: OptionType, fieldType: FieldOptionType, + level = 1, ): z.ZodType> { + const nested = level < 3 ? z.lazy(() => createConditionGroup(optionType, fieldType, level + 1)) : undefined + const child = nested + ? z.union([...createConditionSchema(fieldType).options, nested]) + : z.union([...createConditionSchema(fieldType).options]) + return z.object({ conjunction: z.enum(["and", "or"]), - children: z.array( - z.union([...createConditionSchema(fieldType).options, z.lazy(() => createConditionGroup(optionType, fieldType))]), - ), + children: z.array(child), disabled: z.boolean().optional(), option: optionType, }) as z.ZodType> diff --git a/packages/table/src/modules/schema/fields/dto/create-field.dto.ts b/packages/table/src/modules/schema/fields/dto/create-field.dto.ts index f876f1c61..48d319fd2 100644 --- a/packages/table/src/modules/schema/fields/dto/create-field.dto.ts +++ b/packages/table/src/modules/schema/fields/dto/create-field.dto.ts @@ -1,13 +1,13 @@ import { z } from "@undb/zod" -import { createAttachmentFieldDTO } from "../variants/attachment-field" +import { createAttachmentFieldDTO } from "../variants/attachment-field/attachment-field.vo" import { createButtonFieldDTO } from "../variants/button-field/button-field.vo" -import { createCheckboxFieldDTO } from "../variants/checkbox-field" -import { createCurrencyFieldDTO } from "../variants/currency-field" +import { createCheckboxFieldDTO } from "../variants/checkbox-field/checkbox-field.vo" +import { createCurrencyFieldDTO } from "../variants/currency-field/currency-field.vo" import { createDateFieldDTO } from "../variants/date-field/date-field.vo" import { createDurationFieldDTO } from "../variants/duration-field/duration-field.vo" -import { createEmailFieldDTO } from "../variants/email-field" +import { createEmailFieldDTO } from "../variants/email-field/email-field.vo" import { createJsonFieldDTO } from "../variants/json-field/json-field.vo" -import { createLongTextFieldDTO } from "../variants/long-text-field" +import { createLongTextFieldDTO } from "../variants/long-text-field/long-text-field.vo" import { createNumberFieldDTO } from "../variants/number-field/number-field.vo" import { createPercentageFieldDTO } from "../variants/percentage-field/percentage-field.vo" import { createRatingFieldDTO } from "../variants/rating-field/rating-field.vo" @@ -16,7 +16,7 @@ import { createRollupFieldDTO } from "../variants/rollup-field/rollup-field.vo" import { createSelectFieldDTO } from "../variants/select-field/select-field.vo" import { createStringFieldDTO } from "../variants/string-field/string-field.vo" import { createUrlFieldDTO } from "../variants/url-field/url-field.vo" -import { createUserFieldDTO } from "../variants/user-field" +import { createUserFieldDTO } from "../variants/user-field/user-field.vo" export const createFieldDTO = z.discriminatedUnion("type", [ createStringFieldDTO, @@ -39,4 +39,25 @@ export const createFieldDTO = z.discriminatedUnion("type", [ createPercentageFieldDTO, ]) +export const createFieldWithoutNameDTO = z.discriminatedUnion("type", [ + createStringFieldDTO.omit({ name: true }), + createNumberFieldDTO.omit({ name: true }), + createReferenceFieldDTO.omit({ name: true }), + createRollupFieldDTO.omit({ name: true }), + createSelectFieldDTO.omit({ name: true }), + createRatingFieldDTO.omit({ name: true }), + createEmailFieldDTO.omit({ name: true }), + createUrlFieldDTO.omit({ name: true }), + createAttachmentFieldDTO.omit({ name: true }), + createDateFieldDTO.omit({ name: true }), + createJsonFieldDTO.omit({ name: true }), + createCheckboxFieldDTO.omit({ name: true }), + createUserFieldDTO.omit({ name: true }), + createLongTextFieldDTO.omit({ name: true }), + createCurrencyFieldDTO.omit({ name: true }), + createButtonFieldDTO.omit({ name: true }), + createDurationFieldDTO.omit({ name: true }), + createPercentageFieldDTO.omit({ name: true }), +]) + export type ICreateFieldDTO = z.infer diff --git a/packages/template/.gitignore b/packages/template/.gitignore new file mode 100644 index 000000000..9b1ee42e8 --- /dev/null +++ b/packages/template/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/packages/template/README.md b/packages/template/README.md new file mode 100644 index 000000000..5ce3e9add --- /dev/null +++ b/packages/template/README.md @@ -0,0 +1,15 @@ +# @undb/template + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run src/index.ts +``` + +This project was created using `bun init` in bun v1.1.29. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/packages/template/package.json b/packages/template/package.json new file mode 100644 index 000000000..8d1a25601 --- /dev/null +++ b/packages/template/package.json @@ -0,0 +1,18 @@ +{ + "name": "@undb/template", + "module": "src/index.ts", + "types": "src/index.d.ts", + "type": "module", + "dependencies": { + "@undb/base": "workspace:*", + "@undb/table": "workspace:*", + "@undb/zod": "workspace:*", + "zod-to-json-schema": "^3.23.3" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/packages/template/src/dto/index.ts b/packages/template/src/dto/index.ts new file mode 100644 index 000000000..8d39f46f6 --- /dev/null +++ b/packages/template/src/dto/index.ts @@ -0,0 +1 @@ +export * from "./template.dto" diff --git a/packages/template/src/dto/template.dto.ts b/packages/template/src/dto/template.dto.ts new file mode 100644 index 000000000..282880552 --- /dev/null +++ b/packages/template/src/dto/template.dto.ts @@ -0,0 +1,14 @@ +import { baseNameSchema } from "@undb/base" +import { createFieldWithoutNameDTO } from "@undb/table" +import { z } from "@undb/zod" + +export const templateDTO = z.object({ + name: baseNameSchema, + tables: z.record( + z.object({ + schema: z.record(createFieldWithoutNameDTO), + }), + ), +}) + +export type ITemplateDTO = z.infer diff --git a/packages/template/src/index.ts b/packages/template/src/index.ts new file mode 100644 index 000000000..30ec08ead --- /dev/null +++ b/packages/template/src/index.ts @@ -0,0 +1,2 @@ +export * from "./dto" +export * from "./schema" diff --git a/packages/template/src/schema/index.ts b/packages/template/src/schema/index.ts new file mode 100644 index 000000000..485ab3c44 --- /dev/null +++ b/packages/template/src/schema/index.ts @@ -0,0 +1 @@ +export * from "./template.schema" diff --git a/packages/template/src/schema/template.schema.ts b/packages/template/src/schema/template.schema.ts new file mode 100644 index 000000000..76be92e54 --- /dev/null +++ b/packages/template/src/schema/template.schema.ts @@ -0,0 +1,6 @@ +import zodToJsonSchema from "zod-to-json-schema" +import { templateDTO } from "../dto/template.dto" + +export const templateSchema = zodToJsonSchema(templateDTO, { + errorMessages: true, +}) diff --git a/packages/template/src/templates/test.json b/packages/template/src/templates/test.json new file mode 100644 index 000000000..95887156b --- /dev/null +++ b/packages/template/src/templates/test.json @@ -0,0 +1,17 @@ +{ + "name": "hello", + "tables": { + "world": { + "schema": { + "name": { + "type": "string", + "constraint": { + "max": 10 + }, + "defaultValue": "world", + "display": true + } + } + } + } +} diff --git a/packages/template/tsconfig.json b/packages/template/tsconfig.json new file mode 100644 index 000000000..238655f2c --- /dev/null +++ b/packages/template/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} From 919ad556b48c382c10f8714f7571b6e93845fdbb Mon Sep 17 00:00:00 2001 From: nichenqin Date: Sat, 21 Sep 2024 14:52:20 +0800 Subject: [PATCH 3/6] feat: rename create from template to create from share --- .vscode/settings.json | 4 +- .../src/modules/template/template.module.ts | 6 +- .../[shareId]/+layout.gql | 2 +- .../[shareId]/+layout.svelte | 0 .../[shareId]/+layout.ts | 4 +- .../[shareId]/+page.svelte | 16 ++--- ...s => create-from-share.command-handler.ts} | 12 ++-- .../command-handlers/src/handlers/index.ts | 4 +- packages/commands/package.json | 1 + ...ommand.ts => create-from-share.command.ts} | 8 +-- packages/commands/src/index.ts | 2 +- .../reference-field/reference-field.vo.ts | 2 +- .../variants/rollup-field/rollup-field.vo.ts | 2 +- packages/template/package.json | 2 + packages/template/src/dto/template.dto.ts | 9 +-- packages/template/src/index.ts | 1 + .../template/src/schema/template.schema.ts | 66 ++++++++++++++++++- packages/template/src/service/index.ts | 1 + .../template/src/service/template.service.ts | 15 +++++ .../template/src/templates/test.base.json | 31 +++++++++ packages/template/src/templates/test.json | 17 ----- packages/trpc/src/router.ts | 16 ++--- 22 files changed, 159 insertions(+), 62 deletions(-) rename apps/frontend/src/routes/(authed)/(template)/{create-from-template => create-from-share}/[shareId]/+layout.gql (75%) rename apps/frontend/src/routes/(authed)/(template)/{create-from-template => create-from-share}/[shareId]/+layout.svelte (100%) rename apps/frontend/src/routes/(authed)/(template)/{create-from-template => create-from-share}/[shareId]/+layout.ts (71%) rename apps/frontend/src/routes/(authed)/(template)/{create-from-template => create-from-share}/[shareId]/+page.svelte (93%) rename packages/command-handlers/src/handlers/{create-from-template.command-handler.ts => create-from-share.command-handler.ts} (81%) rename packages/commands/src/{create-from-template.command.ts => create-from-share.command.ts} (68%) create mode 100644 packages/template/src/service/index.ts create mode 100644 packages/template/src/service/template.service.ts create mode 100644 packages/template/src/templates/test.base.json delete mode 100644 packages/template/src/templates/test.json diff --git a/.vscode/settings.json b/.vscode/settings.json index d4689852c..2999acac8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,8 @@ { "json.schemas": [ { - "fileMatch": ["packages/template/src/templates/*.json"], - "url": "http://localhost:3721/api/template/schema.json" + "fileMatch": ["packages/template/src/templates/*.base.json"], + "url": "http://localhost:3721/api/template/base/schema.json" } ] } diff --git a/apps/backend/src/modules/template/template.module.ts b/apps/backend/src/modules/template/template.module.ts index 63dc4ac02..f16390717 100644 --- a/apps/backend/src/modules/template/template.module.ts +++ b/apps/backend/src/modules/template/template.module.ts @@ -1,12 +1,12 @@ import { singleton } from "@undb/di" -import { templateSchema } from "@undb/template" +import { baseTemplateSchema } from "@undb/template" import Elysia from "elysia" @singleton() export class TemplateModule { route() { - return new Elysia().get("/api/template/schema.json", () => { - return templateSchema + return new Elysia().get("/api/template/base/schema.json", () => { + return baseTemplateSchema }) } } diff --git a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.gql b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.gql similarity index 75% rename from apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.gql rename to apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.gql index d562fc602..fc5e8196e 100644 --- a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.gql +++ b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.gql @@ -1,4 +1,4 @@ -query GetCreateFromTemplateData($shareId: ID!) { +query GetCreateFromShareData($shareId: ID!) { space { id name diff --git a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.svelte b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.svelte similarity index 100% rename from apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.svelte rename to apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.svelte diff --git a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.ts b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.ts similarity index 71% rename from apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.ts rename to apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.ts index 0c07ee103..102e215b6 100644 --- a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+layout.ts +++ b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+layout.ts @@ -1,4 +1,4 @@ -import { GetCreateFromTemplateDataStore } from "$houdini" +import { GetCreateFromShareDataStore } from "$houdini" import type { LayoutLoad } from "./$types" export const ssr = false @@ -7,7 +7,7 @@ export const prerender = "auto" export const load: LayoutLoad = async (event) => { const { shareId } = event.params - const store = new GetCreateFromTemplateDataStore() + const store = new GetCreateFromShareDataStore() await store.fetch({ event, diff --git a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+page.svelte b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+page.svelte similarity index 93% rename from apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+page.svelte rename to apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+page.svelte index 6a8b0ed27..ac81bfe87 100644 --- a/apps/frontend/src/routes/(authed)/(template)/create-from-template/[shareId]/+page.svelte +++ b/apps/frontend/src/routes/(authed)/(template)/create-from-share/[shareId]/+page.svelte @@ -9,7 +9,7 @@ import * as Form from "$lib/components/ui/form" import * as Alert from "$lib/components/ui/alert/index.js" import { LoaderCircleIcon, SirenIcon, Store } from "lucide-svelte" - import { createFromTemplateCommand } from "@undb/commands" + import { createFromShareCommand } from "@undb/commands" import { Checkbox } from "$lib/components/ui/checkbox" import { trpc } from "$lib/trpc/client" import { page } from "$app/stores" @@ -39,8 +39,8 @@ }) } - const createFromTemplateMutation = createMutation({ - mutationFn: trpc.base.createFromTemplate.mutate, + const createFromShareMutation = createMutation({ + mutationFn: trpc.base.createFromShare.mutate, onError(error, variables, context) { toast.error(error.message) }, @@ -60,12 +60,12 @@ name: template?.name, includeData: true, }, - zodClient(createFromTemplateCommand), + zodClient(createFromShareCommand), ), { SPA: true, dataType: "json", - validators: zodClient(createFromTemplateCommand), + validators: zodClient(createFromShareCommand), resetForm: false, invalidateAll: false, onSubmit(input) { @@ -77,7 +77,7 @@ return } - await $createFromTemplateMutation.mutateAsync(event.form.data) + await $createFromShareMutation.mutateAsync(event.form.data) }, }, ) @@ -176,8 +176,8 @@ System fields will be updated to the current user and timestamp. - - {#if $createFromTemplateMutation.isPending} + + {#if $createFromShareMutation.isPending} {/if} Create diff --git a/packages/command-handlers/src/handlers/create-from-template.command-handler.ts b/packages/command-handlers/src/handlers/create-from-share.command-handler.ts similarity index 81% rename from packages/command-handlers/src/handlers/create-from-template.command-handler.ts rename to packages/command-handlers/src/handlers/create-from-share.command-handler.ts index 376ffb96b..272e0cc3b 100644 --- a/packages/command-handlers/src/handlers/create-from-template.command-handler.ts +++ b/packages/command-handlers/src/handlers/create-from-share.command-handler.ts @@ -1,6 +1,6 @@ import { checkPermission, injectSpaceMemberService, type ISpaceMemberService } from "@undb/authz" import { BaseId, injectBaseRepository, WithBaseId, WithBaseSpaceId, type IBaseRepository } from "@undb/base" -import { CreateFromTemplateCommand } from "@undb/commands" +import { CreateFromShareCommand } from "@undb/commands" import { getCurrentUserId, mustGetCurrentSpaceId } from "@undb/context/server" import { commandHandler } from "@undb/cqrs" import { singleton } from "@undb/di" @@ -9,10 +9,10 @@ import { createLogger } from "@undb/logger" import { injectShareRepository, WithShareId, type IShareRepository } from "@undb/share" import { injectTableService, type ITableService } from "@undb/table" -@commandHandler(CreateFromTemplateCommand) +@commandHandler(CreateFromShareCommand) @singleton() -export class CreateFromTemplateCommandHandler implements ICommandHandler { - private readonly logger = createLogger(CreateFromTemplateCommandHandler.name) +export class CreateFromShareCommandHandler implements ICommandHandler { + private readonly logger = createLogger(CreateFromShareCommandHandler.name) constructor( @injectBaseRepository() @@ -25,8 +25,8 @@ export class CreateFromTemplateCommandHandler implements ICommandHandler { - this.logger.debug("CreateFromTemplateCommandHandler execute command", command) + async execute(command: CreateFromShareCommand): Promise { + this.logger.debug("CreateFromShareCommandHandler execute command", command) const share = (await this.shareRepository.findOne(WithShareId.fromString(command.shareId))).expect( "Share not found", ) diff --git a/packages/command-handlers/src/handlers/index.ts b/packages/command-handlers/src/handlers/index.ts index 103e70821..1f6853ae4 100644 --- a/packages/command-handlers/src/handlers/index.ts +++ b/packages/command-handlers/src/handlers/index.ts @@ -4,7 +4,7 @@ import { BulkDuplicateRecordsCommandHandler } from "./bulk-duplicate-records.com import { BulkUpdateRecordsCommandHandler } from "./bulk-update-records.command-handler" import { CreateApiTokenCommandHandler } from "./create-api-token.command-handler" import { CreateBaseCommandHandler } from "./create-base.command-handler" -import { CreateFromTemplateCommandHandler } from "./create-from-template.command-handler" +import { CreateFromShareCommandHandler } from "./create-from-share.command-handler" import { CreateRecordCommandHandler } from "./create-record.command-handler" import { CreateRecordsCommandHandler } from "./create-records.command-handler" import { CreateSpaceCommandHandler } from "./create-space.command-handler" @@ -79,7 +79,7 @@ export const commandHandlers = [ BulkUpdateRecordsCommandHandler, CreateTableViewCommandHandler, DuplicateViewCommandHandler, - CreateFromTemplateCommandHandler, + CreateFromShareCommandHandler, DeleteViewCommandHandler, CreateBaseCommandHandler, UpdateBaseCommandHandler, diff --git a/packages/commands/package.json b/packages/commands/package.json index 421c37f60..d993de07b 100644 --- a/packages/commands/package.json +++ b/packages/commands/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@undb/base": "workspace:*", + "@undb/template": "workspace:*", "@undb/domain": "workspace:*", "@undb/openapi": "workspace:*", "@undb/share": "workspace:*", diff --git a/packages/commands/src/create-from-template.command.ts b/packages/commands/src/create-from-share.command.ts similarity index 68% rename from packages/commands/src/create-from-template.command.ts rename to packages/commands/src/create-from-share.command.ts index b67a9d9c3..51291da75 100644 --- a/packages/commands/src/create-from-template.command.ts +++ b/packages/commands/src/create-from-share.command.ts @@ -3,22 +3,22 @@ import { shareIdSchema } from "@undb/share" import { spaceIdSchema } from "@undb/space" import { z } from "@undb/zod" -export const createFromTemplateCommand = z.object({ +export const createFromShareCommand = z.object({ shareId: shareIdSchema, targetSpaceId: spaceIdSchema.optional(), name: z.string().optional(), includeData: z.boolean().optional(), }) -export type ICreateFromTemplateCommand = z.infer +export type ICreateFromShareCommand = z.infer -export class CreateFromTemplateCommand extends Command implements ICreateFromTemplateCommand { +export class CreateFromShareCommand extends Command implements ICreateFromShareCommand { public readonly shareId: string public readonly targetSpaceId?: string public readonly name?: string public readonly includeData?: boolean - constructor(props: CommandProps) { + constructor(props: CommandProps) { super(props) this.shareId = props.shareId this.targetSpaceId = props.targetSpaceId diff --git a/packages/commands/src/index.ts b/packages/commands/src/index.ts index 18f1e17db..b3d2df428 100644 --- a/packages/commands/src/index.ts +++ b/packages/commands/src/index.ts @@ -4,7 +4,7 @@ export * from "./bulk-duplicate-records.command" export * from "./bulk-update-records.command" export * from "./create-api-token.command" export * from "./create-base.command" -export * from "./create-from-template.command" +export * from "./create-from-share.command" export * from "./create-record.command" export * from "./create-records.command" export * from "./create-space.command" diff --git a/packages/table/src/modules/schema/fields/variants/reference-field/reference-field.vo.ts b/packages/table/src/modules/schema/fields/variants/reference-field/reference-field.vo.ts index 0eac8748d..3b6788f64 100644 --- a/packages/table/src/modules/schema/fields/variants/reference-field/reference-field.vo.ts +++ b/packages/table/src/modules/schema/fields/variants/reference-field/reference-field.vo.ts @@ -21,7 +21,7 @@ import { createReferenceFieldCondition, type IReferenceFieldConditionSchema } fr export const REFERENCE_TYPE = "reference" as const -const referenceFieldOption = z.object({ +export const referenceFieldOption = z.object({ isOwner: z.boolean(), foreignTableId: tableId, symmetricFieldId: fieldId.optional(), diff --git a/packages/table/src/modules/schema/fields/variants/rollup-field/rollup-field.vo.ts b/packages/table/src/modules/schema/fields/variants/rollup-field/rollup-field.vo.ts index 927334c3a..c98ee7034 100644 --- a/packages/table/src/modules/schema/fields/variants/rollup-field/rollup-field.vo.ts +++ b/packages/table/src/modules/schema/fields/variants/rollup-field/rollup-field.vo.ts @@ -17,7 +17,7 @@ export const rollupFn = z.enum(["sum", "average", "count", "min", "max", "lookup export type IRollupFn = z.infer -const rollupFieldOption = z.object({ +export const rollupFieldOption = z.object({ referenceFieldId: fieldId, rollupFieldId: fieldId, fn: rollupFn, diff --git a/packages/template/package.json b/packages/template/package.json index 8d1a25601..ead1da7f6 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -7,6 +7,8 @@ "@undb/base": "workspace:*", "@undb/table": "workspace:*", "@undb/zod": "workspace:*", + "@undb/di": "workspace:*", + "@undb/logger": "workspace:*", "zod-to-json-schema": "^3.23.3" }, "devDependencies": { diff --git a/packages/template/src/dto/template.dto.ts b/packages/template/src/dto/template.dto.ts index 282880552..a36cfc1e3 100644 --- a/packages/template/src/dto/template.dto.ts +++ b/packages/template/src/dto/template.dto.ts @@ -1,14 +1,15 @@ import { baseNameSchema } from "@undb/base" -import { createFieldWithoutNameDTO } from "@undb/table" +import { createFieldWithoutNameDTO, fieldId, tableName } from "@undb/table" import { z } from "@undb/zod" -export const templateDTO = z.object({ +export const baseTemplateDTO = z.object({ name: baseNameSchema, tables: z.record( + tableName, z.object({ - schema: z.record(createFieldWithoutNameDTO), + schema: z.record(fieldId, createFieldWithoutNameDTO), }), ), }) -export type ITemplateDTO = z.infer +export type IBaseTemplateDTO = z.infer diff --git a/packages/template/src/index.ts b/packages/template/src/index.ts index 30ec08ead..b349bab42 100644 --- a/packages/template/src/index.ts +++ b/packages/template/src/index.ts @@ -1,2 +1,3 @@ export * from "./dto" export * from "./schema" +export * from "./service" diff --git a/packages/template/src/schema/template.schema.ts b/packages/template/src/schema/template.schema.ts index 76be92e54..78b4ba4f4 100644 --- a/packages/template/src/schema/template.schema.ts +++ b/packages/template/src/schema/template.schema.ts @@ -1,6 +1,68 @@ +import { baseNameSchema } from "@undb/base" +import { + attachmentFieldConstraint, + buttonFieldOption, + checkboxFieldConstraint, + currencyFieldConstraint, + currencyFieldOption, + dateFieldConstraint, + durationFieldConstraint, + emailFieldConstraint, + fieldId, + fieldName, + jsonFieldConstraint, + longTextFieldConstraint, + numberFieldConstraint, + percentageFieldConstraint, + ratingFieldConstraint, + referenceFieldConstraint, + referenceFieldOption, + rollupFieldOption, + selectFieldConstraint, + selectFieldOption, + stringFieldConstraint, + tableId, + tableName, + urlFieldConstraint, + userFieldConstraint, + viewFilterGroup, +} from "@undb/table" import zodToJsonSchema from "zod-to-json-schema" -import { templateDTO } from "../dto/template.dto" +import { baseTemplateDTO } from "../dto/template.dto" -export const templateSchema = zodToJsonSchema(templateDTO, { +export const baseTemplateSchema = zodToJsonSchema(baseTemplateDTO, { errorMessages: true, + definitions: { + tableId, + tableName, + baseName: baseNameSchema, + fieldId, + fieldName, + viewFilterGroup, + + stringFieldConstraint, + numberFieldConstraint, + checkboxFieldConstraint, + attachmentFieldConstraint, + buttonFieldOption, + + referenceFieldConstraint, + referenceFieldOption, + rollupFieldOption, + + selectFieldOption, + selectFieldConstraint, + + ratingFieldConstraint, + emailFieldConstraint, + urlFieldConstraint, + dateFieldConstraint, + jsonFieldConstraint, + userFieldConstraint, + longTextFieldConstraint, + currencyFieldConstraint, + currencyFieldOption, + durationFieldConstraint, + percentageFieldConstraint, + }, }) diff --git a/packages/template/src/service/index.ts b/packages/template/src/service/index.ts new file mode 100644 index 000000000..6da5aabb7 --- /dev/null +++ b/packages/template/src/service/index.ts @@ -0,0 +1 @@ +export * from "./template.service" diff --git a/packages/template/src/service/template.service.ts b/packages/template/src/service/template.service.ts new file mode 100644 index 000000000..fe7615078 --- /dev/null +++ b/packages/template/src/service/template.service.ts @@ -0,0 +1,15 @@ +import { singleton } from "@undb/di" +import { createLogger } from "@undb/logger" +import type { IBaseTemplateDTO } from "../dto" + +export interface ITemplateService { + create(dto: IBaseTemplateDTO): Promise +} + +@singleton() +export class TemplateService implements ITemplateService { + private readonly logger = createLogger(TemplateService.name) + async create(dto: IBaseTemplateDTO): Promise { + this.logger.info(dto) + } +} diff --git a/packages/template/src/templates/test.base.json b/packages/template/src/templates/test.base.json new file mode 100644 index 000000000..c48783698 --- /dev/null +++ b/packages/template/src/templates/test.base.json @@ -0,0 +1,31 @@ +{ + "name": "hello", + "tables": { + "world": { + "schema": { + "name": { + "type": "string", + "constraint": { + "max": 10 + }, + "defaultValue": "world", + "display": true + }, + "age": { + "type": "number", + "constraint": { + "min": 0 + } + }, + "parent": { + "type": "user", + "defaultValue": "@me" + }, + "isActive": { + "type": "checkbox", + "defaultValue": true + } + } + } + } +} diff --git a/packages/template/src/templates/test.json b/packages/template/src/templates/test.json deleted file mode 100644 index 95887156b..000000000 --- a/packages/template/src/templates/test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "hello", - "tables": { - "world": { - "schema": { - "name": { - "type": "string", - "constraint": { - "max": 10 - }, - "defaultValue": "world", - "display": true - } - } - } - } -} diff --git a/packages/trpc/src/router.ts b/packages/trpc/src/router.ts index d6257bb1e..85f200e06 100644 --- a/packages/trpc/src/router.ts +++ b/packages/trpc/src/router.ts @@ -4,7 +4,7 @@ import { BulkUpdateRecordsCommand, CreateApiTokenCommand, CreateBaseCommand, - CreateFromTemplateCommand, + CreateFromShareCommand, CreateRecordCommand, CreateRecordsCommand, CreateSpaceCommand, @@ -55,7 +55,7 @@ import { bulkduplicateRecordsCommand, createApiTokenCommand, createBaseCommand, - createFromTemplateCommand, + createFromShareCommand, createRecordCommand, createRecordsCommand, createSpaceCommand, @@ -106,9 +106,9 @@ import { updateaccountCommand, } from "@undb/commands" import { getCurrentSpaceId } from "@undb/context/server" -import { CommandBus,QueryBus } from "@undb/cqrs" +import { CommandBus, QueryBus } from "@undb/cqrs" import { container } from "@undb/di" -import type { ICommandBus,IQueryBus } from "@undb/domain" +import type { ICommandBus, IQueryBus } from "@undb/domain" import { CountRecordsQuery, GetAggregatesQuery, @@ -136,7 +136,7 @@ import { import { tableDTO } from "@undb/table" import { z } from "@undb/zod" import { authz } from "./authz.middleware" -import { privateProcedure,publicProcedure,t } from "./trpc" +import { privateProcedure, publicProcedure, t } from "./trpc" const commandBus = container.resolve(CommandBus) const queryBus = container.resolve(QueryBus) @@ -361,11 +361,11 @@ const baseRouter = t.router({ } return commandBus.execute(new CreateBaseCommand({ ...input, spaceId })) }), - createFromTemplate: privateProcedure + createFromShare: privateProcedure // check authz in handler, because we can create base to another space // .use(authz("base:create")) - .input(createFromTemplateCommand) - .mutation(({ input }) => commandBus.execute(new CreateFromTemplateCommand(input))), + .input(createFromShareCommand) + .mutation(({ input }) => commandBus.execute(new CreateFromShareCommand(input))), duplicate: privateProcedure .use(authz("base:create")) .input(duplicateBaseCommand) From b106abfec6331578e7363714156ad3d889c38c9e Mon Sep 17 00:00:00 2001 From: nichenqin Date: Sat, 21 Sep 2024 20:46:14 +0800 Subject: [PATCH 4/6] feat: create from template --- .../components/blocks/nav/nav-tools.svelte | 25 ++++++++++ packages/command-handlers/package.json | 1 + .../create-from-template.command-handler.ts | 31 ++++++++++++ .../command-handlers/src/handlers/index.ts | 2 + .../src/create-from-template.command.ts | 24 ++++++++++ packages/commands/src/create-table.command.ts | 5 +- packages/commands/src/index.ts | 1 + .../persistence/src/table/table.repository.ts | 6 +++ packages/table/src/dto/create-table.dto.ts | 5 +- packages/table/src/table.repository.ts | 2 + packages/template/src/dto/template.dto.ts | 27 +++++++---- packages/template/src/index.ts | 1 + packages/template/src/service/index.ts | 1 + .../src/service/template.service.provider.ts | 6 +++ .../template/src/service/template.service.ts | 25 +++++++++- packages/template/src/template.factory.ts | 27 +++++++++++ packages/template/src/templates/index.ts | 6 +++ .../template/src/templates/test.base.json | 47 ++++++++++--------- packages/template/tsconfig.json | 4 +- packages/trpc/package.json | 1 + packages/trpc/src/router.ts | 16 ++++++- 21 files changed, 223 insertions(+), 40 deletions(-) create mode 100644 packages/command-handlers/src/handlers/create-from-template.command-handler.ts create mode 100644 packages/commands/src/create-from-template.command.ts create mode 100644 packages/template/src/service/template.service.provider.ts create mode 100644 packages/template/src/template.factory.ts create mode 100644 packages/template/src/templates/index.ts diff --git a/apps/frontend/src/lib/components/blocks/nav/nav-tools.svelte b/apps/frontend/src/lib/components/blocks/nav/nav-tools.svelte index ec025fbdf..9cd2cbc24 100644 --- a/apps/frontend/src/lib/components/blocks/nav/nav-tools.svelte +++ b/apps/frontend/src/lib/components/blocks/nav/nav-tools.svelte @@ -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]}`) + } + }, + })

diff --git a/packages/command-handlers/package.json b/packages/command-handlers/package.json index bd9085882..3aae4ceed 100644 --- a/packages/command-handlers/package.json +++ b/packages/command-handlers/package.json @@ -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" diff --git a/packages/command-handlers/src/handlers/create-from-template.command-handler.ts b/packages/command-handlers/src/handlers/create-from-template.command-handler.ts new file mode 100644 index 000000000..9f93951f6 --- /dev/null +++ b/packages/command-handlers/src/handlers/create-from-template.command-handler.ts @@ -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 +{ + private readonly logger = createLogger(CreateFromTemplateCommandHandler.name) + + constructor( + @injectTemplateService() + private readonly templateService: ITemplateService, + ) {} + + async execute(command: CreateFromTemplateCommand): Promise { + 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) } + } +} diff --git a/packages/command-handlers/src/handlers/index.ts b/packages/command-handlers/src/handlers/index.ts index 1f6853ae4..0be613430 100644 --- a/packages/command-handlers/src/handlers/index.ts +++ b/packages/command-handlers/src/handlers/index.ts @@ -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" @@ -106,4 +107,5 @@ export const commandHandlers = [ SubmitFormCommandHandler, SetFieldWidthCommandHandler, DuplicateTableFormCommandHandler, + CreateFromTemplateCommandHandler, ] diff --git a/packages/commands/src/create-from-template.command.ts b/packages/commands/src/create-from-template.command.ts new file mode 100644 index 000000000..316aa444d --- /dev/null +++ b/packages/commands/src/create-from-template.command.ts @@ -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 + +export const createFromTemplateCommandOutput = z.object({ + baseIds: z.array(baseIdSchema), +}) + +export type ICreateFromTemplateCommandOutput = z.infer + +export class CreateFromTemplateCommand extends Command implements ICreateFromTemplateCommand { + public readonly templateName: string + + constructor(props: CommandProps) { + super(props) + this.templateName = props.templateName + } +} diff --git a/packages/commands/src/create-table.command.ts b/packages/commands/src/create-table.command.ts index 3ef358baa..5287c13c5 100644 --- a/packages/commands/src/create-table.command.ts +++ b/packages/commands/src/create-table.command.ts @@ -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 diff --git a/packages/commands/src/index.ts b/packages/commands/src/index.ts index b3d2df428..adfca09be 100644 --- a/packages/commands/src/index.ts +++ b/packages/commands/src/index.ts @@ -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" diff --git a/packages/persistence/src/table/table.repository.ts b/packages/persistence/src/table/table.repository.ts index 9f2eaa58e..8dc23e877 100644 --- a/packages/persistence/src/table/table.repository.ts +++ b/packages/persistence/src/table/table.repository.ts @@ -106,6 +106,12 @@ export class TableRepository implements ITableRepository { await this.outboxService.save(table) } + async insertMany(tables: TableDo[]): Promise { + for (const table of tables) { + await this.insert(table) + } + } + async bulkUpdate(updates: { table: TableDo; spec: Option }[]): Promise { for (const update of updates) { await this.#updateOneById(update.table, update.spec) diff --git a/packages/table/src/dto/create-table.dto.ts b/packages/table/src/dto/create-table.dto.ts index f323f5bf6..245b9ced3 100644 --- a/packages/table/src/dto/create-table.dto.ts +++ b/packages/table/src/dto/create-table.dto.ts @@ -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" @@ -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, diff --git a/packages/table/src/table.repository.ts b/packages/table/src/table.repository.ts index a81ea405c..60230e4e0 100644 --- a/packages/table/src/table.repository.ts +++ b/packages/table/src/table.repository.ts @@ -6,8 +6,10 @@ import type { TableDo } from "./table.do" export interface ITableRepository { insert(table: TableDo): Promise + insertMany(tables: TableDo[]): Promise updateOneById(table: TableDo, spec: Option): Promise bulkUpdate(updates: { table: TableDo; spec: Option }[]): Promise + deleteOneById(table: TableDo): Promise find(spec: Option, ignoreSpace?: boolean): Promise diff --git a/packages/template/src/dto/template.dto.ts b/packages/template/src/dto/template.dto.ts index a36cfc1e3..d979de096 100644 --- a/packages/template/src/dto/template.dto.ts +++ b/packages/template/src/dto/template.dto.ts @@ -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 + +export const tableTemplateDTO = z + .object({ + name: tableName, + }) + .merge(basicTemplateTableDTO) + +export type ITableTemplateDTO = z.infer diff --git a/packages/template/src/index.ts b/packages/template/src/index.ts index b349bab42..fa809484b 100644 --- a/packages/template/src/index.ts +++ b/packages/template/src/index.ts @@ -1,3 +1,4 @@ export * from "./dto" export * from "./schema" export * from "./service" +export * from "./templates" diff --git a/packages/template/src/service/index.ts b/packages/template/src/service/index.ts index 6da5aabb7..169ce6f84 100644 --- a/packages/template/src/service/index.ts +++ b/packages/template/src/service/index.ts @@ -1 +1,2 @@ export * from "./template.service" +export * from "./template.service.provider" diff --git a/packages/template/src/service/template.service.provider.ts b/packages/template/src/service/template.service.provider.ts new file mode 100644 index 000000000..2586c7df4 --- /dev/null +++ b/packages/template/src/service/template.service.provider.ts @@ -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 }) diff --git a/packages/template/src/service/template.service.ts b/packages/template/src/service/template.service.ts index fe7615078..1d98bea5f 100644 --- a/packages/template/src/service/template.service.ts +++ b/packages/template/src/service/template.service.ts @@ -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 + 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 { + + 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 } } diff --git a/packages/template/src/template.factory.ts b/packages/template/src/template.factory.ts new file mode 100644 index 000000000..c8a93001b --- /dev/null +++ b/packages/template/src/template.factory.ts @@ -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 + } +} diff --git a/packages/template/src/templates/index.ts b/packages/template/src/templates/index.ts new file mode 100644 index 000000000..53e7c2f17 --- /dev/null +++ b/packages/template/src/templates/index.ts @@ -0,0 +1,6 @@ +import type { IBaseTemplateDTO } from "../dto" +import { default as test } from "./test.base.json" + +const templates: Record = { test } as const + +export { templates } diff --git a/packages/template/src/templates/test.base.json b/packages/template/src/templates/test.base.json index c48783698..6fe83d4f2 100644 --- a/packages/template/src/templates/test.base.json +++ b/packages/template/src/templates/test.base.json @@ -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 } } } diff --git a/packages/template/tsconfig.json b/packages/template/tsconfig.json index 238655f2c..34ae0fe3d 100644 --- a/packages/template/tsconfig.json +++ b/packages/template/tsconfig.json @@ -22,6 +22,8 @@ // Some stricter flags (disabled by default) "noUnusedLocals": false, "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false + "noPropertyAccessFromIndexSignature": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true } } diff --git a/packages/trpc/package.json b/packages/trpc/package.json index a19dd241d..b6d4e771e 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -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" } diff --git a/packages/trpc/src/router.ts b/packages/trpc/src/router.ts index 85f200e06..48e2f6920 100644 --- a/packages/trpc/src/router.ts +++ b/packages/trpc/src/router.ts @@ -5,6 +5,7 @@ import { CreateApiTokenCommand, CreateBaseCommand, CreateFromShareCommand, + CreateFromTemplateCommand, CreateRecordCommand, CreateRecordsCommand, CreateSpaceCommand, @@ -56,6 +57,8 @@ import { createApiTokenCommand, createBaseCommand, createFromShareCommand, + createFromTemplateCommand, + createFromTemplateCommandOutput, createRecordCommand, createRecordsCommand, createSpaceCommand, @@ -425,18 +428,26 @@ const apiTokenRouter = t.router({ const spaceRouter = t.router({ list: privateProcedure - .input(getMemberSpacesQuery) .use(authz("space:list")) + .input(getMemberSpacesQuery) .query(({ input }) => queryBus.execute(new GetMemberSpacesQuery(input))), create: privateProcedure .input(createSpaceCommand) .mutation(({ input }) => commandBus.execute(new CreateSpaceCommand(input))), update: privateProcedure - .input(updateSpaceCommand) .use(authz("space:update")) + .input(updateSpaceCommand) .mutation(({ input }) => commandBus.execute(new UpdateSpaceCommand(input))), }) +const templateRouter = t.router({ + createFromTemplate: privateProcedure + .use(authz("base:create")) + .input(createFromTemplateCommand) + .output(createFromTemplateCommandOutput) + .mutation(({ input }) => commandBus.execute(new CreateFromTemplateCommand(input))), +}) + export const route = t.router({ table: tableRouter, record: recordRouter, @@ -448,6 +459,7 @@ export const route = t.router({ space: spaceRouter, apiToken: apiTokenRouter, shareData: shareDataRouter, + template: templateRouter, }) export type AppRouter = typeof route From 68c52912b151579a7e8c205d59235704f3a8fea5 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Sat, 21 Sep 2024 20:52:35 +0800 Subject: [PATCH 5/6] chore: fix ts issue --- packages/template/src/templates/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/template/src/templates/index.ts b/packages/template/src/templates/index.ts index 53e7c2f17..f12a7b369 100644 --- a/packages/template/src/templates/index.ts +++ b/packages/template/src/templates/index.ts @@ -1,6 +1,6 @@ import type { IBaseTemplateDTO } from "../dto" import { default as test } from "./test.base.json" -const templates: Record = { test } as const +const templates = { test } as Record export { templates } From 6abc7b80345d6c39e6e76578c0d52a41244968a0 Mon Sep 17 00:00:00 2001 From: GitHub actions Date: Sat, 21 Sep 2024 12:53:25 +0000 Subject: [PATCH 6/6] Prepare release v1.0.0-84 --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ee7ce5f5..65bcea585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v1.0.0-84 + + +### 🏡 Chore + +- Fix ts issue ([68c5291](https://github.com/undb-io/undb/commit/68c5291)) + +### ❤️ Contributors + +- Nichenqin ([@nichenqin](http://github.com/nichenqin)) + ## v1.0.0-83 diff --git a/package.json b/package.json index 1f64171f0..49f8107f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "undb", - "version": "1.0.0-83", + "version": "1.0.0-84", "private": true, "scripts": { "build": "NODE_ENV=production bun --bun turbo build",