@loomcore/api 0.1.68 → 0.1.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.js +1 -0
- package/dist/controllers/query-api.controller.d.ts +19 -0
- package/dist/controllers/query-api.controller.js +61 -0
- package/dist/databases/operations/index.d.ts +2 -0
- package/dist/databases/operations/index.js +2 -0
- package/dist/services/generic-query-service/generic-query-service.interface.d.ts +1 -0
- package/dist/services/generic-query-service/generic-query.service.d.ts +1 -0
- package/dist/services/generic-query-service/generic-query.service.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Application, NextFunction, Request, Response } from 'express';
|
|
2
|
+
import { IEntity, IModelSpec } from '@loomcore/common/models';
|
|
3
|
+
import type { TSchema } from '@sinclair/typebox';
|
|
4
|
+
import { IGenericQueryService } from '../services/index.js';
|
|
5
|
+
export declare abstract class QueryApiController<T extends IEntity> {
|
|
6
|
+
protected app: Application;
|
|
7
|
+
protected service: IGenericQueryService<T>;
|
|
8
|
+
protected slug: string;
|
|
9
|
+
protected apiResourceName: string;
|
|
10
|
+
protected modelSpec?: IModelSpec;
|
|
11
|
+
protected publicSpec?: IModelSpec;
|
|
12
|
+
protected idSchema: TSchema;
|
|
13
|
+
protected constructor(slug: string, app: Application, service: IGenericQueryService<T>, resourceName?: string, modelSpec?: IModelSpec, publicSpec?: IModelSpec);
|
|
14
|
+
mapRoutes(app: Application): void;
|
|
15
|
+
getAll(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
16
|
+
get(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
17
|
+
getById(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
18
|
+
getCount(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { BadRequestError } from '../errors/index.js';
|
|
2
|
+
import { Value } from '@sinclair/typebox/value';
|
|
3
|
+
import { getIdSchema } from '@loomcore/common/validation';
|
|
4
|
+
import { apiUtils } from '../utils/index.js';
|
|
5
|
+
import { isAuthorized } from '../middleware/index.js';
|
|
6
|
+
export class QueryApiController {
|
|
7
|
+
app;
|
|
8
|
+
service;
|
|
9
|
+
slug;
|
|
10
|
+
apiResourceName;
|
|
11
|
+
modelSpec;
|
|
12
|
+
publicSpec;
|
|
13
|
+
idSchema;
|
|
14
|
+
constructor(slug, app, service, resourceName = '', modelSpec, publicSpec) {
|
|
15
|
+
this.slug = slug;
|
|
16
|
+
this.app = app;
|
|
17
|
+
this.service = service;
|
|
18
|
+
this.apiResourceName = resourceName;
|
|
19
|
+
this.modelSpec = modelSpec;
|
|
20
|
+
this.publicSpec = publicSpec;
|
|
21
|
+
this.idSchema = getIdSchema();
|
|
22
|
+
this.mapRoutes(app);
|
|
23
|
+
}
|
|
24
|
+
mapRoutes(app) {
|
|
25
|
+
app.get(`/api/${this.slug}`, isAuthorized(), this.get.bind(this));
|
|
26
|
+
app.get(`/api/${this.slug}/all`, isAuthorized(), this.getAll.bind(this));
|
|
27
|
+
app.get(`/api/${this.slug}/count`, isAuthorized(), this.getCount.bind(this));
|
|
28
|
+
app.get(`/api/${this.slug}/:id`, isAuthorized(), this.getById.bind(this));
|
|
29
|
+
}
|
|
30
|
+
async getAll(req, res, next) {
|
|
31
|
+
res.set('Content-Type', 'application/json');
|
|
32
|
+
const entities = await this.service.getAll(req.userContext);
|
|
33
|
+
apiUtils.apiResponse(res, 200, { data: entities }, this.modelSpec, this.publicSpec);
|
|
34
|
+
}
|
|
35
|
+
async get(req, res, next) {
|
|
36
|
+
res.set('Content-Type', 'application/json');
|
|
37
|
+
const queryOptions = apiUtils.getQueryOptionsFromRequest(req);
|
|
38
|
+
const pagedResult = await this.service.get(req.userContext, queryOptions);
|
|
39
|
+
apiUtils.apiResponse(res, 200, { data: pagedResult }, this.modelSpec, this.publicSpec);
|
|
40
|
+
}
|
|
41
|
+
async getById(req, res, next) {
|
|
42
|
+
res.set('Content-Type', 'application/json');
|
|
43
|
+
const idParam = req.params?.id;
|
|
44
|
+
if (!idParam) {
|
|
45
|
+
throw new BadRequestError('ID parameter is required');
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const id = Value.Convert(this.idSchema, idParam);
|
|
49
|
+
const entity = await this.service.getById(req.userContext, id);
|
|
50
|
+
apiUtils.apiResponse(res, 200, { data: entity }, this.modelSpec, this.publicSpec);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new BadRequestError(`Invalid ID format: ${error.message || error}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async getCount(req, res, next) {
|
|
57
|
+
res.set('Content-Type', 'application/json');
|
|
58
|
+
const count = await this.service.getCount(req.userContext);
|
|
59
|
+
apiUtils.apiResponse(res, 200, { data: count }, this.modelSpec, this.publicSpec);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -11,4 +11,5 @@ export interface IGenericQueryService<T extends IEntity> {
|
|
|
11
11
|
getAll(userContext: IUserContext): Promise<T[]>;
|
|
12
12
|
get(userContext: IUserContext, queryOptions: IQueryOptions): Promise<IPagedResult<T>>;
|
|
13
13
|
getById(userContext: IUserContext, id: AppIdType): Promise<T>;
|
|
14
|
+
getCount(userContext: IUserContext): Promise<number>;
|
|
14
15
|
}
|
|
@@ -18,4 +18,5 @@ export declare class GenericQueryService<T extends IEntity> implements IGenericQ
|
|
|
18
18
|
getAll(userContext: IUserContext): Promise<T[]>;
|
|
19
19
|
get(userContext: IUserContext, queryOptions?: IQueryOptions): Promise<IPagedResult<T>>;
|
|
20
20
|
getById(userContext: IUserContext, id: AppIdType): Promise<T>;
|
|
21
|
+
getCount(userContext: IUserContext): Promise<number>;
|
|
21
22
|
}
|
|
@@ -44,4 +44,8 @@ export class GenericQueryService {
|
|
|
44
44
|
}
|
|
45
45
|
return this.postProcessEntity(userContext, entity);
|
|
46
46
|
}
|
|
47
|
+
async getCount(userContext) {
|
|
48
|
+
const { operations } = this.prepareQuery(userContext, {}, []);
|
|
49
|
+
return await this.database.getCount(this.rootTableName);
|
|
50
|
+
}
|
|
47
51
|
}
|