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

[DEVEX-106] Fix proposal #372

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/utils/__tests__/cosmosdb_model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import {
} 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 @@ -82,6 +87,27 @@ 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">, [string]>;
// allow a string as partition key
type _1 = Equal<DocumentSearchKey<MyModel, "id", "foo">, [string, string]>;
// same model and partition key
type _2 = Equal<DocumentSearchKey<MyModel, "foo", "foo">, [string]>;
// @ts-expect-error MyModel["bar"] is not a string
type _3 = Equal<DocumentSearchKey<MyModel, "bar">, [string]>;
// @ts-expect-error MyModel["baz"] is not a string or number
type _4 = Equal<DocumentSearchKey<MyModel, "id", "baz">, [string, string]>;
// allow custom fields as search key
type _5 = Equal<DocumentSearchKey<MyModel, "foo">, [string]>;
// @ts-expect-error "pippo" is not a field of MyModel
type _6 = Equal<DocumentSearchKey<MyModel, "pippo">, [string]>;
});

describe("create", () => {
it("should create a document", async () => {
containerMock.items.create.mockResolvedValueOnce(
Expand Down
20 changes: 13 additions & 7 deletions src/utils/cosmosdb_model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,19 @@ export type DocumentSearchKey<
// Hence we omit "extends BaseModel", but we check keys to be part of "T & BaseModel"
ModelIdKey extends keyof (T & BaseModel),
PartitionKey extends keyof (T & BaseModel) = ModelIdKey
> = (T & BaseModel)[ModelIdKey] extends string // narrow type to the ones that might be an identity
? PartitionKey extends ModelIdKey // eslint-disable-next-line functional/prefer-readonly-type
? [(T & BaseModel)[ModelIdKey]] // eslint-disable-next-line functional/prefer-readonly-type
: PartitionKey extends keyof (T & BaseModel) // eslint-disable-next-line functional/prefer-readonly-type
? [(T & BaseModel)[ModelIdKey], (T & BaseModel)[PartitionKey]]
: never
: never;
> =
// We must be sure the provided keys refer to fields whose value is appropriate
// the modelId must be a string
// the partitiion key might be a string or a number
Pick<BaseModel & T, ModelIdKey | PartitionKey> extends Record<
ModelIdKey,
string
> &
Record<PartitionKey, string | number>
? PartitionKey extends ModelIdKey // partition key === model id means no partition key is provided
lucacavallaro marked this conversation as resolved.
Show resolved Hide resolved
? readonly [string]
: readonly [string, string | number]
Copy link
Member

@lucacavallaro lucacavallaro Mar 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should also support boolean (?)

Suggested change
: readonly [string, string | number]
: readonly [string, string | number | boolean]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically yes. What boolean partition key you imagine to use?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't imagine any! I was just wondering to "adhere" to the PrimaryKey type of @azure/cosmos which puts it among the supported scalars

: never;

export type AzureCosmosResource = t.TypeOf<typeof AzureCosmosResource>;
export const AzureCosmosResource = t.interface({
Expand Down
14 changes: 2 additions & 12 deletions src/utils/cosmosdb_model_versioned.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,8 @@ const getPartitionKeyFromSearchKey = <
PartitionKey extends keyof T = ModelIdKey
>(
searchKey: DocumentSearchKey<T, ModelIdKey, PartitionKey>
): CosmosPartitionKey => {
const value: unknown =
typeof searchKey[1] !== "undefined" ? searchKey[1] : searchKey[0];
if (
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean"
) {
return value;
}
return null;
};
): CosmosPartitionKey =>
typeof searchKey[1] === "undefined" ? searchKey[0] : searchKey[1];

/**
* Assumption: the model ID is also the partition key
Expand Down
Loading