Skip to content

Commit

Permalink
Merge pull request #91 from palantir/mf/multilink-object-set
Browse files Browse the repository at this point in the history
Convert multi-links to a full BaseObjectSet
  • Loading branch information
mfedderly authored Feb 23, 2024
2 parents 862e6f3 + 8b78ebd commit 7e67bb1
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 487 deletions.
5 changes: 5 additions & 0 deletions packages/client/changelog/@unreleased/pr-91.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: improvement
improvement:
description: Convert multi-links to a full BaseObjectSet
links:
- https://github.com/palantir/osdk-ts/pull/91
88 changes: 4 additions & 84 deletions packages/client/src/definitions/LinkDefinitions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@

import type { ObjectTypeDefinition } from "@osdk/api";
import { describe, expectTypeOf, it } from "vitest";
import type {
FetchPageOrThrowArgs,
SelectArg,
} from "../object/fetchPageOrThrow.js";
import type { Osdk, OsdkObjectPrimaryKeyType } from "../OsdkObjectFrom.js";
import type { PageResult } from "../PageResult.js";
import type { SelectArg } from "../object/fetchPageOrThrow.js";
import type { BaseObjectSet } from "../objectSet/ObjectSet.js";
import type { Osdk } from "../OsdkObjectFrom.js";
import type { MockOntology } from "../util/test/mockOntology.js";
import type {
DefaultToFalse,
MultiLinkAccessor,
OsdkObjectLinksObject,
SingleLinkAccessor,
} from "./LinkDefinitions.js";
Expand All @@ -48,7 +44,7 @@ describe("LinkDefinitions", () => {
expectTypeOf<OsdkObjectLinksObject<TaskDef>>()
.toEqualTypeOf<
{
Todos: MultiLinkAccessor<TodoDef>;
Todos: BaseObjectSet<TodoDef>;
RP: SingleLinkAccessor<PersonDef>;
}
>();
Expand Down Expand Up @@ -106,81 +102,5 @@ describe("LinkDefinitions", () => {
.toEqualTypeOf<Osdk<PersonDef, "name">>();
});
});

describe("MultitonLinkAccessor", () => {
it("infers select properly", () => {
// this helper lets us get return types of functions that are generic
class Helper<
T extends ObjectTypeDefinition<any, any>,
const A extends SelectArg<T>,
> {
constructor(private accessor: MultiLinkAccessor<T>) {}

public fetchPage() {
return this.accessor.fetchPageOrThrow<A>();
}

public get(pk: OsdkObjectPrimaryKeyType<T>) {
return this.accessor.get<A>({} as any);
}
}

// e.g. fetchPageOrThrow({});
expectTypeOf<Awaited<ReturnType<Helper<TodoDef, {}>["fetchPage"]>>>()
.toEqualTypeOf<PageResult<Osdk<TodoDef, "$all">>>();

// e.g. fetchPageOrThrow({ select: [] });
expectTypeOf<
Awaited<ReturnType<Helper<TodoDef, { select: [] }>["fetchPage"]>>
>()
.toEqualTypeOf<PageResult<Osdk<TodoDef, "$all">>>();

// e.g. fetchPageOrThrow()
expectTypeOf<
Awaited<
ReturnType<
Helper<TodoDef, FetchPageOrThrowArgs<TodoDef>>["fetchPage"]
>
>
>()
.toEqualTypeOf<PageResult<Osdk<TodoDef, "$all">>>();

// e.g. fetchPageOrThrow({ select: ["text"]}
expectTypeOf<
Awaited<
ReturnType<Helper<TodoDef, { select: ["text"] }>["fetchPage"]>
>
>()
.toEqualTypeOf<PageResult<Osdk<TodoDef, "text">>>();

// e.g. .peeps.get("", {});
expectTypeOf<Awaited<ReturnType<Helper<PersonDef, {}>["get"]>>>()
.toEqualTypeOf<Osdk<PersonDef, "$all">>();

// e.g. .peeps.get("");
expectTypeOf<
Awaited<
ReturnType<Helper<PersonDef, SelectArg<PersonDef>>["get"]>
>
>()
.toEqualTypeOf<Osdk<PersonDef, "$all">>();

// e.g. .peeps.get("", { select: [] });
expectTypeOf<
Awaited<
ReturnType<Helper<PersonDef, { select: [] }>["get"]>
>
>()
.toEqualTypeOf<Osdk<PersonDef, "$all">>();

// e.g. .peeps.get("", { select: ["name"] });
expectTypeOf<
Awaited<
ReturnType<Helper<PersonDef, { select: ["name"] }>["get"]>
>
>()
.toEqualTypeOf<Osdk<PersonDef, "name">>();
});
});
});
});
47 changes: 4 additions & 43 deletions packages/client/src/definitions/LinkDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,9 @@ import type {
ObjectTypeLinkDefinition,
ObjectTypeLinkKeysFrom2,
} from "@osdk/api";
import type {
FetchPageOrThrowArgs,
SelectArg,
SelectArgToKeys,
} from "../object/fetchPageOrThrow.js";
import type { Osdk, OsdkObjectPrimaryKeyType } from "../OsdkObjectFrom.js";
import type { PageResult } from "../PageResult.js";
import type { SelectArg, SelectArgToKeys } from "../object/fetchPageOrThrow.js";
import type { BaseObjectSet } from "../objectSet/ObjectSet.js";
import type { Osdk } from "../OsdkObjectFrom.js";

