Skip to content

Commit

Permalink
BREAKING CHANGE: [DEVEX-106] Update Cosmos SDK (#371)
Browse files Browse the repository at this point in the history
Co-authored-by: Emanuele De Cupis <emanuele.decupis@pagopa.it>
  • Loading branch information
lucacavallaro and Emanuele De Cupis authored Apr 3, 2024
1 parent 583b2c0 commit efa2969
Show file tree
Hide file tree
Showing 15 changed files with 148,893 additions and 2,312 deletions.
147,529 changes: 147,529 additions & 0 deletions .yarn/releases/yarn-classic.cjs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yarnPath: .yarn/releases/yarn-classic.cjs
4 changes: 2 additions & 2 deletions __integrations__/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@types/jest": "^25.2.1",
"@types/node": "~18.13.0",
"dotenv-cli": "^4.1.0",
"jest": "^25.2.7",
"ts-jest": "^25.3.1"
"jest": "^29.7.0",
"ts-jest": "^29.1.2"
}
}
3,357 changes: 1,109 additions & 2,248 deletions __integrations__/yarn.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"io-ts": "^2.2.21"
},
"dependencies": {
"@azure/cosmos": "^3.17.1",
"@azure/cosmos": "^4.0.0",
"@azure/data-tables": "^13.2.2",
"@pagopa/ts-commons": "^12.6.0",
"applicationinsights": "^2.9.5",
Expand Down Expand Up @@ -104,5 +104,6 @@
},
"resolutions": {
"graceful-fs": "^4.2.4"
}
},
"packageManager": "yarn@4.1.1"
}
7 changes: 5 additions & 2 deletions src/models/__tests__/message.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
} from "../message";

