diff --git a/apps/backend/src/modules/file/storage/local-object-storage.ts b/apps/backend/src/modules/file/storage/local-object-storage.ts index a7f65a84c..4a91b2dc4 100644 --- a/apps/backend/src/modules/file/storage/local-object-storage.ts +++ b/apps/backend/src/modules/file/storage/local-object-storage.ts @@ -1,4 +1,5 @@ import { singleton } from "@undb/di" +import { env } from "@undb/env" import { IObjectStorage, IPresign, IPutObject } from "@undb/table" import { nanoid } from "nanoid" import * as path from "node:path" @@ -22,7 +23,7 @@ export class LocalObjectStorage implements IObjectStorage { } } async getPreviewUrl(fileName: string): Promise { - return "/public/" + fileName + return env.UNDB_BASE_URL + "/public/" + fileName } async put(buffer: Buffer, path: string, originalname: string, mimeType: string): Promise { await Bun.write(`./.undb/storage/${path ? path + "/" : ""}${originalname}`, buffer) diff --git a/apps/backend/src/modules/openapi/openapi.ts b/apps/backend/src/modules/openapi/openapi.ts index 7075674ca..c90ab875b 100644 --- a/apps/backend/src/modules/openapi/openapi.ts +++ b/apps/backend/src/modules/openapi/openapi.ts @@ -13,17 +13,17 @@ import { import { executionContext, getCurrentUserId, setContextValue } from "@undb/context/server" import { CommandBus, QueryBus } from "@undb/cqrs" import { inject, singleton } from "@undb/di" -import { type ICommandBus, type IQueryBus, None, PaginatedDTO, Some } from "@undb/domain" +import { type ICommandBus, type IQueryBus, PaginatedDTO, Some } from "@undb/domain" import { createLogger } from "@undb/logger" import { API_TOKEN_HEADER_NAME, createOpenApiSpec, type IApiTokenService, injectApiTokenService } from "@undb/openapi" import { injectQueryBuilder, type IQueryBuilder } from "@undb/persistence" import { GetReadableRecordByIdQuery, GetReadableRecordsQuery } from "@undb/queries" import { injectSpaceService, type ISpaceService } from "@undb/space" import { - injectRecordRepository, + injectRecordsQueryService, injectTableRepository, type IRecordReadableValueDTO, - type IRecordRepository, + type IRecordsQueryService, type ITableRepository, withUniqueTable, } from "@undb/table" @@ -40,8 +40,8 @@ export class OpenAPI { private readonly baseRepo: IBaseRepository, @injectTableRepository() private readonly repo: ITableRepository, - @injectRecordRepository() - private readonly recordRepo: IRecordRepository, + @injectRecordsQueryService() + private readonly recordsQueryService: IRecordsQueryService, @inject(QueryBus) private readonly queryBus: IQueryBus, @@ -82,7 +82,12 @@ export class OpenAPI { const ts = withUniqueTable({ baseName, tableName }).unwrap() const table = (await this.repo.findOne(Some(ts))).expect("Table not found") const base = (await this.baseRepo.findOneById(table.baseId)).expect("Base not found") - const record = (await this.recordRepo.findOne(table, None)).into(undefined) + const record = ( + await this.recordsQueryService.getReadableRecords({ + tableId: table.id.value, + pagination: { limit: 1 }, + }) + ).values.at(0) const spec = createOpenApiSpec(base, table, record) diff --git a/packages/openapi/src/index.ts b/packages/openapi/src/index.ts index 4d5091f7e..1b44101c7 100644 --- a/packages/openapi/src/index.ts +++ b/packages/openapi/src/index.ts @@ -9,7 +9,7 @@ import { z } from "@undb/zod" extendZodWithOpenApi(z) import type { Base } from "@undb/base" -import type { RecordDO, TableDo } from "@undb/table" +import type { IReadableRecordDTO, TableDo } from "@undb/table" import { RECORD_COMPONENT, bulkDeleteRecords, @@ -28,7 +28,7 @@ import { export const API_TOKEN_HEADER_NAME = "x-undb-api-token" -export const createOpenApiSpec = (base: Base, table: TableDo, record?: RecordDO) => { +export const createOpenApiSpec = (base: Base, table: TableDo, record?: IReadableRecordDTO) => { const registry = new OpenAPIRegistry() const recordSchema = createRecordComponent(table, record) diff --git a/packages/openapi/src/openapi/record.openapi.ts b/packages/openapi/src/openapi/record.openapi.ts index 2ccbd96fc..b494cc3ba 100644 --- a/packages/openapi/src/openapi/record.openapi.ts +++ b/packages/openapi/src/openapi/record.openapi.ts @@ -1,36 +1,23 @@ import type { RouteConfig } from "@asteasolutions/zod-to-openapi" import type { Base } from "@undb/base" -import { RecordDO, recordId, type TableDo } from "@undb/table" +import { recordId, type IReadableRecordDTO, type TableDo } from "@undb/table" import { z, type ZodTypeAny } from "@undb/zod" -import { objectify } from "radash" +export const RECORD_ID_COMPONENT = "RecordId" export const RECORD_COMPONENT = "Record" export const RECORD_VALUES_COMPONENT = "RecordValues" export const RECORD_DISPLAY_VALUES_COMPONENT = "RecordDisplayValues" -export const createRecordComponent = (table: TableDo, record?: RecordDO) => { - const fields = table.schema.fields - const displayFields = table.schema.getFieldsHasDisplayValue() +export const createRecordComponent = (table: TableDo, record?: IReadableRecordDTO) => { const schema = table.schema.readableSchema const displayScheam = table.schema.displayValuesSchema - const example = record - ? objectify( - fields, - (f) => f.name.value, - (f) => record?.getValue(f.id).into(undefined)?.value, - ) - : undefined + const example = record?.values + const displayExample = record?.displayValues - const displayExample = record - ? objectify( - displayFields, - (f) => f.name.value, - (f) => record.getDisplayValueByField(f.id)?.into(undefined), - ) - : undefined return z .object({ + id: recordId.openapi(RECORD_ID_COMPONENT, { example: record?.id }), values: schema.openapi(RECORD_VALUES_COMPONENT, { example }), displayValues: displayScheam.openapi(RECORD_DISPLAY_VALUES_COMPONENT, { example: displayExample }), }) diff --git a/packages/table/src/modules/records/record/dto/record.dto.ts b/packages/table/src/modules/records/record/dto/record.dto.ts index f7cb3fed6..804c85317 100644 --- a/packages/table/src/modules/records/record/dto/record.dto.ts +++ b/packages/table/src/modules/records/record/dto/record.dto.ts @@ -19,6 +19,7 @@ export const recordReadableDisplayValueDTO = z.record(fieldName, z.any()) export type IRecordReadableDisplayValueDTO = z.infer export const readableRecordDTO = z.object({ + id: recordId, values: recordReadableValueDTO, displayValues: recordReadableDisplayValueDTO.optional(), }) diff --git a/packages/table/src/modules/records/record/record.do.ts b/packages/table/src/modules/records/record/record.do.ts index af6c355bf..b1faef3e2 100644 --- a/packages/table/src/modules/records/record/record.do.ts +++ b/packages/table/src/modules/records/record/record.do.ts @@ -118,6 +118,7 @@ export class RecordDO extends AggregateRoot { const values = this.values.toReadable(table, fields) const displayValues = this.displayValues?.toReadable(table, fields) return { + id: this.id.value, values, displayValues, } diff --git a/packages/table/src/modules/records/services/methods/get-readable-records.method.ts b/packages/table/src/modules/records/services/methods/get-readable-records.method.ts index 110386769..b1fe33ee2 100644 --- a/packages/table/src/modules/records/services/methods/get-readable-records.method.ts +++ b/packages/table/src/modules/records/services/methods/get-readable-records.method.ts @@ -2,21 +2,22 @@ import { None, Some, type PaginatedDTO } from "@undb/domain" import { withUniqueTable } from "../../../../specifications/table-name.specification" import { ViewIdVo } from "../../../views" import type { IGetRecordsDTO } from "../../dto" -import { buildQuery, type IRecordReadableValueDTO } from "../../record" +import { buildQuery, type IReadableRecordDTO } from "../../record" import { recordsToReadable } from "../../record.util" import type { RecordsQueryService } from "../records.query-service" export async function getReadableRecords( this: RecordsQueryService, dto: IGetRecordsDTO, -): Promise> { +): Promise> { const spec = withUniqueTable(dto).expect("Invalid unique table specification") const table = (await this.tableRepository.findOne(Some(spec))).expect("Table not found") const viewId = dto.viewId ? Some(new ViewIdVo(dto.viewId)) : None const query = buildQuery(table, dto) const data = await this.repo.find(table, viewId, query) - const readable = recordsToReadable(table, data.values) + const values = await this.populateAttachments({}, table, data.values) + const readable = recordsToReadable(table, values) return { total: data.total, values: readable, diff --git a/packages/table/src/modules/records/services/records.query-service.ts b/packages/table/src/modules/records/services/records.query-service.ts index 60ab9f85b..bd89343b3 100644 --- a/packages/table/src/modules/records/services/records.query-service.ts +++ b/packages/table/src/modules/records/services/records.query-service.ts @@ -9,6 +9,7 @@ import { injectObjectStorage, type IObjectStorage } from "../../storage" import type { AggregateResult, ICountRecordsDTO, IGetAggregatesDTO, IGetRecordByIdDTO, IGetRecordsDTO } from "../dto" import { injectRecordQueryRepository, + type IReadableRecordDTO, type IRecordDTO, type IRecordQueryRepository, type IRecordReadableValueDTO, @@ -24,7 +25,7 @@ export interface IRecordsQueryService { getRecords(query: IGetRecordsDTO): Promise> countRecords(query: ICountRecordsDTO): Promise getRecordById(query: IGetRecordByIdDTO): Promise> - getReadableRecords(query: IGetRecordsDTO): Promise> + getReadableRecords(query: IGetRecordsDTO): Promise> getReadableRecordById(query: IGetRecordByIdDTO): Promise> getAggregates(query: IGetAggregatesDTO): Promise> populateAttachments(dto: IGetRecordsDTO, table: TableDo, records: IRecordDTO[]): Promise