Skip to content

Commit 0b714b5

Browse files
committed
Add runtime checks for 'input' columns
1 parent 3956520 commit 0b714b5

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

src/domain-services/flows/flow-service.ts

+77-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { type Database } from '@unocha/hpc-api-core/src/db';
22
import { type FlowId } from '@unocha/hpc-api-core/src/db/models/flow';
33
import { Op } from '@unocha/hpc-api-core/src/db/util/conditions';
44
import { type InstanceOfModel } from '@unocha/hpc-api-core/src/db/util/types';
5-
import { createBrandedValue } from '@unocha/hpc-api-core/src/util/types';
5+
import {
6+
createBrandedValue,
7+
getTableColumns,
8+
} from '@unocha/hpc-api-core/src/util/types';
69
import { Service } from 'typedi';
710
import { FlowObjectService } from '../flow-object/flow-object-service';
811
import type {
@@ -52,11 +55,20 @@ export class FlowService {
5255
orderBy: FlowOrderByWithSubEntity
5356
): Promise<UniqueFlowEntity[]> {
5457
const entity = orderBy.subEntity ?? orderBy.entity;
58+
let columns: string[] = [];
59+
5560
// Get the entity list
5661
// 'externalReference' is a special case
5762
// because it does have a direct relation with flow
5863
// and no direction
5964
if (entity === 'externalReference') {
65+
columns = getTableColumns(database.externalReference);
66+
if (!columns.includes(orderBy.column)) {
67+
throw new Error(
68+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
69+
);
70+
}
71+
6072
const column = orderBy.column as keyof InstanceOfModel<
6173
Database['externalReference']
6274
>;
@@ -78,17 +90,23 @@ export class FlowService {
7890

7991
const refDirection = orderBy.direction ?? 'source';
8092

81-
// Validate the variable using io-ts
82-
8393
let flowObjects = [];
8494
let entityIDsSorted: number[] = [];
8595

8696
switch (entity) {
8797
case 'emergency': {
98+
columns = getTableColumns(database.emergency);
99+
if (!columns.includes(orderBy.column)) {
100+
throw new Error(
101+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
102+
);
103+
}
104+
88105
// Get emergency entities sorted
89106
const column = orderBy.column as keyof InstanceOfModel<
90107
Database['emergency']
91108
>;
109+
92110
const orderByEmergency = { column, order: orderBy.order };
93111

94112
const emergencies = await database.emergency.find({
@@ -102,6 +120,13 @@ export class FlowService {
102120
break;
103121
}
104122
case 'globalCluster': {
123+
columns = getTableColumns(database.globalCluster);
124+
125+
if (!columns.includes(orderBy.column)) {
126+
throw new Error(
127+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
128+
);
129+
}
105130
// Get globalCluster entities sorted
106131
const column = orderBy.column as keyof InstanceOfModel<
107132
Database['globalCluster']
@@ -119,6 +144,13 @@ export class FlowService {
119144
break;
120145
}
121146
case 'governingEntity': {
147+
columns = getTableColumns(database.governingEntity);
148+
149+
if (!columns.includes(orderBy.column)) {
150+
throw new Error(
151+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
152+
);
153+
}
122154
// Get governingEntity entities sorted
123155
const column = orderBy.column as keyof InstanceOfModel<
124156
Database['governingEntity']
@@ -136,6 +168,13 @@ export class FlowService {
136168
break;
137169
}
138170
case 'location': {
171+
columns = getTableColumns(database.location);
172+
173+
if (!columns.includes(orderBy.column)) {
174+
throw new Error(
175+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
176+
);
177+
}
139178
// Get location entities sorted
140179
const column = orderBy.column as keyof InstanceOfModel<
141180
Database['location']
@@ -151,6 +190,13 @@ export class FlowService {
151190
break;
152191
}
153192
case 'organization': {
193+
columns = getTableColumns(database.organization);
194+
195+
if (!columns.includes(orderBy.column)) {
196+
throw new Error(
197+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
198+
);
199+
}
154200
// Get organization entities sorted
155201
const column = orderBy.column as keyof InstanceOfModel<
156202
Database['organization']
@@ -168,6 +214,13 @@ export class FlowService {
168214
break;
169215
}
170216
case 'plan': {
217+
columns = getTableColumns(database.plan);
218+
219+
if (!columns.includes(orderBy.column)) {
220+
throw new Error(
221+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
222+
);
223+
}
171224
// Get plan entities sorted
172225
const column = orderBy.column as keyof InstanceOfModel<
173226
Database['plan']
@@ -183,6 +236,13 @@ export class FlowService {
183236
break;
184237
}
185238
case 'project': {
239+
columns = getTableColumns(database.project);
240+
241+
if (!columns.includes(orderBy.column)) {
242+
throw new Error(
243+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
244+
);
245+
}
186246
// Get project entities sorted
187247
const column = orderBy.column as keyof InstanceOfModel<
188248
Database['project']
@@ -198,6 +258,13 @@ export class FlowService {
198258
break;
199259
}
200260
case 'usageYear': {
261+
columns = getTableColumns(database.usageYear);
262+
263+
if (!columns.includes(orderBy.column)) {
264+
throw new Error(
265+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
266+
);
267+
}
201268
// Get usageYear entities sorted
202269
const column = orderBy.column as keyof InstanceOfModel<
203270
Database['usageYear']
@@ -213,6 +280,13 @@ export class FlowService {
213280
break;
214281
}
215282
case 'planVersion': {
283+
columns = getTableColumns(database.planVersion);
284+
285+
if (!columns.includes(orderBy.column)) {
286+
throw new Error(
287+
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
288+
);
289+
}
216290
// Get planVersion entities sorted
217291
// Collect fisrt part of the entity key by the fisrt Case letter
218292
const entityKey = `${

src/domain-services/flows/strategy/impl/utils.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Cond, Op } from '@unocha/hpc-api-core/src/db/util/conditions';
33
import type { InstanceDataOf } from '@unocha/hpc-api-core/src/db/util/model-definition';
44
import { type InstanceOfModel } from '@unocha/hpc-api-core/src/db/util/types';
55
import { createBrandedValue } from '@unocha/hpc-api-core/src/util/types';
6+
import type * as t from 'io-ts';
67
import { type OrderBy } from '../../../../utils/database-types';
78
import { type SortOrder } from '../../../../utils/graphql/pagination';
89
import { type EntityDirection } from '../../../base-types';
@@ -40,7 +41,8 @@ export const defaultSearchFlowFilter: FlowWhere = {
4041

4142
type FlowOrderByCommon = {
4243
order: SortOrder;
43-
direction?: EntityDirection;
44+
direction: EntityDirection;
45+
subEntity?: string;
4446
};
4547

4648
export type FlowOrderBy = FlowOrderByCommon &
@@ -91,6 +93,8 @@ export type FlowOrderBy = FlowOrderByCommon &
9193
}
9294
);
9395

96+
export type FlowOrderByCodec = t.Type<FlowOrderBy>;
97+
9498
export const mapFlowCategoryConditionsToWhereClause = (
9599
flowCategoryConditions: FlowCategory[]
96100
) => {
@@ -150,7 +154,7 @@ export const mapFlowCategoryConditionsToWhereClause = (
150154
};
151155

152156
export const mapFlowOrderBy = (
153-
orderBy?: FlowOrderByWithSubEntity
157+
orderBy?: FlowOrderBy | FlowOrderByWithSubEntity
154158
): OrderBy<FlowFieldsDefinition> => {
155159
if (!orderBy || orderBy.entity !== 'flow') {
156160
return defaultFlowOrderBy();
@@ -371,9 +375,9 @@ export const buildOrderBy = (
371375
const orderBy: FlowOrderByWithSubEntity = {
372376
column: sortField ?? 'updatedAt',
373377
order: sortOrder ?? ('desc' as SortOrder),
374-
direction: undefined,
378+
direction: 'source' as EntityDirection,
375379
entity: 'flow',
376-
};
380+
} satisfies FlowOrderByWithSubEntity;
377381

378382
// Check if sortField is a nested property
379383
if (orderBy.column.includes('.')) {

0 commit comments

Comments
 (0)