Skip to content

Commit

Permalink
v3
Browse files Browse the repository at this point in the history
  • Loading branch information
nckhell committed Dec 28, 2024
1 parent 5b2cf05 commit 49c1403
Show file tree
Hide file tree
Showing 131 changed files with 9,349 additions and 5,567 deletions.
18 changes: 18 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node', // or 'jsdom' for browser-like environments
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
testMatch: [
'**/__tests__/**/*.(ts|tsx|js)',
'**/?(*.)+(spec|test).(ts|tsx|js)',
],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
},
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json', // Use your project's tsconfig
},
},
modulePathIgnorePatterns: ['dist'],
}
10,366 changes: 7,820 additions & 2,546 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"lint": "eslint --ignore-path .eslintignore --ext .js,.ts .",
"dev": "concurrently \"npx tsc --watch\" \"nodemon -q dist/server.js\"",
"format": "prettier --ignore-path .gitignore --write \"**/*.+(js|ts|json)\"",
"test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register 'src/**/*.test.ts'"
"test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register 'src/**/*.test.ts'",
"test:jest": "jest"
},
"precommit": [
"lint"
Expand Down Expand Up @@ -37,12 +38,14 @@
"swagger-ui-express": "^4.5.0",
"ts-node": "^10.9.1",
"winston": "^3.8.2",
"winston-mongodb": "^5.1.0"
"winston-mongodb": "^5.1.0",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.14",
"@types/jest": "^29.5.14",
"@types/lodash": "^4.14.186",
"@types/mocha": "^10.0.0",
"@types/multer": "^1.4.7",
Expand All @@ -60,9 +63,11 @@
"eslint-plugin-n": "^15.3.0",
"eslint-plugin-promise": "^6.0.1",
"eslint-plugin-unused-imports": "^2.0.0",
"jest": "^29.7.0",
"nodemon": "^2.0.20",
"pre-commit": "^1.2.2",
"prettier": "^2.7.1",
"ts-jest": "^29.2.5",
"typescript": "^4.8.4"
}
}
85 changes: 85 additions & 0 deletions src/api/shared/classes/Calculation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { z } from 'zod'
import { isNil } from 'lodash'
import { LabelType } from '../../../types/localization.types'

type CalculationOutputSchema = {
label: LabelType
type: z.ZodTypeAny
unit?: LabelType
interpretation?: LabelType
terminology?: unknown
}

export type CalculationType<
InputSchema extends z.ZodObject<Record<string, z.ZodTypeAny>>,
OutputSchema extends Record<string, CalculationOutputSchema>
> = {
name: string
readme_location: string
inputSchema: InputSchema
outputSchema: OutputSchema
formData?: {
[K in keyof z.infer<InputSchema>]: unknown
}
calculate: CalculateFn<InputSchema, OutputSchema>['calculate']
}

type CalculateFn<
InputSchema extends z.ZodObject<Record<string, z.ZodTypeAny>>,
OutputSchema extends Record<string, CalculationOutputSchema>
> = {
calculate?: (opts: {
data: z.infer<InputSchema>
}) => Record<
keyof OutputSchema,
z.infer<OutputSchema[keyof OutputSchema]['type']> | null
>
}

export class Calculation<
InputSchema extends z.ZodObject<Record<string, z.ZodTypeAny>>,
OutputSchema extends Record<string, CalculationOutputSchema>
> implements Omit<CalculationType<InputSchema, OutputSchema>, 'calculate'>
{
name: string
readme_location: string
inputSchema: InputSchema
outputSchema: OutputSchema
formData?: Record<keyof z.infer<InputSchema>, unknown>
_calculate?: CalculateFn<InputSchema, OutputSchema>['calculate']

public constructor(
calculation: Omit<CalculationType<InputSchema, OutputSchema>, 'schema'> & {
inputSchema: InputSchema
outputSchema: OutputSchema
}
) {
this.name = calculation.name
this.readme_location = calculation.readme_location
this.inputSchema = calculation.inputSchema
this.outputSchema = calculation.outputSchema
this.formData = calculation.formData
this._calculate = calculation.calculate
}

/**
* We don't know the shape of the data when the class is instantiated.
* We need to parse the data before we can call the onCalculate function.
*/
calculate(opts: {
payload: unknown
}): Record<
keyof OutputSchema,
z.infer<OutputSchema[keyof OutputSchema]['type']> | null
> {
if (!isNil(this._calculate)) {
const parsedData = this.inputSchema.parse(opts.payload)

return this._calculate({
data: parsedData,
})
} else {
throw new Error('Failed to calculate')
}
}
}
15 changes: 12 additions & 3 deletions src/api/shared/services/calculations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,27 @@ import {
filter_out_non_applicable_inputs,
generate_random_calculation_input_based_on_calculation_parameters,
} from '../utils'
import type { CalculationType as NewCalculationType } from '../classes/Calculation'

/**
* Only return calculations where `is_private` is set to false
*/
const get_public_calculations = (): CalculationsLibraryType =>
R.filter(calculation => calculation.is_private === false, CALCULATIONS)
R.filter(
(calculation): calculation is CalculationType =>
'is_private' in calculation && calculation.is_private === false,
CALCULATIONS
)

/**
* Only return calculations where `is_private` is set to true
*/
const get_private_calculations = (): CalculationsLibraryType =>
R.filter(calculation => calculation.is_private === true, CALCULATIONS)
R.filter(
(calculation): calculation is CalculationType =>
'is_private' in calculation && calculation.is_private === true,
CALCULATIONS
)

/**
* Return all calculations
Expand All @@ -36,7 +45,7 @@ const get_all_calculations = (): CalculationsLibraryType => CALCULATIONS

const get_calculation = (
calculation_id: CalculationScriptIdentifierType
): CalculationType | undefined => {
): CalculationType | NewCalculationType<any, any> | undefined => {
const calculation = CALCULATIONS[calculation_id]

if (R.isNil(calculation)) return undefined
Expand Down
14 changes: 14 additions & 0 deletions src/api/v1/controllers/calculations.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ const get_calculation = async (req: Request, res: Response) => {
return
}

// Then it's a new calculation
if ('inputSchema' in requested_calculation) {
res.status(StatusCodes.OK).send(requested_calculation)
return
}

res.status(StatusCodes.OK).send(
transform_single_calculation_for_api_response({
calculation_id,
Expand Down Expand Up @@ -109,6 +115,10 @@ const execute_calculation = async (req: Request, res: Response) => {
return
}

if ('inputSchema' in requested_calculation) {
return
}

const casted_calculation_input =
cast_incoming_calculation_input_to_exact_types({
calculation: requested_calculation,
Expand Down Expand Up @@ -156,6 +166,10 @@ const simulate_calculation = async (req: Request, res: Response) => {
return
}

if ('inputSchema' in requested_calculation) {
return
}

const simulation = CalculationsService.simulate({
calculation: requested_calculation,
calculation_id,
Expand Down
9 changes: 9 additions & 0 deletions src/api/v2/controllers/calculations.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ const execute_calculation = async (req: Request, res: Response) => {
return
}

if (!('calculation_name' in requested_calculation)) {
res.status(StatusCodes.BAD_REQUEST).send({
error: {
message: `Awaiting update to v3`,
},
})
return
}

/**
* Clincal App Support:
* The Awell Score API is strictly typed in terms of the inputs it can receive for a calculation.
Expand Down
18 changes: 0 additions & 18 deletions src/calculation_suite/PARAMETERS.ts

This file was deleted.

Loading

0 comments on commit 49c1403

Please sign in to comment.