Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HPC-9766: Rewrite legacy RPM endpoints in typescript #163

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions src/auth/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const AUTH_PERMISSIONS = {
* Can clone data from any project to a new project
*/
CLONE_ANY_PROJECT: 'cloneAnyProject',
CREATE_PLAN: 'createPlan',
DELETE_ANY_PROJECT: 'canDeleteAnyProject',
DELETE_ANY_PLAN: 'canDeleteAnyPlan',
/**
Expand Down
1 change: 1 addition & 0 deletions src/auth/roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export const calculatePermissionsFromRolesGrant = async <
}
} else if (role === 'rpmAdmin') {
// New Permissions
global.add(P.global.CREATE_PLAN);
global.add(P.global.VIEW_ANY_PLAN_DATA);
global.add(P.global.EDIT_ANY_PLAN_DATA);
global.add(P.global.EDIT_ANY_MEASUREMENT);
Expand Down
16 changes: 9 additions & 7 deletions src/db/models/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@ export const BLUEPRINT_TYPE = t.keyof({
operation: null,
});

const ENTITY_REFS = t.array(
export const ENTITY_REFS = t.array(
t.type({
refCode: t.string,
cardinality: t.string,
})
);

export const ENTITY_REFS_OR_XOR = t.union([
ENTITY_REFS,
t.type({
xor: ENTITY_REFS,
}),
]);

const BLUEPRINT_MODEL_ATTACHMENT_TYPE = t.union([
ATTACHMENT_TYPE,
t.keyof({
Expand Down Expand Up @@ -84,12 +91,7 @@ export const BLUEPRINT_MODEL = t.type({
t.partial({
possibleChildren: ENTITY_REFS,
description: LOCALIZED_STRING,
canSupport: t.union([
ENTITY_REFS,
t.type({
xor: ENTITY_REFS,
}),
]),
canSupport: ENTITY_REFS_OR_XOR,
}),
])
),
Expand Down
9 changes: 7 additions & 2 deletions src/db/models/entityPrototype.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export const ENTITY_PROTOTYPE_TYPE = t.keyof({
PE: null,
});

export const ENTITY_PROTOTYPE_CARDINALITY = t.union([
t.literal('1-1'),
t.literal('0-N'),
]);

const ENTITY_REFS = t.array(
t.intersection([
t.type({
Expand All @@ -52,7 +57,7 @@ const ENTITY_REFS = t.array(
refCode: t.string,
}),
t.partial({
cardinality: t.union([t.literal('1-1'), t.literal('0-N')]),
cardinality: ENTITY_PROTOTYPE_CARDINALITY,
/**
* @deprecated
* There are records in database that have
Expand All @@ -61,7 +66,7 @@ const ENTITY_REFS = t.array(
* TODO: Rename this property to "cardinality" in DB, then,
* drop this definition and make "cardinality" required
*/
cadinality: t.union([t.literal('1-1'), t.literal('0-N')]),
cadinality: ENTITY_PROTOTYPE_CARDINALITY,
}),
])
);
Expand Down
4 changes: 2 additions & 2 deletions src/db/models/json/indicatorsAndCaseloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type CaseloadOrIndicatorMetricDefinition = t.TypeOf<
typeof METRIC_DEFINITION
>;