jest.mock("../../utils/azure_storage");
import { Container, ResourceResponse } from "@azure/cosmos";
import { Container, CosmosDiagnostics, ResourceResponse } from "@azure/cosmos";
import { MessageSubject } from "../../../generated/definitions/MessageSubject";
import { ServiceId } from "../../../generated/definitions/ServiceId";
import { TimeToLiveSeconds } from "../../../generated/definitions/TimeToLiveSeconds";
Expand Down Expand Up @@ -648,6 +648,7 @@ describe("findMessageForRecipient", () => {
},
{},
200,
new CosmosDiagnostics(),
200
)
);
Expand Down Expand Up @@ -675,7 +676,9 @@ describe("findMessageForRecipient", () => {
it("should return an empty value if the recipient doesn't match", async () => {
const readMock = jest
.fn()
.mockResolvedValueOnce(new ResourceResponse(undefined, {}, 200, 200));
.mockResolvedValueOnce(
new ResourceResponse(undefined, {}, 200, new CosmosDiagnostics(), 200)
);
const containerMock = ({
item: jest.fn().mockReturnValue({ read: readMock })
} as unknown) as Container;
Expand Down
3 changes: 2 additions & 1 deletion src/models/__tests__/message_status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "@pagopa/ts-commons/lib/numbers";
import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings";

import { Container, ResourceResponse } from "@azure/cosmos";
import { Container, CosmosDiagnostics, ResourceResponse } from "@azure/cosmos";
import { readableReport } from "@pagopa/ts-commons/lib/reporters";
import { NotRejectedMessageStatusValueEnum as MessageStatusValueEnum } from "../../../generated/definitions/NotRejectedMessageStatusValue";
import { RejectedMessageStatusValueEnum } from "../../../generated/definitions/RejectedMessageStatusValue";
Expand Down Expand Up @@ -84,6 +84,7 @@ mockCreateItem.mockImplementation(
{ ...doc, _etag: "_etag", _rid: "_rid", _self: "_self", _ts: 1 },
{},
200,
new CosmosDiagnostics(),
200
)
);
Expand Down
15 changes: 13 additions & 2 deletions src/models/__tests__/user_data_processing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import * as E from "fp-ts/lib/Either";
import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers";
import { FiscalCode } from "../../../generated/definitions/FiscalCode";

import { Container, FeedResponse, ResourceResponse } from "@azure/cosmos";
import {
Container,
CosmosDiagnostics,
FeedResponse,
ResourceResponse
} from "@azure/cosmos";
import { NonEmptyString } from "@pagopa/ts-commons/lib/strings";
import { UserDataProcessingChoiceEnum } from "../../../generated/definitions/UserDataProcessingChoice";
import { UserDataProcessingStatusEnum } from "../../../generated/definitions/UserDataProcessingStatus";
Expand Down Expand Up @@ -82,13 +87,19 @@ describe("createOrUpdateByNewOne", () => {
},
{},
200,
new CosmosDiagnostics(),
200
)
),
query: jest.fn(() => ({
fetchAll: jest.fn(() =>
Promise.resolve(
new FeedResponse([aRetrievedUserDataProcessing], {}, false)
new FeedResponse(
[aRetrievedUserDataProcessing],
{},
false,
new CosmosDiagnostics()
)
)
)
}))
Expand Down
48 changes: 45 additions & 3 deletions src/utils/__tests__/cosmosdb_model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ import * as t from "io-ts";
import * as E from "fp-ts/lib/Either";
import * as O from "fp-ts/lib/Option";

import { Container, ErrorResponse, ResourceResponse } from "@azure/cosmos";
import {
Container,
CosmosDiagnostics,
ErrorResponse,
ResourceResponse
} from "@azure/cosmos";

import { NonEmptyString } from "@pagopa/ts-commons/lib/strings";
import { BaseModel, CosmosdbModel, CosmosResource } from "../cosmosdb_model";
import {
BaseModel,
CosmosdbModel,
CosmosResource,
DocumentSearchKey
} from "../cosmosdb_model";

beforeEach(() => {
jest.resetAllMocks();
Expand Down Expand Up @@ -77,6 +87,34 @@ const errorResponse: ErrorResponse = new Error();
// eslint-disable-next-line functional/immutable-data
errorResponse.code = 500;

type Equal<X, Y extends X> = X extends Y ? (Y extends X ? X : never) : never;

describe("DocumentSearchKey", () => {
type MyModel = { foo: string; bar: number; baz: boolean[] };

// alway allow id as a search key
type _0 = Equal<DocumentSearchKey<MyModel, "id">, readonly [string]>;
// allow a string as partition key
type _1 = Equal<
DocumentSearchKey<MyModel, "id", "foo">,
readonly [string, string]
>;
// same model and partition key
type _2 = Equal<DocumentSearchKey<MyModel, "foo", "foo">, readonly [string]>;
// @ts-expect-error MyModel["bar"] is not a string
type _3 = Equal<DocumentSearchKey<MyModel, "bar">, readonly [string]>;
// @ ts-expect-error MyModel["baz"] is not a string or number
type _4 = Equal<
DocumentSearchKey<MyModel, "id", "baz">,
// @ts-expect-error
readonly [string, string]
>;
// allow custom fields as search key
type _5 = Equal<DocumentSearchKey<MyModel, "foo">, readonly [string]>;
// @ts-expect-error "pippo" is not a field of MyModel
type _6 = Equal<DocumentSearchKey<MyModel, "pippo">, readonly [string]>;
});

describe("create", () => {
it("should create a document", async () => {
containerMock.items.create.mockResolvedValueOnce(
Expand All @@ -87,6 +125,7 @@ describe("create", () => {
},
{},
200,
new CosmosDiagnostics(),
200
)
);
Expand Down Expand Up @@ -174,6 +213,7 @@ describe("upsert", () => {
},
{},
200,
new CosmosDiagnostics(),
200
)
);
Expand Down Expand Up @@ -202,6 +242,7 @@ describe("find", () => {
},
{},
200,
new CosmosDiagnostics(),
200
)
);
Expand Down Expand Up @@ -230,6 +271,7 @@ describe("find", () => {
},
{},
200,
new CosmosDiagnostics(),
200
)
);
Expand All @@ -252,7 +294,7 @@ describe("find", () => {
it("should return an empty option if the document does not exist", async () => {
readMock.mockResolvedValueOnce(
// TODO: check whether this is what the client actually returns
new ResourceResponse(undefined, {}, 200, 200)
new ResourceResponse(undefined, {}, 200, new CosmosDiagnostics(), 200)
);
containerMock.item.mockReturnValue({ read: readMock });
const model = new MyModel(container);
Expand Down
81 changes: 63 additions & 18 deletions src/utils/__tests__/cosmosdb_model_composed_versioned.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import { NonEmptyString } from "@pagopa/ts-commons/lib/strings";
import { CosmosdbModelComposedVersioned, generateComposedVersionedModelId } from "../cosmosdb_model_composed_versioned";
import {
CosmosdbModelComposedVersioned,
generateComposedVersionedModelId
} from "../cosmosdb_model_composed_versioned";
import * as t from "io-ts";
import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers";
import { RetrievedVersionedModel } from "../cosmosdb_model_versioned";
import { BaseModel } from "../cosmosdb_model";
import { Container, ErrorResponse, FeedResponse, ResourceResponse } from "@azure/cosmos";
import {
Container,
CosmosDiagnostics,
ErrorResponse,
FeedResponse,
ResourceResponse
} from "@azure/cosmos";
import * as E from "fp-ts/lib/Either";
import * as O from "fp-ts/lib/Option";

const cosmosDiagnostics = new CosmosDiagnostics();

const aModelExternalKeyId = "aModelExternalKeyId" as const;
const aModelPartitionField = "aModelPartitionField" as const;
const aModelExternalKeyValue = "aModelExternalKeyValue";
Expand All @@ -21,12 +32,16 @@ const MyDocument = t.interface({
type MyDocument = t.TypeOf<typeof MyDocument>;

// test stub that compose a document id from the tuple (externalKey, partitionKey, version)
const documentId = (externalKey: string, partitionKey: number, version: number): NonEmptyString =>
generateComposedVersionedModelId<MyDocument, typeof aModelExternalKeyId, typeof aModelPartitionField>(
externalKey,
partitionKey,
version as NonNegativeInteger
);
const documentId = (
externalKey: string,
partitionKey: number,
version: number
): NonEmptyString =>
generateComposedVersionedModelId<
MyDocument,
typeof aModelExternalKeyId,
typeof aModelPartitionField
>(externalKey, partitionKey, version as NonNegativeInteger);

const RetrievedMyDocument = t.intersection([
MyDocument,
Expand All @@ -43,7 +58,13 @@ class MyComposedModel extends CosmosdbModelComposedVersioned<
typeof aModelPartitionField
> {
constructor(c: Container) {
super(c, MyDocument, RetrievedMyDocument, aModelExternalKeyId, aModelPartitionField);
super(
c,
MyDocument,
RetrievedMyDocument,
aModelExternalKeyId,
aModelPartitionField
);
}
}

Expand Down Expand Up @@ -71,9 +92,11 @@ const containerMock = {
items: {
create: jest
.fn()
.mockImplementation(async doc => new ResourceResponse(doc, {}, 200, 200)),
.mockImplementation(
async doc => new ResourceResponse(doc, {}, 200, cosmosDiagnostics, 200)
),
query: jest.fn().mockReturnValue({
fetchAll: async () => new FeedResponse([], {}, false)
fetchAll: async () => new FeedResponse([], {}, false, cosmosDiagnostics)
}),
upsert: jest.fn()
}
Expand All @@ -99,7 +122,12 @@ describe("upsert", () => {
containerMock.items.query.mockReturnValueOnce({
fetchAll: async () =>
// if currentlyOnDb is undefined return empty array
new FeedResponse([currentlyOnDb].filter(Boolean), {}, false)
new FeedResponse(
[currentlyOnDb].filter(Boolean),
{},
false,
cosmosDiagnostics
)
});

const model = new MyComposedModel(container);
Expand All @@ -108,7 +136,11 @@ describe("upsert", () => {
expect(containerMock.items.create).toHaveBeenCalledWith(
{
...document,
id: documentId(document[aModelExternalKeyId], document[aModelPartitionField], expectedVersion),
id: documentId(
document[aModelExternalKeyId],
document[aModelPartitionField],
expectedVersion
),
version: expectedVersion
},
{ disableAutomaticIdGeneration: true }
Expand All @@ -118,7 +150,11 @@ describe("upsert", () => {
expect(result.right).toEqual({
...document,
...someMetadata,
id: documentId(document[aModelExternalKeyId], document[aModelPartitionField], expectedVersion),
id: documentId(
document[aModelExternalKeyId],
document[aModelPartitionField],
expectedVersion
),
version: expectedVersion
});
}
Expand All @@ -143,7 +179,8 @@ describe("upsert", () => {

it("should fail on query error when creating next version", async () => {
containerMock.items.query.mockReturnValueOnce({
fetchAll: () => Promise.resolve(new FeedResponse([], {}, false))
fetchAll: () =>
Promise.resolve(new FeedResponse([], {}, false, cosmosDiagnostics))
});
containerMock.items.create.mockRejectedValueOnce(errorResponse);
const model = new MyComposedModel(container);
Expand Down Expand Up @@ -235,7 +272,10 @@ describe("findLastVersionByModelId", () => {
fetchAll: () => Promise.reject(errorResponse)
});
const model = new MyComposedModel(container);
const result = await model.findLastVersionByModelId([aModelExternalKeyValue, aModelPartitionValue])();
const result = await model.findLastVersionByModelId([
aModelExternalKeyValue,
aModelPartitionValue
])();
expect(E.isLeft(result));
if (E.isLeft(result)) {
expect(result.left.kind).toBe("COSMOS_ERROR_RESPONSE");
Expand All @@ -257,9 +297,14 @@ describe("typings restrictions", () => {
typeof aModelExternalKeyId
> {
constructor(c: Container) {
super(c, MyDocument, RetrievedMyDocument, aModelExternalKeyId, aModelExternalKeyId);
super(
c,
MyDocument,
RetrievedMyDocument,
aModelExternalKeyId,
aModelExternalKeyId
);
}
}
});
});

Loading

0 comments on commit efa2969

Please sign in to comment.