/** The $link container to get from one object type to its linked objects */
export type OsdkObjectLinksObject<
Expand All @@ -39,7 +35,7 @@ export type OsdkObjectLinksEntry<
O extends ObjectTypeDefinition<any>,
L extends ObjectTypeLinkKeysFrom2<O>,
> = O["links"][L] extends ObjectTypeLinkDefinition<infer T, infer M> ? (
M extends false ? SingleLinkAccessor<T> : MultiLinkAccessor<T>
M extends false ? SingleLinkAccessor<T> : BaseObjectSet<T>
)
: never;

Expand All @@ -64,38 +60,3 @@ export interface SingleLinkAccessor<T extends ObjectTypeDefinition<any>> {
: Osdk<T, SelectArgToKeys<T, A>, DefaultToFalse<A["includeRid"]>>
>;
}

// note to future editor: these types may look gross but they were specifically
// written to make it clear what the return type is when you use intellisense.
// sorry i have no way to test this right now (ever?)

export interface MultiLinkAccessor<T extends ObjectTypeDefinition<any>> {
get: <
const A extends SelectArg<
T,
ObjectOrInterfacePropertyKeysFrom2<T>,
boolean
>,
>(
pk: OsdkObjectPrimaryKeyType<T>,
options?: A,
) => Promise<
DefaultToFalse<A["includeRid"]> extends false
? Osdk<T, SelectArgToKeys<T, A>>
: Osdk<T, SelectArgToKeys<T, A>, DefaultToFalse<A["includeRid"]>>
>;

fetchPageOrThrow: <
const A extends FetchPageOrThrowArgs<
T,
ObjectOrInterfacePropertyKeysFrom2<T>,
boolean
>,
>(options?: A) => Promise<
PageResult<
DefaultToFalse<A["includeRid"]> extends false
? Osdk<T, SelectArgToKeys<T, A>>
: Osdk<T, SelectArgToKeys<T, A>, DefaultToFalse<A["includeRid"]>>
>
>;
}
45 changes: 11 additions & 34 deletions packages/client/src/object/convertWireToOsdkObjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ import type { OntologyDefinition } from "@osdk/api";
import type { OntologyObjectV2 } from "@osdk/gateway/types";
import type { ClientContext } from "@osdk/shared.net";
import { createCachedOntologyTransform } from "../createCachedOntologyTransform.js";
import { createBaseObjectSet } from "../objectSet/createObjectSet.js";
import { Attachment } from "./Attachment.js";
import type { FetchPageOrThrowArgs, SelectArg } from "./fetchPageOrThrow.js";
import { getLinkedObjectByPkOrThrow } from "./getLinkedObjectByPkOrThrow.js";
import { getLinkedObjectOrThrow } from "./getLinkedObjectOrThrow.js";
import { pageLinkedObjectsOrThrow } from "./pageLinkedObjectsOrThrow.js";
import type { SelectArg } from "./fetchPageOrThrow.js";
import { fetchSingle } from "./fetchSingle.js";

