Skip to content

Commit

Permalink
Add runtime checks for 'input' columns
Browse files Browse the repository at this point in the history
  • Loading branch information
manelcecs committed Nov 13, 2024
1 parent d6c08b2 commit e6cf143
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 4 deletions.
95 changes: 95 additions & 0 deletions src/domain-services/flows/flow-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Op } from '@unocha/hpc-api-core/src/db/util/conditions';
import { type InstanceOfModel } from '@unocha/hpc-api-core/src/db/util/types';
import { createBrandedValue } from '@unocha/hpc-api-core/src/util/types';
import { Service } from 'typedi';
import { isValidKey } from '../../utils/utils';
import { FlowObjectService } from '../flow-object/flow-object-service';
import type {
FlowObject,
Expand Down Expand Up @@ -85,10 +86,22 @@ export class FlowService {

switch (entity) {
case 'emergency': {
if (
!isValidKey<
InstanceOfModel<Database['emergency']>,
keyof InstanceOfModel<Database['emergency']>
>(orderBy.column as keyof InstanceOfModel<Database['emergency']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}

// Get emergency entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['emergency']
>;

const orderByEmergency = { column, order: orderBy.order };

const emergencies = await database.emergency.find({
Expand All @@ -102,6 +115,16 @@ export class FlowService {
break;
}
case 'globalCluster': {
if (
!isValidKey<
InstanceOfModel<Database['globalCluster']>,
keyof InstanceOfModel<Database['globalCluster']>
>(orderBy.column as keyof InstanceOfModel<Database['globalCluster']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get globalCluster entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['globalCluster']
Expand All @@ -119,6 +142,18 @@ export class FlowService {
break;
}
case 'governingEntity': {
if (
!isValidKey<
InstanceOfModel<Database['governingEntity']>,
keyof InstanceOfModel<Database['governingEntity']>
>(
orderBy.column as keyof InstanceOfModel<Database['governingEntity']>
)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get governingEntity entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['governingEntity']
Expand All @@ -136,6 +171,16 @@ export class FlowService {
break;
}
case 'location': {
if (
!isValidKey<
InstanceOfModel<Database['location']>,
keyof InstanceOfModel<Database['location']>
>(orderBy.column as keyof InstanceOfModel<Database['location']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get location entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['location']
Expand All @@ -151,6 +196,16 @@ export class FlowService {
break;
}
case 'organization': {
if (
!isValidKey<
InstanceOfModel<Database['organization']>,
keyof InstanceOfModel<Database['organization']>
>(orderBy.column as keyof InstanceOfModel<Database['organization']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get organization entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['organization']
Expand All @@ -168,6 +223,16 @@ export class FlowService {
break;
}
case 'plan': {
if (
!isValidKey<
InstanceOfModel<Database['plan']>,
keyof InstanceOfModel<Database['plan']>
>(orderBy.column as keyof InstanceOfModel<Database['plan']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get plan entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['plan']
Expand All @@ -183,6 +248,16 @@ export class FlowService {
break;
}
case 'project': {
if (
!isValidKey<
InstanceOfModel<Database['project']>,
keyof InstanceOfModel<Database['project']>
>(orderBy.column as keyof InstanceOfModel<Database['project']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get project entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['project']
Expand All @@ -198,6 +273,16 @@ export class FlowService {
break;
}
case 'usageYear': {
if (
!isValidKey<
InstanceOfModel<Database['usageYear']>,
keyof InstanceOfModel<Database['usageYear']>
>(orderBy.column as keyof InstanceOfModel<Database['usageYear']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get usageYear entities sorted
const column = orderBy.column as keyof InstanceOfModel<
Database['usageYear']
Expand All @@ -213,6 +298,16 @@ export class FlowService {
break;
}
case 'planVersion': {
if (
!isValidKey<
InstanceOfModel<Database['planVersion']>,
keyof InstanceOfModel<Database['planVersion']>
>(orderBy.column as keyof InstanceOfModel<Database['planVersion']>)
) {
throw new Error(
`Invalid column ${orderBy.column} to sort by in ${orderBy.entity}`
);
}
// Get planVersion entities sorted
// Collect fisrt part of the entity key by the fisrt Case letter
const entityKey = `${
Expand Down
12 changes: 8 additions & 4 deletions src/domain-services/flows/strategy/impl/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Cond, Op } from '@unocha/hpc-api-core/src/db/util/conditions';
import type { InstanceDataOf } from '@unocha/hpc-api-core/src/db/util/model-definition';
import { type InstanceOfModel } from '@unocha/hpc-api-core/src/db/util/types';
import { createBrandedValue } from '@unocha/hpc-api-core/src/util/types';
import type * as t from 'io-ts';
import { type OrderBy } from '../../../../utils/database-types';
import { type SortOrder } from '../../../../utils/graphql/pagination';
import { type EntityDirection } from '../../../base-types';
Expand Down Expand Up @@ -40,7 +41,8 @@ export const defaultSearchFlowFilter: FlowWhere = {

type FlowOrderByCommon = {
order: SortOrder;
direction?: EntityDirection;
direction: EntityDirection;
subEntity?: string;
};

export type FlowOrderBy = FlowOrderByCommon &
Expand Down Expand Up @@ -91,6 +93,8 @@ export type FlowOrderBy = FlowOrderByCommon &
}
);

export type FlowOrderByCodec = t.Type<FlowOrderBy>;

export const mapFlowCategoryConditionsToWhereClause = (
flowCategoryConditions: FlowCategory[]
) => {
Expand Down Expand Up @@ -150,7 +154,7 @@ export const mapFlowCategoryConditionsToWhereClause = (
};

export const mapFlowOrderBy = (
orderBy?: FlowOrderByWithSubEntity
orderBy?: FlowOrderBy | FlowOrderByWithSubEntity
): OrderBy<FlowFieldsDefinition> => {
if (!orderBy || orderBy.entity !== 'flow') {
return defaultFlowOrderBy();
Expand Down Expand Up @@ -371,9 +375,9 @@ export const buildOrderBy = (
const orderBy: FlowOrderByWithSubEntity = {
column: sortField ?? 'updatedAt',
order: sortOrder ?? ('desc' as SortOrder),
direction: undefined,
direction: 'source' as EntityDirection,
entity: 'flow',
};
} satisfies FlowOrderByWithSubEntity;

// Check if sortField is a nested property
if (orderBy.column.includes('.')) {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const isValidKey = <T extends object, Q extends keyof T>(
key: keyof T
): key is Q => {
const runtimeKeys: Array<keyof T> = Object.keys({} as T).map(
(key) => key as keyof T
);
return runtimeKeys.includes(key as keyof T);
};

0 comments on commit e6cf143

Please sign in to comment.