Skip to content

Commit

Permalink
[IP-387] Upgrade fp-ts (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
Emanuele De Cupis authored Sep 21, 2021
1 parent 55a445d commit 0a2d30d
Show file tree
Hide file tree
Showing 101 changed files with 3,546 additions and 3,186 deletions.
26 changes: 14 additions & 12 deletions CreateDevelopmentProfile/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as express from "express";

import { Context } from "@azure/functions";

import { isLeft } from "fp-ts/lib/Either";
import * as E from "fp-ts/lib/Either";

import { readableReport } from "@pagopa/ts-commons/lib/reporters";
import {
Expand Down Expand Up @@ -40,6 +40,7 @@ import {

import { ServicesPreferencesModeEnum } from "@pagopa/io-functions-commons/dist/generated/definitions/ServicesPreferencesMode";
import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers";
import { pipe } from "fp-ts/lib/function";
import { DevelopmentProfile } from "../generated/definitions/DevelopmentProfile";

// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
Expand All @@ -66,9 +67,10 @@ export const DeveloperProfilePayloadMiddleware: IRequestMiddleware<
DevelopmentProfile
> = request =>
new Promise(resolve => {
const validation = DevelopmentProfile.decode(request.body);
const result = validation.mapLeft(
ResponseErrorFromValidationErrors(ExtendedProfile)
const result = pipe(
request.body,
DevelopmentProfile.decode,
E.mapLeft(ResponseErrorFromValidationErrors(ExtendedProfile))
);
resolve(result);
});
Expand Down Expand Up @@ -98,16 +100,16 @@ export function CreateDevelopmentProfileHandler(

const errorOrFiscalCode = FiscalCode.decode(sandboxFiscalCode);

if (isLeft(errorOrFiscalCode)) {
if (E.isLeft(errorOrFiscalCode)) {
context.log.error(
`${logPrefix}|ERROR=${readableReport(errorOrFiscalCode.value)}`
`${logPrefix}|ERROR=${readableReport(errorOrFiscalCode.left)}`
);
return ResponseErrorFromValidationErrors(FiscalCode)(
errorOrFiscalCode.value
errorOrFiscalCode.left
);
}

const fiscalCode = errorOrFiscalCode.value;
const fiscalCode = errorOrFiscalCode.right;

const newProfile: NewProfile = {
email: developmentProfilePayload.email,
Expand All @@ -121,10 +123,10 @@ export function CreateDevelopmentProfileHandler(
}
};

const errorOrCreatedProfile = await profileModel.create(newProfile).run();
const errorOrCreatedProfile = await profileModel.create(newProfile)();

if (isLeft(errorOrCreatedProfile)) {
const error = errorOrCreatedProfile.value;
if (E.isLeft(errorOrCreatedProfile)) {
const error = errorOrCreatedProfile.left;
context.log.error(`${logPrefix}|ERROR=${error}`);

if (error.kind === "COSMOS_ERROR_RESPONSE" && error.error.code === 409) {
Expand All @@ -139,7 +141,7 @@ export function CreateDevelopmentProfileHandler(
);
}

const createdProfile = errorOrCreatedProfile.value;
const createdProfile = errorOrCreatedProfile.right;

context.log.verbose(`${logPrefix}|SUCCESS`);

Expand Down
10 changes: 4 additions & 6 deletions CreateService/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import * as df from "durable-functions";
import * as lolex from "lolex";

import { left, right } from "fp-ts/lib/Either";

import { fromEither, fromLeft } from "fp-ts/lib/TaskEither";
import * as TE from "fp-ts/lib/TaskEither";
import { toCosmosErrorResponse } from "@pagopa/io-functions-commons/dist/src/utils/cosmosdb_model";
import {
aNewService,
Expand All @@ -33,7 +31,7 @@ describe("CreateServiceHandler", () => {
it("should return a query error if the service fails to be created", async () => {
const mockServiceModel = {
create: jest.fn(_ => {
return fromLeft(
return TE.left(
toCosmosErrorResponse({ kind: "COSMOS_ERROR_RESPONSE" })
);
})
Expand All @@ -54,7 +52,7 @@ describe("CreateServiceHandler", () => {
it("should create a new service using the payload and return the created service", async () => {
const mockServiceModel = {
create: jest.fn(_ => {
return fromEither(right(aRetrievedService));
return TE.right(aRetrievedService);
})
};

Expand All @@ -76,7 +74,7 @@ describe("CreateServiceHandler", () => {
it("should start the orchestrator with an appropriate event after the service is created", async () => {
const mockServiceModel = {
create: jest.fn(_ => {
return fromEither(right(aRetrievedService));
return TE.right(aRetrievedService);
})
};

Expand Down
6 changes: 3 additions & 3 deletions CreateService/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ export function CreateServiceHandler(
...apiServiceToService(servicePayload),
kind: "INewService" as const
};
const errorOrCreatedService = await serviceModel.create(newService).run();
const errorOrCreatedService = await serviceModel.create(newService)();

if (isLeft(errorOrCreatedService)) {
return ResponseErrorQuery(
"CreateServiceHandler error",
errorOrCreatedService.value
errorOrCreatedService.left
);
}

const createdService = errorOrCreatedService.value;
const createdService = errorOrCreatedService.right;

const upsertServiceEvent = UpsertServiceEvent.encode({
newService: createdService,
Expand Down
16 changes: 8 additions & 8 deletions CreateSubscription/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
SubscriptionContract,
UserContract
} from "@azure/arm-apimanagement/esm/models";
import { isRight, left, right } from "fp-ts/lib/Either";
import { fromEither, fromLeft } from "fp-ts/lib/TaskEither";
import * as E from "fp-ts/lib/Either";
import * as TE from "fp-ts/lib/TaskEither";
import { ProductNamePayload } from "../../generated/definitions/ProductNamePayload";
import { UserInfo } from "../../generated/definitions/UserInfo";
import * as ApimUtils from "../../utils/apim";
Expand Down Expand Up @@ -85,7 +85,7 @@ mockApiManagementClient.mockImplementation(() => ({

const spyOnGetApiClient = jest.spyOn(ApimUtils, "getApiClient");
spyOnGetApiClient.mockImplementation(() =>
fromEither(right(new mockApiManagementClient()))
TE.of(new mockApiManagementClient())
);

const mockLog = jest.fn();
Expand All @@ -95,7 +95,7 @@ const mockedContext = { log: { error: mockLog } };
describe("CreateSubscription", () => {
it("should return an internal error response if the API management client can not be got", async () => {
spyOnGetApiClient.mockImplementationOnce(() =>
fromLeft(Error("Error from ApiManagementClient constructor"))
TE.left(Error("Error from ApiManagementClient constructor"))
);

const createSubscriptionHandler = CreateSubscriptionHandler(
Expand Down Expand Up @@ -309,10 +309,10 @@ describe("CreateSubscription", () => {
expect(response).toEqual({
apply: expect.any(Function),
kind: "IResponseSuccessJson",
value: subscriptionContractToApiSubscription(
aFakeApimSubscriptionContract
).value
value: E.toUnion(
subscriptionContractToApiSubscription(aFakeApimSubscriptionContract)
)
});
expect(isRight(UserInfo.decode((response as any).value))).toBeTruthy();
expect(E.isRight(UserInfo.decode((response as any).value))).toBeTruthy();
});
});
132 changes: 71 additions & 61 deletions CreateSubscription/handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Context } from "@azure/functions";
import * as express from "express";
import { fromEither, fromPredicate, tryCatch } from "fp-ts/lib/TaskEither";
import * as TE from "fp-ts/lib/TaskEither";
import {
AzureApiAuthMiddleware,
IAzureApiAuthorization,
Expand All @@ -22,6 +22,7 @@ import {
ResponseSuccessJson
} from "@pagopa/ts-commons/lib/responses";
import { NonEmptyString } from "@pagopa/ts-commons/lib/strings";
import { flow, pipe } from "fp-ts/lib/function";
import { EmailAddress } from "../generated/definitions/EmailAddress";
import { ProductNamePayload } from "../generated/definitions/ProductNamePayload";
import { Subscription } from "../generated/definitions/Subscription";
Expand Down Expand Up @@ -75,15 +76,13 @@ export function CreateSubscriptionHandler(
errors,
errorMessage
);
const response = await getApiClient(
servicePrincipalCreds,
azureApimConfig.subscriptionId
)
.mapLeft<IResponseErrorInternal | IResponseErrorNotFound>(error =>
return pipe(
getApiClient(servicePrincipalCreds, azureApimConfig.subscriptionId),
TE.mapLeft(error =>
internalErrorHandler("Could not get the APIM client.", error)
)
.chain(apimClient =>
tryCatch(
),
TE.chainW(apimClient =>
TE.tryCatch(
() =>
apimClient.user
.listByService(
Expand All @@ -103,77 +102,88 @@ export function CreateSubscriptionHandler(
error as Error
)
)
)
.chain(
fromPredicate(
),
TE.chainW(
TE.fromPredicate(
taskResults => taskResults.userList.length !== 0,
() =>
ResponseErrorNotFound(
"Not found",
"The provided user does not exist"
)
)
)
.chain(taskResults =>
fromEither(NonEmptyString.decode(taskResults.userList[0].id))
.mapLeft(errors =>
),
TE.chainW(taskResults =>
pipe(
taskResults.userList[0].id,
NonEmptyString.decode,
TE.fromEither,
TE.mapLeft(errors =>
internalValidationErrorHandler(
"Could not get user id from user contract.",
errors
)
)
.map(userId => ({
),
TE.map(userId => ({
apimClient: taskResults.apimClient,
userId
}))
)
.chain(taskResults =>
tryCatch(
() =>
taskResults.apimClient.product.listByService(
azureApimConfig.apimResourceGroup,
azureApimConfig.apim,
{
filter: `name eq '${productNamePayload.product_name}'`
}
),
error =>
internalErrorHandler(
"Could not list the products by name.",
error as Error
)
).map(productList => ({
apimClient: taskResults.apimClient,
productList,
userId: taskResults.userId
}))
)
.chain(
fromPredicate(
)
),
TE.chainW(taskResults =>
pipe(
TE.tryCatch(
() =>
taskResults.apimClient.product.listByService(
azureApimConfig.apimResourceGroup,
azureApimConfig.apim,
{
filter: `name eq '${productNamePayload.product_name}'`
}
),
error =>
internalErrorHandler(
"Could not list the products by name.",
error as Error
)
),
TE.map(productList => ({
apimClient: taskResults.apimClient,
productList,
userId: taskResults.userId
}))
)
),
TE.chainW(
TE.fromPredicate(
taskResults => taskResults.productList.length !== 0,
() =>
ResponseErrorNotFound(
"Not found",
"The provided product does not exist"
)
)
)
.chain(taskResults =>
fromEither(NonEmptyString.decode(taskResults.productList[0].id))
.mapLeft(errors =>
),
TE.chainW(taskResults =>
pipe(
taskResults.productList[0].id,
NonEmptyString.decode,
TE.fromEither,
TE.mapLeft(errors =>
internalValidationErrorHandler(
"Could not get product id from product contract.",
errors
)
)
.map(productId => ({
),
TE.map(productId => ({
apimClient: taskResults.apimClient,
productId,
userId: taskResults.userId
}))
)
.chain(taskResults =>
tryCatch(
)
),
TE.chainW(taskResults =>
TE.tryCatch(
() =>
taskResults.apimClient.subscription.createOrUpdate(
azureApimConfig.apimResourceGroup,
Expand All @@ -192,22 +202,22 @@ export function CreateSubscriptionHandler(
error as Error
)
)
)
.chain(subscriptionResponse =>
fromEither(
subscriptionContractToApiSubscription(
subscriptionResponse
).mapLeft(error =>
),
TE.chainW(
flow(
subscriptionContractToApiSubscription,
TE.fromEither,
TE.mapLeft(error =>
internalErrorHandler(
"Invalid subscription contract from APIM.",
error
)
)
)
)
.map(ResponseSuccessJson)
.run();
return response.value;
),
TE.map(ResponseSuccessJson),
TE.toUnion
)();
};
}

Expand Down
Loading

0 comments on commit 0a2d30d

Please sign in to comment.