mirror of https://github.com/buster-so/buster.git
Add docs API endpoints and database schema
- Introduced new API routes for managing documents, including listing, creating, updating, and deleting documents. - Implemented database queries for document operations. - Added validation schemas for request and response types using Zod. - Updated the database schema to include a 'docs' table with necessary constraints. - Integrated the new docs functionality into the server and shared packages.
This commit is contained in:
parent
cae94ae56a
commit
d17c21b2b7
|
@ -0,0 +1,44 @@
|
|||
import type { User } from '@buster/database';
|
||||
import { getUserOrganizationId, listDocs } from '@buster/database';
|
||||
import type { GetDocsListRequest, GetDocsListResponse } from '@buster/server-shared/docs';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
||||
export async function listDocsHandler(
|
||||
request: GetDocsListRequest,
|
||||
user: User
|
||||
): Promise<GetDocsListResponse> {
|
||||
const { page, page_size, type, search } = request;
|
||||
|
||||
const userToOrg = await getUserOrganizationId(user.id);
|
||||
|
||||
if (!userToOrg) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not associated with an organization',
|
||||
});
|
||||
}
|
||||
|
||||
const result = await listDocs({
|
||||
organizationId: userToOrg.organizationId,
|
||||
type: type as 'analyst' | 'normal' | undefined,
|
||||
search,
|
||||
page,
|
||||
pageSize: page_size,
|
||||
});
|
||||
|
||||
return {
|
||||
data: result.data.map((doc) => ({
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
content: doc.content,
|
||||
type: doc.type as 'analyst' | 'normal',
|
||||
organizationId: doc.organizationId,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
deletedAt: doc.deletedAt,
|
||||
})),
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
page_size: result.pageSize,
|
||||
total_pages: result.totalPages,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import type { User } from '@buster/database';
|
||||
import { getUserOrganizationId, upsertDoc } from '@buster/database';
|
||||
import type { CreateDocRequest, CreateDocResponse } from '@buster/server-shared/docs';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
||||
export async function createDocHandler(
|
||||
request: CreateDocRequest,
|
||||
user: User
|
||||
): Promise<CreateDocResponse> {
|
||||
try {
|
||||
const { name, content, type } = request;
|
||||
|
||||
const userToOrg = await getUserOrganizationId(user.id);
|
||||
|
||||
if (!userToOrg) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not associated with an organization',
|
||||
});
|
||||
}
|
||||
|
||||
if (userToOrg.role !== 'workspace_admin' && userToOrg.role !== 'data_admin') {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not an admin',
|
||||
});
|
||||
}
|
||||
|
||||
const doc = await upsertDoc({
|
||||
name,
|
||||
content,
|
||||
type,
|
||||
organizationId: userToOrg.organizationId,
|
||||
});
|
||||
|
||||
if (!doc) {
|
||||
throw new HTTPException(400, {
|
||||
message: 'Failed to create doc',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
content: doc.content,
|
||||
type: doc.type as 'analyst' | 'normal',
|
||||
organizationId: doc.organizationId,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
deletedAt: doc.deletedAt,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error creating doc:', error);
|
||||
throw new HTTPException(500, {
|
||||
message: 'Failed to create doc',
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import type { User } from '@buster/database';
|
||||
import { deleteDoc, getUserOrganizationId } from '@buster/database';
|
||||
import type { DeleteDocResponse } from '@buster/server-shared/docs';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
||||
export async function deleteDocHandler(docId: string, user: User): Promise<DeleteDocResponse> {
|
||||
const userToOrg = await getUserOrganizationId(user.id);
|
||||
|
||||
if (!userToOrg) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not associated with an organization',
|
||||
});
|
||||
}
|
||||
|
||||
if (userToOrg.role !== 'workspace_admin' && userToOrg.role !== 'data_admin') {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not an admin',
|
||||
});
|
||||
}
|
||||
|
||||
const doc = await deleteDoc({
|
||||
id: docId,
|
||||
organizationId: userToOrg.organizationId,
|
||||
});
|
||||
|
||||
if (!doc) {
|
||||
throw new HTTPException(404, { message: 'Document not found' });
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Document deleted successfully',
|
||||
};
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import type { User } from '@buster/database';
|
||||
import { getDoc, getUserOrganizationId } from '@buster/database';
|
||||
import type { GetDocResponse } from '@buster/server-shared/docs';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
||||
export async function getDocHandler(docId: string, user: User): Promise<GetDocResponse> {
|
||||
const userToOrg = await getUserOrganizationId(user.id);
|
||||
|
||||
if (!userToOrg) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not associated with an organization',
|
||||
});
|
||||
}
|
||||
|
||||
const doc = await getDoc({
|
||||
id: docId,
|
||||
organizationId: userToOrg.organizationId,
|
||||
});
|
||||
|
||||
if (!doc) {
|
||||
throw new HTTPException(404, { message: 'Document not found' });
|
||||
}
|
||||
|
||||
return {
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
content: doc.content,
|
||||
type: doc.type as 'analyst' | 'normal',
|
||||
organizationId: doc.organizationId,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
deletedAt: doc.deletedAt,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import type { User } from '@buster/database';
|
||||
import { getUserOrganizationId, updateDoc } from '@buster/database';
|
||||
import type { UpdateDocRequest, UpdateDocResponse } from '@buster/server-shared/docs';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
||||
export async function updateDocHandler(
|
||||
docId: string,
|
||||
request: UpdateDocRequest,
|
||||
user: User
|
||||
): Promise<UpdateDocResponse> {
|
||||
const { name, content, type } = request;
|
||||
|
||||
const userToOrg = await getUserOrganizationId(user.id);
|
||||
|
||||
if (!userToOrg) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not associated with an organization',
|
||||
});
|
||||
}
|
||||
|
||||
if (userToOrg.role !== 'workspace_admin' && userToOrg.role !== 'data_admin') {
|
||||
throw new HTTPException(403, {
|
||||
message: 'User is not an admin',
|
||||
});
|
||||
}
|
||||
|
||||
const doc = await updateDoc({
|
||||
id: docId,
|
||||
organizationId: userToOrg.organizationId,
|
||||
name,
|
||||
content,
|
||||
type: type as 'analyst' | 'normal' | undefined,
|
||||
});
|
||||
|
||||
if (!doc) {
|
||||
throw new HTTPException(404, { message: 'Document not found' });
|
||||
}
|
||||
|
||||
return {
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
content: doc.content,
|
||||
type: doc.type as 'analyst' | 'normal',
|
||||
organizationId: doc.organizationId,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
deletedAt: doc.deletedAt,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
import {
|
||||
CreateDocRequestSchema,
|
||||
GetDocByIdParamsSchema,
|
||||
GetDocsListRequestSchema,
|
||||
UpdateDocRequestSchema,
|
||||
} from '@buster/server-shared/docs';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { Hono } from 'hono';
|
||||
import { requireAuth } from '../../../middleware/auth';
|
||||
import { standardErrorHandler } from '../../../utils/response';
|
||||
import { listDocsHandler } from './GET';
|
||||
import { createDocHandler } from './POST';
|
||||
import { deleteDocHandler } from './id/DELETE';
|
||||
import { getDocHandler } from './id/GET';
|
||||
import { updateDocHandler } from './id/PUT';
|
||||
|
||||
const app = new Hono()
|
||||
.use('*', requireAuth)
|
||||
|
||||
// GET /docs - List all docs
|
||||
.get('/', zValidator('query', GetDocsListRequestSchema), async (c) => {
|
||||
const request = c.req.valid('query');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await listDocsHandler(request, user);
|
||||
return c.json(response);
|
||||
})
|
||||
|
||||
// POST /docs - Create new doc (upsert)
|
||||
.post('/', zValidator('json', CreateDocRequestSchema), async (c) => {
|
||||
const request = c.req.valid('json');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await createDocHandler(request, user);
|
||||
return c.json(response);
|
||||
})
|
||||
|
||||
// GET /docs/:id - Get single doc
|
||||
.get('/:id', zValidator('param', GetDocByIdParamsSchema), async (c) => {
|
||||
const params = c.req.valid('param');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await getDocHandler(params.id, user);
|
||||
return c.json(response);
|
||||
})
|
||||
|
||||
// PUT /docs/:id - Update doc
|
||||
.put(
|
||||
'/:id',
|
||||
zValidator('param', GetDocByIdParamsSchema),
|
||||
zValidator('json', UpdateDocRequestSchema),
|
||||
async (c) => {
|
||||
const params = c.req.valid('param');
|
||||
const request = c.req.valid('json');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await updateDocHandler(params.id, request, user);
|
||||
return c.json(response);
|
||||
}
|
||||
)
|
||||
|
||||
// PATCH /docs/:id - Update doc (same as PUT)
|
||||
.patch(
|
||||
'/:id',
|
||||
zValidator('param', GetDocByIdParamsSchema),
|
||||
zValidator('json', UpdateDocRequestSchema),
|
||||
async (c) => {
|
||||
const params = c.req.valid('param');
|
||||
const request = c.req.valid('json');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await updateDocHandler(params.id, request, user);
|
||||
return c.json(response);
|
||||
}
|
||||
)
|
||||
|
||||
// DELETE /docs/:id - Soft delete doc
|
||||
.delete('/:id', zValidator('param', GetDocByIdParamsSchema), async (c) => {
|
||||
const params = c.req.valid('param');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await deleteDocHandler(params.id, user);
|
||||
return c.json(response);
|
||||
})
|
||||
|
||||
.onError(standardErrorHandler);
|
||||
|
||||
export default app;
|
|
@ -5,6 +5,7 @@ import authRoutes from './auth';
|
|||
import chatsRoutes from './chats';
|
||||
import datasetsRoutes from './datasets';
|
||||
import dictionariesRoutes from './dictionaries';
|
||||
import docsRoutes from './docs';
|
||||
import electricShapeRoutes from './electric-shape';
|
||||
import githubRoutes from './github';
|
||||
import metricFilesRoutes from './metric_files';
|
||||
|
@ -22,6 +23,7 @@ const app = new Hono()
|
|||
.route('/auth', authRoutes)
|
||||
.route('/users', userRoutes)
|
||||
.route('/datasets', datasetsRoutes)
|
||||
.route('/docs', docsRoutes)
|
||||
.route('/electric-shape', electricShapeRoutes)
|
||||
.route('/healthcheck', healthcheckRoutes)
|
||||
.route('/chats', chatsRoutes)
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
CREATE TYPE "public"."docs_type_enum" AS ENUM('analyst', 'normal');--> statement-breakpoint
|
||||
CREATE TABLE "docs" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"content" text NOT NULL,
|
||||
"type" "docs_type_enum" DEFAULT 'normal' NOT NULL,
|
||||
"organization_id" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"deleted_at" timestamp with time zone
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "docs" ADD CONSTRAINT "docs_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "docs" ADD CONSTRAINT "docs_name_organization_id_key" UNIQUE("name","organization_id");
|
File diff suppressed because it is too large
Load Diff
|
@ -652,6 +652,13 @@
|
|||
"when": 1757364170176,
|
||||
"tag": "0092_high_wendell_vaughn",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 93,
|
||||
"version": "7",
|
||||
"when": 1757366674063,
|
||||
"tag": "0093_friendly_puff_adder",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { and, eq, isNull } from 'drizzle-orm';
|
||||
import { db } from '../../connection';
|
||||
import { docs } from '../../schema';
|
||||
|
||||
export interface DeleteDocParams {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
}
|
||||
|
||||
export async function deleteDoc(params: DeleteDocParams) {
|
||||
const { id, organizationId } = params;
|
||||
|
||||
// Soft delete by setting deletedAt
|
||||
const [deletedDoc] = await db
|
||||
.update(docs)
|
||||
.set({
|
||||
deletedAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
})
|
||||
.where(and(eq(docs.id, id), eq(docs.organizationId, organizationId), isNull(docs.deletedAt)))
|
||||
.returning();
|
||||
|
||||
return deletedDoc || null;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { and, eq, isNull } from 'drizzle-orm';
|
||||
import { db } from '../../connection';
|
||||
import { docs } from '../../schema';
|
||||
|
||||
export interface GetDocParams {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
}
|
||||
|
||||
export async function getDoc(params: GetDocParams) {
|
||||
const { id, organizationId } = params;
|
||||
|
||||
const [doc] = await db
|
||||
.select()
|
||||
.from(docs)
|
||||
.where(and(eq(docs.id, id), eq(docs.organizationId, organizationId), isNull(docs.deletedAt)))
|
||||
.limit(1);
|
||||
|
||||
return doc || null;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export * from './upsert-doc';
|
||||
export * from './get-doc';
|
||||
export * from './list-docs';
|
||||
export * from './update-doc';
|
||||
export * from './delete-doc';
|
|
@ -0,0 +1,53 @@
|
|||
import { and, eq, isNull, like, sql } from 'drizzle-orm';
|
||||
import { db } from '../../connection';
|
||||
import { docs } from '../../schema';
|
||||
|
||||
export interface ListDocsParams {
|
||||
organizationId: string;
|
||||
type?: 'analyst' | 'normal';
|
||||
search?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export async function listDocs(params: ListDocsParams) {
|
||||
const { organizationId, type, search, page = 1, pageSize = 20 } = params;
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
// Build where conditions
|
||||
const conditions = [eq(docs.organizationId, organizationId), isNull(docs.deletedAt)];
|
||||
|
||||
if (type) {
|
||||
conditions.push(eq(docs.type, type));
|
||||
}
|
||||
|
||||
if (search) {
|
||||
conditions.push(like(docs.name, `%${search}%`));
|
||||
}
|
||||
|
||||
// Get total count
|
||||
const [countResult] = await db
|
||||
.select({ count: sql<number>`count(*)::int` })
|
||||
.from(docs)
|
||||
.where(and(...conditions));
|
||||
|
||||
const count = countResult?.count ?? 0;
|
||||
|
||||
// Get paginated results
|
||||
const results = await db
|
||||
.select()
|
||||
.from(docs)
|
||||
.where(and(...conditions))
|
||||
.orderBy(docs.updatedAt)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return {
|
||||
data: results,
|
||||
total: count,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages: Math.ceil(count / pageSize),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { and, eq, isNull } from 'drizzle-orm';
|
||||
import { db } from '../../connection';
|
||||
import { docs } from '../../schema';
|
||||
|
||||
export interface UpdateDocParams {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name?: string;
|
||||
content?: string;
|
||||
type?: 'analyst' | 'normal';
|
||||
}
|
||||
|
||||
export async function updateDoc(params: UpdateDocParams) {
|
||||
const { id, organizationId, ...updates } = params;
|
||||
|
||||
// Filter out undefined values
|
||||
const updateData: Record<string, string> = {};
|
||||
if (updates.name !== undefined) updateData.name = updates.name;
|
||||
if (updates.content !== undefined) updateData.content = updates.content;
|
||||
if (updates.type !== undefined) updateData.type = updates.type;
|
||||
|
||||
// Always update updatedAt
|
||||
updateData.updatedAt = new Date().toISOString();
|
||||
|
||||
const [updatedDoc] = await db
|
||||
.update(docs)
|
||||
.set(updateData)
|
||||
.where(and(eq(docs.id, id), eq(docs.organizationId, organizationId), isNull(docs.deletedAt)))
|
||||
.returning();
|
||||
|
||||
return updatedDoc || null;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import { and, eq, isNull } from 'drizzle-orm';
|
||||
import { z } from 'zod';
|
||||
import { db } from '../../connection';
|
||||
import { docs } from '../../schema';
|
||||
|
||||
export const UpsertDocSchema = z.object({
|
||||
name: z.string().min(1).max(255),
|
||||
content: z.string(),
|
||||
type: z.enum(['analyst', 'normal']),
|
||||
organizationId: z.string().uuid(),
|
||||
});
|
||||
|
||||
export type UpsertDocParams = z.infer<typeof UpsertDocSchema>;
|
||||
|
||||
export async function upsertDoc(params: UpsertDocParams) {
|
||||
const { name, content, type = 'normal', organizationId } = params;
|
||||
|
||||
try {
|
||||
// Update existing doc and unmark deleted_at if it was soft deleted
|
||||
const [updatedDoc] = await db
|
||||
.insert(docs)
|
||||
.values({
|
||||
name,
|
||||
content,
|
||||
type,
|
||||
organizationId,
|
||||
updatedAt: new Date().toISOString(),
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: [docs.name, docs.organizationId],
|
||||
set: {
|
||||
content,
|
||||
type,
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null, // Unmark soft delete
|
||||
},
|
||||
})
|
||||
.returning();
|
||||
|
||||
return updatedDoc;
|
||||
} catch (error) {
|
||||
console.error('Error upserting doc:', error);
|
||||
throw new Error('Failed to upsert doc');
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ export * from './dashboards';
|
|||
export * from './metrics';
|
||||
export * from './collections';
|
||||
export * from './reports';
|
||||
export * from './docs';
|
||||
export * from './s3-integrations';
|
||||
export * from './vault';
|
||||
export * from './cascading-permissions';
|
||||
|
|
|
@ -35,4 +35,3 @@ export type UserOrganizationRole =
|
|||
| 'querier'
|
||||
| 'restricted_querier'
|
||||
| 'viewer';
|
||||
|
||||
|
|
|
@ -2315,5 +2315,6 @@ export const docs = pgTable(
|
|||
foreignColumns: [organizations.id],
|
||||
name: 'docs_organization_id_fkey',
|
||||
}).onDelete('cascade'),
|
||||
unique('docs_name_organization_id_key').on(table.name, table.organizationId),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const DocTypeSchema = z.enum(['analyst', 'normal']);
|
||||
|
||||
export type DocType = z.infer<typeof DocTypeSchema>;
|
|
@ -32,6 +32,10 @@
|
|||
"types": "./dist/dashboards/index.d.ts",
|
||||
"default": "./dist/dashboards/index.js"
|
||||
},
|
||||
"./docs": {
|
||||
"types": "./dist/docs/index.d.ts",
|
||||
"default": "./dist/docs/index.js"
|
||||
},
|
||||
"./github": {
|
||||
"types": "./dist/github/index.d.ts",
|
||||
"default": "./dist/github/index.js"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export * from './types';
|
||||
export * from './requests';
|
||||
export * from './responses';
|
|
@ -0,0 +1,29 @@
|
|||
import { z } from 'zod';
|
||||
import { PaginatedRequestSchema } from '../type-utilities/pagination';
|
||||
import { DocsTypeEnum } from './types';
|
||||
|
||||
export const CreateDocRequestSchema = z.object({
|
||||
name: z.string().min(1).max(255),
|
||||
content: z.string(),
|
||||
type: DocsTypeEnum,
|
||||
});
|
||||
|
||||
export const UpdateDocRequestSchema = z.object({
|
||||
name: z.string().min(1).max(255).optional(),
|
||||
content: z.string().optional(),
|
||||
type: DocsTypeEnum.optional(),
|
||||
});
|
||||
|
||||
export const GetDocsListRequestSchema = PaginatedRequestSchema.extend({
|
||||
type: DocsTypeEnum.optional(),
|
||||
search: z.string().optional(),
|
||||
});
|
||||
|
||||
export const GetDocByIdParamsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
});
|
||||
|
||||
export type CreateDocRequest = z.infer<typeof CreateDocRequestSchema>;
|
||||
export type UpdateDocRequest = z.infer<typeof UpdateDocRequestSchema>;
|
||||
export type GetDocsListRequest = z.infer<typeof GetDocsListRequestSchema>;
|
||||
export type GetDocByIdParams = z.infer<typeof GetDocByIdParamsSchema>;
|
|
@ -0,0 +1,27 @@
|
|||
import { z } from 'zod';
|
||||
import { DocSchema } from './types';
|
||||
|
||||
export const GetDocResponseSchema = DocSchema;
|
||||
|
||||
export const CreateDocResponseSchema = DocSchema;
|
||||
|
||||
export const UpdateDocResponseSchema = DocSchema;
|
||||
|
||||
export const DeleteDocResponseSchema = z.object({
|
||||
success: z.boolean(),
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
export const GetDocsListResponseSchema = z.object({
|
||||
data: z.array(DocSchema),
|
||||
total: z.number(),
|
||||
page: z.number(),
|
||||
page_size: z.number(),
|
||||
total_pages: z.number(),
|
||||
});
|
||||
|
||||
export type GetDocResponse = z.infer<typeof GetDocResponseSchema>;
|
||||
export type CreateDocResponse = z.infer<typeof CreateDocResponseSchema>;
|
||||
export type UpdateDocResponse = z.infer<typeof UpdateDocResponseSchema>;
|
||||
export type DeleteDocResponse = z.infer<typeof DeleteDocResponseSchema>;
|
||||
export type GetDocsListResponse = z.infer<typeof GetDocsListResponseSchema>;
|
|
@ -0,0 +1,18 @@
|
|||
import { docsTypeEnum } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const DocsTypeEnum = z.enum(docsTypeEnum.enumValues);
|
||||
export type DocsType = z.infer<typeof DocsTypeEnum>;
|
||||
|
||||
export const DocSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
content: z.string(),
|
||||
type: DocsTypeEnum,
|
||||
organizationId: z.string().uuid(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
deletedAt: z.string().nullable(),
|
||||
});
|
||||
|
||||
export type Doc = z.infer<typeof DocSchema>;
|
|
@ -10,6 +10,7 @@ export * from './chats';
|
|||
export * from './dashboards';
|
||||
export * from './datasets';
|
||||
export * from './dictionary';
|
||||
export * from './docs';
|
||||
export * from './github';
|
||||
export * from './message';
|
||||
export * from './metrics';
|
||||
|
|
Loading…
Reference in New Issue