const getPrototype = createCachedOntologyTransform(createPrototype);
const getConverter = createCachedOntologyTransform(createConverter);
Expand Down Expand Up @@ -55,44 +54,22 @@ function createPrototype<
return;
}

const objectSet = createBaseObjectSet(objDef, client).where({
[objDef.primaryKeyApiName]: primaryKey,
}).pivotTo(p);

if (!linkDef.multiplicity) {
return {
get: <A extends SelectArg<any>>(options?: A) =>
getLinkedObjectOrThrow(
client,
ontology.objects[type],
primaryKey,
p,
options ?? {},
),
};
} else {
return {
get: <A extends SelectArg<any>>(
targetPrimaryKey: any,
options?: A,
) =>
getLinkedObjectByPkOrThrow(
fetchSingle(
client,
objDef,
primaryKey,
p,
targetPrimaryKey,
options,
),
fetchPageOrThrow: (
options: FetchPageOrThrowArgs<
O["objects"][typeof linkDef.targetType]
> = {},
) =>
pageLinkedObjectsOrThrow(
client,
objDef,
primaryKey,
p,
options ?? {},
objectSet.definition,
),
};
} else {
return objectSet;
}
},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Palantir Technologies, Inc. All rights reserved.
* Copyright 2024 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,41 +15,35 @@
*/

import type { ObjectOrInterfaceDefinition } from "@osdk/api";
import type { ObjectSet } from "@osdk/gateway/types";
import { type ClientContext, PalantirApiError } from "@osdk/shared.net";
import type { Osdk } from "../index.js";
import {
fetchPageOrThrow,
type FetchPageOrThrowArgs,
type SelectArgToKeys,
} from "./fetchPageOrThrow.js";

import type { DefaultToFalse } from "../definitions/LinkDefinitions.js";
import type { LinkedType, LinkNames } from "../objectSet/LinkUtils.js";
import type { Osdk } from "../OsdkObjectFrom.js";
import type { SelectArg, SelectArgToKeys } from "./fetchPageOrThrow.js";
import { pageLinkedObjectsOrThrow } from "./pageLinkedObjectsOrThrow.js";

export async function getLinkedObjectOrThrow<
export async function fetchSingle<
Q extends ObjectOrInterfaceDefinition,
L extends LinkNames<Q>,
const A extends SelectArg<LinkedType<Q, L>>,
const A extends FetchPageOrThrowArgs<Q, any, any>,
>(
client: ClientContext<any>,
source: Q,
primaryKey: any,
linkTypeApiName: L,
options: A,
objectType: Q,
args: A,
objectSet: ObjectSet,
): Promise<
DefaultToFalse<A["includeRid"]> extends false ? Osdk<
LinkedType<Q, L>,
SelectArgToKeys<LinkedType<Q, L>, A>
>
: Osdk<
LinkedType<Q, L>,
SelectArgToKeys<LinkedType<Q, L>, A>,
true
>
Osdk<
Q,
SelectArgToKeys<Q, A>,
A["includeRid"] extends true ? true : false
>
> {
const result = await pageLinkedObjectsOrThrow(
const result = await fetchPageOrThrow(
client,
source,
primaryKey,
linkTypeApiName,
{ pageSize: 1, select: options.select, includeRid: options.includeRid },
objectType,
{ ...args, pageSize: 1 },
objectSet,
);

if (result.data.length !== 1 || result.nextPageToken != null) {
Expand Down
73 changes: 0 additions & 73 deletions packages/client/src/object/getLinkedObjectByPkOrThrow.test.ts

This file was deleted.

Loading

0 comments on commit 7e67bb1

Please sign in to comment.