const METRIC_WITH_VALUE = t.intersection([
export const METRIC_WITH_VALUE = t.intersection([
METRIC_DEFINITION,
t.partial({
/**
Expand Down Expand Up @@ -49,7 +49,7 @@ export const DISAGGREGATED_LOCATIONS = t.array(
* Disaggregated data that may be present in a caseload, indicator, or
* measurement for a caseload or indicator.
*/
const DISAGGREGATED_DATA = t.type({
export const DISAGGREGATED_DATA = t.type({
categories: t.array(
t.type({
ids: t.array(t.number),
Expand Down
2 changes: 1 addition & 1 deletion src/db/models/location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type LocationId = Brand<

export const LOCATION_ID = brandedType<number, LocationId>(t.number);

const LOCATION_STATUS = t.keyof({
export const LOCATION_STATUS = t.keyof({
active: null,
expired: null,
});
Expand Down
4 changes: 2 additions & 2 deletions src/db/models/planVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ export type PlanVersionId = Brand<

export const PLAN_VERSION_ID = brandedType<number, PlanVersionId>(t.number);

const PLAN_VERSION_CLUSTER_SELECTION_TYPE = t.keyof({
export const PLAN_VERSION_CLUSTER_SELECTION_TYPE = t.keyof({
single: null,
multi: null,
});

const PLAN_VISIBILITY_PREFERENCES = t.type({
export const PLAN_VISIBILITY_PREFERENCES = t.type({
isDisaggregationForCaseloads: t.boolean,
isDisaggregationForIndicators: t.boolean,
});
Expand Down
39 changes: 37 additions & 2 deletions src/db/util/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export namespace PropertySymbols {
export const LTE = Symbol('less than or equal to');
export const GT = Symbol('greater than');
export const GTE = Symbol('greater than or equal to');

export const SIMILAR = Symbol('similar to');
export const CONTAINS = Symbol('contains');
/**
* Symbols to use when constructing conditions for a single property
*/
Expand All @@ -52,6 +53,8 @@ export namespace PropertySymbols {
LTE: LTE,
GT: GT,
GTE: GTE,
SIMILAR: SIMILAR,
CONTAINS: CONTAINS,
} as const;
}

Expand Down Expand Up @@ -95,6 +98,12 @@ namespace PropertyConditions {
export type GteCondition<T> = {
[Op.GTE]: T;
};
export type SimilarCondition<T> = {
[Op.SIMILAR]: T & string;
};
export type ContainsCondition<T> = {
[Op.CONTAINS]: T;
};
/**
* A condition that must hold over a single property whose type is T
*/
Expand All @@ -109,7 +118,9 @@ namespace PropertyConditions {
| LtCondition<T>
| LteCondition<T>
| GtCondition<T>
| GteCondition<T>;
| GteCondition<T>
| SimilarCondition<T>
| ContainsCondition<T>;

export const isEqualityCondition = <T>(
condition: Condition<T>
Expand Down Expand Up @@ -165,6 +176,16 @@ namespace PropertyConditions {
condition: Condition<T>
): condition is GteCondition<T> =>
Object.prototype.hasOwnProperty.call(condition, Op.GTE);

export const isSimilarCondition = <T>(
condition: Condition<T>
): condition is SimilarCondition<T> =>
Object.prototype.hasOwnProperty.call(condition, Op.SIMILAR);

export const isContainsCondition = <T>(
condition: Condition<T>
): condition is ContainsCondition<T> =>
Object.prototype.hasOwnProperty.call(condition, Op.CONTAINS);
}

namespace OverallConditions {
Expand Down Expand Up @@ -302,6 +323,20 @@ export const prepareCondition =
builder.where(property as any, '>', propertyCondition[Op.GT]);
} else if (PropertyConditions.isGteCondition(propertyCondition)) {
builder.where(property as any, '>=', propertyCondition[Op.GTE]);
} else if (PropertyConditions.isSimilarCondition(propertyCondition)) {
builder.where(
property as string,
'similar to',
propertyCondition[Op.SIMILAR]
);
} else if (PropertyConditions.isContainsCondition(propertyCondition)) {
const prop = `"${String(property)}"::varchar[]`;
const value = propertyCondition[Op.CONTAINS];
const values = (Array.isArray(value) ? value : [value])
.map((v) => `'${v}'`)
.join(',');
const wrappedValues = `ARRAY[${values}]::varchar[]`;
builder.whereRaw(`${prop} @> ${wrappedValues}`);
} else {
throw new Error(`Unexpected condition: ${propertyCondition}`);
}
Expand Down
3 changes: 2 additions & 1 deletion src/db/util/legacy-versioned-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const VERSIONED_FIELDS = {
},
} as const;

type ExtendedFields<F extends FieldDefinition> = F & typeof VERSIONED_FIELDS;
export type ExtendedFields<F extends FieldDefinition> = F &
typeof VERSIONED_FIELDS;

export type FieldsWithVersioned<
F extends FieldDefinition,
Expand Down