1import { Inject, Body, Controller, Delete, Get, HttpCode, Param, Patch, Post, Query, Req, Res, Headers } from "@nestjs/common";
2import type { Request, Response } from "express";
3import { DatabaseService } from "./database.service.js";
4import { DatabaseQueryService } from "./query.service.js";
5import { ZodValidate } from "../../common/pipes/zod-validation.pipe.js";
6import { requireActor } from "../../common/types.js";
7import {
8 BulkRecordsDto,
9 type BulkRecordsInput,
10 CreateFormulaDto,
11 type CreateFormulaInput,
12 CreatePropertyDto,
13 type CreatePropertyInput,
14 CreateRecordDto,
15 type CreateRecordInput,
16 CsvImportDto,
17 type CsvImportInput,
18 CreateRelationDto,
19 type CreateRelationInput,
20 CreateViewDto,
21 type CreateViewInput,
22 DatabaseQueryDto,
23 type DatabaseQueryInput,
24 ListRecordsQuery,
25 type ListRecordsInput,
26 UpdateDatabaseDto,
27 type UpdateDatabaseInput,
28 UpdatePropertyDto,
29 type UpdatePropertyInput,
30 UpdateRecordDto,
31 type UpdateRecordInput,
32 UpdateViewDto,
33 type UpdateViewInput,
34 ValidateFormulaDto,
35 type ValidateFormulaInput
36} from "./dto.js";
37
38@Controller()
39export class DatabasesController {
40 constructor(
41 @Inject(DatabaseService) private readonly databases: DatabaseService,
42 @Inject(DatabaseQueryService) private readonly query: DatabaseQueryService
43 ) {}
44
45
46
47 @Get("databases/:id")
48 get(@Param("id") id: string, @Req() req: Request) {
49 return this.databases.get(id, requireActor(req));
50 }
51
52 @Patch("databases/:id")
53 update(
54 @Param("id") id: string,
55 @Body(ZodValidate(UpdateDatabaseDto)) body: UpdateDatabaseInput,
56 @Req() req: Request
57 ) {
58 return this.databases.update(id, requireActor(req), body, req);
59 }
60
61 @Delete("databases/:id")
62 remove(@Param("id") id: string, @Req() req: Request) {
63 return this.databases.remove(id, requireActor(req), req).then(() => ({ deleted: true }));
64 }
65
66
67
68 @Get("databases/:id/properties")
69 properties(@Param("id") id: string, @Req() req: Request) {
70 return this.databases.listProperties(id, requireActor(req));
71 }
72
73 @Post("databases/:id/properties")
74 createProperty(
75 @Param("id") id: string,
76 @Body(ZodValidate(CreatePropertyDto)) body: CreatePropertyInput,
77 @Req() req: Request
78 ) {
79 return this.databases.createProperty(id, requireActor(req), body, req);
80 }
81
82 @Patch("databases/:id/properties/:propertyId")
83 updateProperty(
84 @Param("id") id: string,
85 @Param("propertyId") propertyId: string,
86 @Body(ZodValidate(UpdatePropertyDto)) body: UpdatePropertyInput,
87 @Req() req: Request
88 ) {
89 return this.databases.updateProperty(id, propertyId, requireActor(req), body, req);
90 }
91
92 @Delete("databases/:id/properties/:propertyId")
93 deleteProperty(
94 @Param("id") id: string,
95 @Param("propertyId") propertyId: string,
96 @Req() req: Request
97 ) {
98 return this.databases.deleteProperty(id, propertyId, requireActor(req), req).then(() => ({ deleted: true }));
99 }
100
101 @Post("databases/:id/properties/:propertyId/reorder")
102 reorderProperty(
103 @Param("id") id: string,
104 @Param("propertyId") propertyId: string,
105 @Body() body: { after?: string; before?: string; index?: number },
106 @Req() req: Request
107 ) {
108 return this.databases.reorderProperty(id, propertyId, requireActor(req), body, req);
109 }
110
111
112
113 @Get("databases/:id/views")
114 views(@Param("id") id: string, @Req() req: Request) {
115 return this.databases.listViews(id, requireActor(req));
116 }
117
118 @Post("databases/:id/views")
119 createView(
120 @Param("id") id: string,
121 @Body(ZodValidate(CreateViewDto)) body: CreateViewInput,
122 @Req() req: Request
123 ) {
124 return this.databases.createView(id, requireActor(req), body, req);
125 }
126
127 @Patch("databases/:id/views/:viewId")
128 updateView(
129 @Param("id") id: string,
130 @Param("viewId") viewId: string,
131 @Body(ZodValidate(UpdateViewDto)) body: UpdateViewInput,
132 @Req() req: Request
133 ) {
134 return this.databases.updateView(id, viewId, requireActor(req), body, req);
135 }
136
137 @Delete("databases/:id/views/:viewId")
138 deleteView(
139 @Param("id") id: string,
140 @Param("viewId") viewId: string,
141 @Req() req: Request
142 ) {
143 return this.databases.deleteView(id, viewId, requireActor(req), req).then(() => ({ deleted: true }));
144 }
145
146 @Post("databases/:id/views/:viewId/reorder")
147 reorderView(
148 @Param("id") id: string,
149 @Param("viewId") viewId: string,
150 @Body() body: { after?: string; before?: string },
151 @Req() req: Request
152 ) {
153 return this.databases.reorderView(id, viewId, requireActor(req), body, req);
154 }
155
156
157
158 @Get("databases/:id/records")
159 records(
160 @Param("id") id: string,
161 @Query(ZodValidate(ListRecordsQuery)) query: ListRecordsInput,
162 @Req() req: Request
163 ) {
164 return this.query.list(id, requireActor(req), query);
165 }
166
167
174 @Post("databases/:id/query")
175 @HttpCode(200)
176 databaseQuery(
177 @Param("id") id: string,
178 @Body(ZodValidate(DatabaseQueryDto)) body: DatabaseQueryInput,
179 @Req() req: Request
180 ) {
181 return this.query.query(id, requireActor(req), body);
182 }
183
184 @Post("databases/:id/records")
185 createRecord(
186 @Param("id") id: string,
187 @Body(ZodValidate(CreateRecordDto)) body: CreateRecordInput,
188 @Req() req: Request
189 ) {
190 return this.query.createRecord(id, requireActor(req), body, req);
191 }
192
193 @Post("databases/:id/records/bulk")
194 bulk(
195 @Param("id") id: string,
196 @Body(ZodValidate(BulkRecordsDto)) body: BulkRecordsInput,
197 @Req() req: Request
198 ) {
199 return this.query.bulk(id, requireActor(req), body, req);
200 }
201
202
203
204
205 @Post("databases/:id/import/csv")
206 async importCsv(
207 @Param("id") id: string,
208 @Body(ZodValidate(CsvImportDto)) body: CsvImportInput,
209 @Req() req: Request,
210 @Res() res: Response
211 ) {
212 const result = await this.query.importCsv(id, requireActor(req), body, req);
213 res.status(result.dryRun ? 200 : 201).json(result);
214 }
215
216 @Get("databases/:id/export")
217 async exportCsv(
218 @Param("id") id: string,
219 @Query(ZodValidate(ListRecordsQuery)) query: ListRecordsInput,
220 @Req() req: Request,
221 @Res() res: Response
222 ) {
223 const { csv, rows, truncated } = await this.query.exportCsv(id, requireActor(req), query);
224 res.setHeader("Content-Type", "text/csv; charset=utf-8");
225 res.setHeader("Content-Disposition", `attachment; filename="database-${id}.csv"`);
226 if (truncated) res.setHeader("X-Export-Truncated", "true");
227 res.send(csv);
228 }
229
230 @Get("records/:id")
231 record(@Param("id") id: string, @Req() req: Request) {
232 return this.query.getRecord(id, requireActor(req));
233 }
234
235 @Patch("records/:id")
236 updateRecord(
237 @Param("id") id: string,
238 @Body(ZodValidate(UpdateRecordDto)) body: UpdateRecordInput,
239 @Req() req: Request
240 ) {
241 return this.query.updateRecord(id, requireActor(req), body, req);
242 }
243
244 @Delete("records/:id")
245 deleteRecord(@Param("id") id: string, @Req() req: Request) {
246 return this.query.deleteRecord(id, requireActor(req), req);
247 }
248
249
250
251 @Get("databases/:id/relations")
252 relations(@Param("id") id: string, @Req() req: Request) {
253 return this.databases.listRelations(id, requireActor(req));
254 }
255
256 @Post("databases/:id/relations")
257 createRelation(
258 @Param("id") id: string,
259 @Body(ZodValidate(CreateRelationDto)) body: CreateRelationInput,
260 @Req() req: Request
261 ) {
262 return this.databases.createRelation(id, requireActor(req), body, req);
263 }
264
265 @Patch("databases/:id/relations/:relationId")
266 updateRelation(
267 @Param("id") id: string,
268 @Param("relationId") relationId: string,
269 @Body() body: { name?: string; targetName?: string },
270 @Req() req: Request
271 ) {
272 return this.databases.updateRelation(id, relationId, requireActor(req), body, req);
273 }
274
275 @Delete("databases/:id/relations/:relationId")
276 deleteRelation(
277 @Param("id") id: string,
278 @Param("relationId") relationId: string,
279 @Req() req: Request
280 ) {
281 return this.databases.deleteRelation(id, relationId, requireActor(req), req).then(() => ({ deleted: true }));
282 }
283
284 @Get("records/:id/relations")
285 recordRelations(@Param("id") id: string, @Req() req: Request) {
286 return this.query.getRecord(id, requireActor(req)).then((r) => ({ relations: (r as { relations: unknown }).relations }));
287 }
288
289
290
291 @Get("databases/:id/formulas")
292 formulas(@Param("id") id: string, @Req() req: Request) {
293 return this.databases.listFormulas(id, requireActor(req));
294 }
295
296 @Post("databases/:id/formulas")
297 createFormula(
298 @Param("id") id: string,
299 @Body(ZodValidate(CreateFormulaDto)) body: CreateFormulaInput,
300 @Req() req: Request
301 ) {
302 return this.databases.createFormula(id, requireActor(req), body, req);
303 }
304
305 @Post("databases/:id/formulas/validate")
306 validateFormula(
307 @Param("id") id: string,
308 @Body(ZodValidate(ValidateFormulaDto)) body: ValidateFormulaInput
309 ) {
310 return this.databases.validateFormula(body);
311 }
312
313
320 @Get("records/:id/formula/:formulaId")
321 formulaValue(
322 @Param("id") id: string,
323 @Param("formulaId") formulaId: string,
324 @Req() req: Request
325 ) {
326 return this.databases.evaluateRecordFormula(id, formulaId, requireActor(req));
327 }
328}
329