From 93b6a91f1f88d325c516746d6ae2ad03eddd7e90 Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 09:56:40 -0500 Subject: [PATCH 01/11] second attempt bulk actions --- .../ontology/actions/BulkActions.ts | 44 +++ .../ontology/actions/BulkActions.ts | 35 ++ .../src/v1.1/generateBulkActions.test.ts | 60 +++ .../generator/src/v1.1/generateBulkActions.ts | 139 +++++++ .../v1.1/generateClientSdkVersionOneDotOne.ts | 3 + .../src/v1.1/generateMetadataFile.test.ts | 6 + .../src/v1.1/generateMetadataFile.ts | 2 + .../src/client/actions/actions.test.ts | 362 +++++++++++++----- .../src/client/actions/actions.ts | 52 ++- .../src/client/actions/createActionProxy.ts | 82 +++- .../src/client/baseTypes/ActionType.ts | 77 +++- .../src/client/net/executeAction.ts | 78 +++- packages/legacy-client/src/client/ontology.ts | 11 +- packages/legacy-client/src/index.ts | 2 + .../src/handlers/actionEndpoints.ts | 42 ++ packages/shared.test/src/stubs/actions.ts | 76 ++++ 16 files changed, 945 insertions(+), 126 deletions(-) create mode 100644 examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts create mode 100644 examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts create mode 100644 packages/generator/src/v1.1/generateBulkActions.test.ts create mode 100644 packages/generator/src/v1.1/generateBulkActions.ts diff --git a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts new file mode 100644 index 000000000..50c101254 --- /dev/null +++ b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts @@ -0,0 +1,44 @@ +import type { + ActionError, + Attachment, + BulkActionExecutionOptions, + BulkActionResponseFromOptions, + Edits, + LocalDate, + ObjectSet, + Result, + Timestamp, +} from '@osdk/legacy-client'; +import type { ObjectTypeWithAllPropertyTypes } from '../objects/ObjectTypeWithAllPropertyTypes'; +import type { Person } from '../objects/Person'; +import type { Todo } from '../objects/Todo'; +export interface Actions { + /** + * An action which takes different types of parameters + * @param {ObjectSet} params.objectSet + * @param {Person | Person["__primaryKey"]} params.object + * @param {string} params.string + * @param {Timestamp} params.time-stamp + * @param {Array} params.dateArray + * @param {Array} params.attachmentArray + */ + actionTakesAllParameterTypes( + params: { + objectSet: ObjectSet; + object?: Person | Person['__primaryKey']; + string: string; + 'time-stamp': Timestamp; + dateArray?: Array; + attachmentArray: Array; + }[], + options?: O, + ): Promise>, ActionError>>; + + /** + * Creates a new Todo + */ + createTodo( + [], + options?: O, + ): Promise>, ActionError>>; +} diff --git a/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts b/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts new file mode 100644 index 000000000..6c29ef632 --- /dev/null +++ b/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts @@ -0,0 +1,35 @@ +import type { + ActionError, + BulkActionExecutionOptions, + BulkActionResponseFromOptions, + Edits, + Result, +} from '@osdk/legacy-client'; +import type { Todo } from '../objects/Todo'; +export interface Actions { + /** + * Creates Todo + * @param {string} params.Todo + * @param {boolean} params.is_complete + */ + createTodo( + params: { + Todo: string; + is_complete: boolean; + }[], + options?: O, + ): Promise>, ActionError>>; + + /** + * Completes Todo + * @param {Todo | Todo["__primaryKey"]} params.Todo + * @param {boolean} params.is_complete + */ + completeTodo( + params: { + Todo: Todo | Todo['__primaryKey']; + is_complete: boolean; + }[], + options?: O, + ): Promise>, ActionError>>; +} diff --git a/packages/generator/src/v1.1/generateBulkActions.test.ts b/packages/generator/src/v1.1/generateBulkActions.test.ts new file mode 100644 index 000000000..462aab706 --- /dev/null +++ b/packages/generator/src/v1.1/generateBulkActions.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2023 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from "vitest"; +import { createMockMinimalFiles } from "../util/test/createMockMinimalFiles"; +import { TodoWireOntology } from "../util/test/TodoWireOntology"; +import { generateBulkActions } from "./generateBulkActions"; + +describe(generateBulkActions, () => { + it("generates bulk action interface", async () => { + const helper = createMockMinimalFiles(); + const BASE_PATH = "/foo"; + + await generateBulkActions( + TodoWireOntology, + helper.minimalFiles, + BASE_PATH, + ); + + expect(helper.minimalFiles.writeFile).toBeCalled(); + + expect(helper.getFiles()[`${BASE_PATH}/BulkActions.ts`]) + .toMatchInlineSnapshot(` + "import type { + ActionError, + BulkActionExecutionOptions, + BulkActionResponseFromOptions, + Edits, + Result, + } from '@osdk/legacy-client'; + import type { Todo } from '../objects/Todo'; + export interface BulkActions { + /** + * An action which takes different types of parameters + * @param {Todo | Todo["__primaryKey"]} params.object + */ + markTodoCompleted( + params: { + object?: Todo | Todo['__primaryKey']; + }[], + options?: O, + ): Promise>, ActionError>>; + } + " + `); + }); +}); diff --git a/packages/generator/src/v1.1/generateBulkActions.ts b/packages/generator/src/v1.1/generateBulkActions.ts new file mode 100644 index 000000000..389b6a58e --- /dev/null +++ b/packages/generator/src/v1.1/generateBulkActions.ts @@ -0,0 +1,139 @@ +/* + * Copyright 2023 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ActionParameterType } from "@osdk/gateway/types"; +import path from "node:path"; +import type { MinimalFs } from "../MinimalFs"; +import { getModifiedEntityTypes } from "../shared/getEditedEntities"; +import { formatTs } from "../util/test/formatTs"; +import type { WireOntologyDefinition } from "../WireOntologyDefinition"; + +export async function generateBulkActions( + ontology: WireOntologyDefinition, + fs: MinimalFs, + outDir: string, + importExt: string = "", +) { + const importedObjects = new Set(); + let actionSignatures: any[] = []; + for (const action of Object.values(ontology.actionTypes)) { + const entries = Object.entries(action.parameters); + + const modifiedEntityTypes = getModifiedEntityTypes(action); + const addedObjects = Array.from(modifiedEntityTypes.addedObjects); + const modifiedObjects = Array.from(modifiedEntityTypes.modifiedObjects); + addedObjects.forEach(importedObjects.add, importedObjects); + modifiedObjects.forEach(importedObjects.add, importedObjects); + + let jsDocBlock = ["/**"]; + if (action.description) { + jsDocBlock.push(`* ${action.description}`); + } + + let parameterBlock = ""; + if (entries.length > 0) { + parameterBlock = `params: { \n`; + for ( + const [parameterName, parameterData] of entries + ) { + parameterBlock += `"${parameterName}"`; + parameterBlock += parameterData.required ? ": " : "?: "; + const typeScriptType = getTypeScriptTypeFromDataType( + parameterData.dataType, + importedObjects, + ); + parameterBlock += `${typeScriptType};\n`; + + jsDocBlock.push( + `* @param {${typeScriptType}} params.${parameterName}`, + ); + } + parameterBlock += "} "; + } + + jsDocBlock.push(`*/`); + actionSignatures.push( + ` + ${jsDocBlock.join("\n")} + ${action.apiName}(${parameterBlock}[],options?: O): + Promise 0 + ? addedObjects.join(" | ") + : "void" + }, ${ + modifiedObjects.length > 0 + ? modifiedObjects.join(" | ") + : "void" + }>>, ActionError>>; + `, + ); + } + + await fs.mkdir(outDir, { recursive: true }); + await fs.writeFile( + path.join(outDir, "BulkActions.ts"), + await formatTs(` + import type { ObjectSet, LocalDate, Timestamp, Attachment, Edits, ActionExecutionOptions, BulkActionExecutionOptions, ActionError, Result, ActionResponseFromOptions, BulkActionResponseFromOptions } from "@osdk/legacy-client"; + ${ + Array.from(importedObjects).map(importedObject => + `import type { ${importedObject} } from "../objects/${importedObject}${importExt}";` + ).join("\n") + } + export interface BulkActions { + ${actionSignatures.join("\n")} + } + `), + ); +} + +function getTypeScriptTypeFromDataType( + actionParameter: ActionParameterType, + importedObjects: Set, +): string { + switch (actionParameter.type) { + case "objectSet": { + const objectType = actionParameter.objectTypeApiName!; + importedObjects.add(objectType); + return `ObjectSet<${objectType}>`; + } + case "object": { + const objectType = actionParameter.objectTypeApiName!; + importedObjects.add(objectType); + return `${objectType} | ${objectType}["__primaryKey"]`; + } + case "array": + return `Array<${ + getTypeScriptTypeFromDataType(actionParameter.subType, importedObjects) + }>`; + case "string": + return `string`; + case "boolean": + return `boolean`; + case "attachment": + return `Attachment`; + case "date": + return `LocalDate`; + case "double": + case "integer": + case "long": + return `number`; + case "timestamp": + return `Timestamp`; + default: + const _: never = actionParameter; + throw new Error(`Unsupported action parameter type: ${actionParameter}`); + } +} diff --git a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts index 28db090e1..e9696acbc 100644 --- a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts +++ b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts @@ -21,6 +21,7 @@ import { verifyOutdir } from "../util/verifyOutdir"; import type { WireOntologyDefinition } from "../WireOntologyDefinition"; import { generateActions } from "./generateActions"; import { generateBackCompatDeprecatedExports } from "./generateBackCompatDeprecatedExports"; +import { generateBulkActions } from "./generateBulkActions"; import { generateFoundryClientFile } from "./generateFoundryClientFile"; import { generateIndexFile } from "./generateIndexFile"; import { generateMetadataFile } from "./generateMetadataFile"; @@ -79,12 +80,14 @@ export async function generateClientSdkVersionOneDotOne( importExt, ); await generateActions(sanitizedOntology, fs, actionsDir, importExt); + await generateBulkActions(sanitizedOntology, fs, actionsDir, importExt); await generatePerActionDataFiles( sanitizedOntology, fs, actionsDir, importExt, ); + await generateQueries(sanitizedOntology, fs, queriesDir, importExt); await generatePerQueryDataFiles( sanitizedOntology, diff --git a/packages/generator/src/v1.1/generateMetadataFile.test.ts b/packages/generator/src/v1.1/generateMetadataFile.test.ts index e338ad00f..97faba2e4 100644 --- a/packages/generator/src/v1.1/generateMetadataFile.test.ts +++ b/packages/generator/src/v1.1/generateMetadataFile.test.ts @@ -39,6 +39,7 @@ describe(generateMetadataFile, () => { "import type { OntologyDefinition } from '@osdk/api'; import type { Ontology as ClientOntology } from '@osdk/legacy-client'; import type { Actions } from './ontology/actions/Actions'; + import type { BulkActions } from './ontology/actions/BulkActions'; import { markTodoCompleted } from './ontology/actions/markTodoCompleted'; import type { Objects } from './ontology/objects/Objects'; import { Person } from './ontology/objects/Person'; @@ -83,6 +84,7 @@ describe(generateMetadataFile, () => { export interface Ontology extends ClientOntology { objects: Objects; actions: Actions; + bulkActions: BulkActions; queries: Queries; } " @@ -165,6 +167,7 @@ describe(generateMetadataFile, () => { "import type { OntologyDefinition } from '@osdk/api'; import type { Ontology as ClientOntology } from '@osdk/legacy-client'; import type { Actions } from './ontology/actions/Actions'; + import type { BulkActions } from './ontology/actions/BulkActions'; import { bar } from './ontology/actions/bar'; import { foo as fooAction } from './ontology/actions/foo'; import type { Objects } from './ontology/objects/Objects'; @@ -212,6 +215,7 @@ describe(generateMetadataFile, () => { export interface Ontology extends ClientOntology { objects: Objects; actions: Actions; + bulkActions: BulkActions; queries: Queries; } " @@ -249,6 +253,7 @@ describe(generateMetadataFile, () => { "import type { OntologyDefinition } from '@osdk/api'; import type { Ontology as ClientOntology } from '@osdk/legacy-client'; import type { Actions } from './ontology/actions/Actions'; + import type { BulkActions } from './ontology/actions/BulkActions'; import type { Objects } from './ontology/objects/Objects'; import type { Queries } from './ontology/queries/Queries'; @@ -275,6 +280,7 @@ describe(generateMetadataFile, () => { export interface Ontology extends ClientOntology { objects: Objects; actions: Actions; + bulkActions: BulkActions; queries: Queries; } " diff --git a/packages/generator/src/v1.1/generateMetadataFile.ts b/packages/generator/src/v1.1/generateMetadataFile.ts index 89ab8eb08..edf577409 100644 --- a/packages/generator/src/v1.1/generateMetadataFile.ts +++ b/packages/generator/src/v1.1/generateMetadataFile.ts @@ -70,6 +70,7 @@ export async function generateMetadataFile( import type { Objects } from "./ontology/objects/Objects${importExt}"; import type { Actions } from "./ontology/actions/Actions${importExt}"; import type { Queries } from "./ontology/queries/Queries${importExt}"; + import type { BulkActions } from "./ontology/actions/BulkActions${importExt}"; ${ objectNames.map((name) => `import {${name}} from "./ontology/objects/${name}${importExt}";` @@ -142,6 +143,7 @@ export async function generateMetadataFile( export interface Ontology extends ClientOntology { objects: Objects; actions: Actions; + bulkActions: BulkActions; queries: Queries; }`), ); diff --git a/packages/legacy-client/src/client/actions/actions.test.ts b/packages/legacy-client/src/client/actions/actions.test.ts index a96619d81..95a89028f 100644 --- a/packages/legacy-client/src/client/actions/actions.test.ts +++ b/packages/legacy-client/src/client/actions/actions.test.ts @@ -17,6 +17,7 @@ import { createClientContext } from "@osdk/shared.net"; import type { ClientContext } from "@osdk/shared.net"; import { + apiServer, getMockTodoObject, MOCK_ORIGIN, mockFetchResponse, @@ -25,6 +26,7 @@ import { import type { MockedFunction } from "vitest"; import { assert, + beforeAll, beforeEach, describe, expect, @@ -40,23 +42,45 @@ import type { Edits, Result, } from "../.."; +import { Ontology as MockOntologyGenerated } from "../../generatedNoCheck/Ontology"; import { USER_AGENT } from "../../USER_AGENT"; import { expectFetchToBeCalledWithBody, expectFetchToBeCalledWithGet, } from "../../util/test/expectUtils"; import { unwrapResultOrThrow } from "../../util/test/resultUtils"; +import type { + BulkActionExecutionOptions, + BulkActionResponseFromOptions, +} from "../baseTypes"; import { createBaseOsdkObjectSet } from "../objectSets/OsdkObjectSet"; import type { OsdkLegacyObjectFrom } from "../OsdkLegacyObject"; -import type { Actions } from "./actions"; -import { createActionProxy } from "./createActionProxy"; +import type { Actions, BulkActions } from "./actions"; +import { createActionProxy, createBulkActionProxy } from "./createActionProxy"; describe("Actions", () => { let client: ClientContext; + let sharedClient: ClientContext; let fetch: MockedFunction; let actions: Actions< typeof MockOntology >; + let bulkActions: BulkActions; + let sharedBulkActions: BulkActions; + + beforeAll(async () => { + apiServer.listen(); + sharedClient = createClientContext( + MockOntologyGenerated, + "https://stack.palantir.com", + () => "myAccessToken", + USER_AGENT, + globalThis.fetch, + ); + sharedBulkActions = createBulkActionProxy( + sharedClient, + ); + }); beforeEach(() => { fetch = vi.fn(); @@ -68,6 +92,7 @@ describe("Actions", () => { fetch, ); actions = createActionProxy(client); + bulkActions = createBulkActionProxy(client); }); describe("type tests", () => { @@ -81,10 +106,28 @@ describe("Actions", () => { ] >(); + expectTypeOf>() + .toEqualTypeOf< + [ + { + id?: number; + }[], + BulkActionExecutionOptions?, + ] + >(); + expectTypeOf() // @ts-expect-error .toBeCallableWith([{ id: 1 }]); + expectTypeOf().toBeCallableWith([{ + id: 1, + }], { + // @ts-expect-error + mode: ActionExecutionMode.VALIDATE_AND_EXECUTE, + returnEdits: ReturnEditsMode.ALL, + }); + expectTypeOf>().toMatchTypeOf< Promise< Result< @@ -96,6 +139,18 @@ describe("Actions", () => { > > >(); + + expectTypeOf>().toMatchTypeOf< + Promise< + Result< + BulkActionResponseFromOptions< + BulkActionExecutionOptions, + Edits, void> + >, + ActionError + > + > + >(); }); it("skips empty parameters", () => { @@ -104,6 +159,12 @@ describe("Actions", () => { ActionExecutionOptions?, ] >(); + + expectTypeOf>().toEqualTypeOf< + [ + BulkActionExecutionOptions?, + ] + >(); }); it("maps Object types correctly", () => { @@ -121,6 +182,20 @@ describe("Actions", () => { ] >(); + expectTypeOf>().toMatchTypeOf< + [ + { + task?: + | OsdkLegacyObjectFrom + | OsdkLegacyObjectFrom< + typeof MockOntology, + "Task" + >["__primaryKey"]; + }[], + ActionExecutionOptions?, + ] + >(); + expectTypeOf>().toMatchTypeOf< Promise< Result< @@ -135,143 +210,220 @@ describe("Actions", () => { > > >(); + + expectTypeOf>().toMatchTypeOf< + Promise< + Result< + BulkActionResponseFromOptions< + BulkActionExecutionOptions, + Edits< + void, + OsdkLegacyObjectFrom + > + >, + ActionError + > + > + >(); }); - }); - describe("proxy", () => { - it("proxies action calls with parameters", async () => { + describe("proxy", () => { + it("proxies action calls with parameters", async () => { + mockFetchResponse(fetch, {}); + const actionResponse = await actions.createTask({ id: 1 }); + expectFetchToBeCalledWithBody( + fetch, + `Ontology/actions/createTask/apply`, + { + parameters: { + id: 1, + }, + options: {}, + }, + ); + expect(actionResponse.type).toEqual("ok"); + }); + + it("proxies action calls with no parameters and parses edits", async () => { + mockFetchResponse(fetch, { + edits: { + type: "edits", + edits: [{ + type: "addObject", + primaryKey: 1, + objectType: "Todo", + }], + addedObjectCount: 1, + modifiedObjectsCount: 0, + addedLinksCount: 0, + }, + }); + + const actionResponse = await actions.createTodo({ + mode: ActionExecutionMode.VALIDATE_AND_EXECUTE, + returnEdits: ReturnEditsMode.ALL, + }); + + expectFetchToBeCalledWithBody( + fetch, + `Ontology/actions/createTodo/apply`, + { + parameters: {}, + options: { + mode: "VALIDATE_AND_EXECUTE", + returnEdits: "ALL", + }, + }, + ); + + const value = unwrapResultOrThrow(actionResponse); + assert(value.edits.type === "edits"); + mockFetchResponse(fetch, getMockTodoObject()); + const loadAddedObject = await value.edits.added[0].get(); + + expectFetchToBeCalledWithGet(fetch, `Ontology/objects/Todo/1`); + const createdObject = unwrapResultOrThrow(loadAddedObject); + expect(createdObject.__primaryKey).toEqual( + getMockTodoObject().__primaryKey, + ); + }); + }); + + it("proxies action calls transforms arguments", async () => { + const taskOs = createBaseOsdkObjectSet(client, "Task"); + mockFetchResponse(fetch, getMockTodoObject()); + const taskObjectResult = await taskOs.get(1); + const taskObject = unwrapResultOrThrow(taskObjectResult); + mockFetchResponse(fetch, {}); - const actionResponse = await actions.createTask({ id: 1 }); + const actionResponse = await actions.updateTask({ + task: taskObject, + tasks: taskOs, + }, {}); + expectFetchToBeCalledWithBody( fetch, - `Ontology/actions/createTask/apply`, + `Ontology/actions/updateTask/apply`, { parameters: { - id: 1, + task: 1, + tasks: { + type: "base", + objectType: "Task", + }, + }, + options: { + mode: "VALIDATE_AND_EXECUTE", + returnEdits: "NONE", }, - options: {}, }, ); - expect(actionResponse.type).toEqual("ok"); + + assert(actionResponse.type === "ok"); }); - it("proxies action calls with no parameters and parses edits", async () => { - mockFetchResponse(fetch, { - edits: { - type: "edits", - edits: [{ - type: "addObject", - primaryKey: 1, - objectType: "Todo", - }], - addedObjectCount: 1, - modifiedObjectsCount: 0, - addedLinksCount: 0, - }, - }); + it("proxies action calls takes object primary key", async () => { + const taskOs = createBaseOsdkObjectSet(client, "Task"); + mockFetchResponse(fetch, getMockTodoObject()); - const actionResponse = await actions.createTodo({ - mode: ActionExecutionMode.VALIDATE_AND_EXECUTE, - returnEdits: ReturnEditsMode.ALL, - }); + mockFetchResponse(fetch, {}); + const actionResponse = await actions.updateTask({ + task: 1, + tasks: taskOs, + }, {}); expectFetchToBeCalledWithBody( fetch, - `Ontology/actions/createTodo/apply`, + `Ontology/actions/updateTask/apply`, { - parameters: {}, + parameters: { + task: 1, + tasks: { + type: "base", + objectType: "Task", + }, + }, options: { mode: "VALIDATE_AND_EXECUTE", - returnEdits: "ALL", + returnEdits: "NONE", }, }, ); - const value = unwrapResultOrThrow(actionResponse); - assert(value.edits.type === "edits"); - mockFetchResponse(fetch, getMockTodoObject()); - const loadAddedObject = await value.edits.added[0].get(); + assert(actionResponse.type === "ok"); + }); - expectFetchToBeCalledWithGet(fetch, `Ontology/objects/Todo/1`); - const createdObject = unwrapResultOrThrow(loadAddedObject); - expect(createdObject.__primaryKey).toEqual( - getMockTodoObject().__primaryKey, + it("has an enumerable list of actions", () => { + const actionProxy = createActionProxy(client); + const bulkActionProxy = createBulkActionProxy(client); + expect(Object.getOwnPropertyNames(actionProxy)).toMatchInlineSnapshot(` + [ + "createTask", + "createTodo", + "updateTask", + ] + `); + expect(Object.getOwnPropertyNames(bulkActionProxy)).toMatchInlineSnapshot( + ` + [ + "createTask", + "createTodo", + "updateTask", + ] + `, ); }); }); - it("proxies action calls transforms arguments", async () => { - const taskOs = createBaseOsdkObjectSet(client, "Task"); - mockFetchResponse(fetch, getMockTodoObject()); - const taskObjectResult = await taskOs.get(1); - const taskObject = unwrapResultOrThrow(taskObjectResult); - - mockFetchResponse(fetch, {}); - const actionResponse = await actions.updateTask({ - task: taskObject, - tasks: taskOs, - }, {}); - - expectFetchToBeCalledWithBody( - fetch, - `Ontology/actions/updateTask/apply`, + it("conditionally returns edits in batch mode", async () => { + const result = await sharedBulkActions.moveOffice([ { - parameters: { - task: 1, - tasks: { - type: "base", - objectType: "Task", - }, - }, - options: { - mode: "VALIDATE_AND_EXECUTE", - returnEdits: "NONE", - }, + officeId: "SEA", + newAddress: "456 Good Place", + newCapacity: 40, }, - ); - - assert(actionResponse.type === "ok"); - }); - - it("proxies action calls takes object primary key", async () => { - const taskOs = createBaseOsdkObjectSet(client, "Task"); - mockFetchResponse(fetch, getMockTodoObject()); - - mockFetchResponse(fetch, {}); - const actionResponse = await actions.updateTask({ - task: 1, - tasks: taskOs, - }, {}); + { + officeId: "NYC", + newAddress: "123 Main Street", + newCapacity: 80, + }, + ], { returnEdits: ReturnEditsMode.ALL }); - expectFetchToBeCalledWithBody( - fetch, - `Ontology/actions/updateTask/apply`, + expect(unwrapResultOrThrow(result)).toMatchInlineSnapshot(` + { + "edits": { + "added": [], + "modified": [ { - parameters: { - task: 1, - tasks: { - type: "base", - objectType: "Task", - }, - }, - options: { - mode: "VALIDATE_AND_EXECUTE", - returnEdits: "NONE", - }, + "apiName": "Office", + "get": [Function], + "primaryKey": "SEA", }, - ); + { + "apiName": "Office", + "get": [Function], + "primaryKey": "NYC", + }, + ], + "type": "edits", + }, +}`); - assert(actionResponse.type === "ok"); - }); + const noEditsResult = await sharedBulkActions.moveOffice([ + { + officeId: "SEA", + newAddress: "456 Good Place", + newCapacity: 40, + }, + { + officeId: "NYC", + newAddress: "123 Main Street", + newCapacity: 80, + }, + ]); - it("has an enumerable list of actions", () => { - const actionProxy = createActionProxy(client); - expect(Object.getOwnPropertyNames(actionProxy)).toMatchInlineSnapshot(` - [ - "createTask", - "createTodo", - "updateTask", - ] - `); + expect(unwrapResultOrThrow(noEditsResult)).toMatchInlineSnapshot(` + {} + `); }); }); diff --git a/packages/legacy-client/src/client/actions/actions.ts b/packages/legacy-client/src/client/actions/actions.ts index 33e3a8015..c585c98af 100644 --- a/packages/legacy-client/src/client/actions/actions.ts +++ b/packages/legacy-client/src/client/actions/actions.ts @@ -25,6 +25,10 @@ import type { Result, Timestamp, } from "../.."; +import type { + BulkActionExecutionOptions, + BulkActionResponseFromOptions, +} from "../baseTypes"; import type { ObjectSet } from "../interfaces"; import type { OsdkLegacyObjectFrom } from "../OsdkLegacyObject"; import type { IsEmptyRecord } from "../utils/IsEmptyRecord"; @@ -129,21 +133,47 @@ export type WrappedActionReturnType< O extends OntologyDefinition, A extends keyof O["actions"], Op extends ActionExecutionOptions, + P extends ActionArgs | ActionArgs[] | undefined = undefined, > = Promise< Result< - ActionReturnType, + ActionReturnType, ActionError > >; +// export type WrappedBulkActionReturnType< +// O extends OntologyDefinition, +// A extends keyof O["actions"], +// Op extends BulkActionExecutionOptions, +// > = Promise< +// Result< +// BulkActionReturnType, +// ActionError +// > +// >; + +// export type BulkActionReturnType< +// O extends OntologyDefinition, +// A extends keyof O["actions"], +// Op extends BulkActionExecutionOptions, +// > = BulkActionResponseFromOptions< +// Op, +// Edits, ModifiedObjectsOrVoid> +// >; + export type ActionReturnType< O extends OntologyDefinition, A extends keyof O["actions"], Op extends ActionExecutionOptions, -> = ActionResponseFromOptions< - Op, - Edits, ModifiedObjectsOrVoid> ->; + P extends ActionArgs | ActionArgs[] | undefined, +> = P extends ActionArgs[] ? BulkActionResponseFromOptions< + Op, + Edits, ModifiedObjectsOrVoid> + > + : ActionResponseFromOptions< + Op, + Edits, ModifiedObjectsOrVoid> + >; export type Actions< O extends OntologyDefinition, @@ -158,3 +188,15 @@ export type Actions< options?: Op, ) => WrappedActionReturnType; }; + +export type BulkActions> = { + [A in keyof O["actions"]]: + IsEmptyRecord extends true + ? ( + options?: Op, + ) => WrappedActionReturnType + : []>( + params: P, + options?: Op, + ) => WrappedActionReturnType; +}; diff --git a/packages/legacy-client/src/client/actions/createActionProxy.ts b/packages/legacy-client/src/client/actions/createActionProxy.ts index 381b2b0c6..ec7eab8f6 100644 --- a/packages/legacy-client/src/client/actions/createActionProxy.ts +++ b/packages/legacy-client/src/client/actions/createActionProxy.ts @@ -17,8 +17,14 @@ import type { OntologyDefinition } from "@osdk/api"; import type { ClientContext } from "@osdk/shared.net"; import type { ActionExecutionOptions } from "../.."; -import { executeAction } from "../net/executeAction"; -import type { ActionArgs, Actions, WrappedActionReturnType } from "./actions"; +import type { BulkActionExecutionOptions } from "../baseTypes"; +import { executeAction, executeBatchAction } from "../net/executeAction"; +import type { + ActionArgs, + Actions, + BulkActions, + WrappedActionReturnType, +} from "./actions"; export function createActionProxy< O extends OntologyDefinition, @@ -41,11 +47,19 @@ export function createActionProxy< }; } - return async function( - params: ActionArgs, + return async function< + Op extends ActionExecutionOptions, + P extends ActionArgs, + >( + params: P, options?: Op, - ): Promise> { - return executeAction(client, p, params, options); + ): Promise> { + return executeAction( + client, + p, + params, + options, + ); }; } @@ -67,3 +81,59 @@ export function createActionProxy< ) as Actions; return proxy; } + +export function createBulkActionProxy< + O extends OntologyDefinition, +>(client: ClientContext): BulkActions { + const proxy = new Proxy( + {}, + { + get: (_target, p: keyof O["actions"], _receiver) => { + if (typeof p === "string") { + if (Object.keys(client.ontology.actions[p].parameters).length === 0) { + return async function( + options?: Op, + ): Promise> { + return executeBatchAction( + client, + p, + undefined, + options, + ); + }; + } + + return async function< + Op extends BulkActionExecutionOptions, + P extends ActionArgs[], + >( + params: P, + options?: Op, + ): Promise> { + return executeBatchAction( + client, + p, + params, + options, + ); + }; + } + + return undefined; + }, + ownKeys(_target) { + return Object.keys(client.ontology.actions); + }, + getOwnPropertyDescriptor(_target, p) { + if (typeof p === "string") { + return { + enumerable: client.ontology.actions[p] != null, + configurable: true, + value: proxy[p], + }; + } + }, + }, + ) as BulkActions; + return proxy; +} diff --git a/packages/legacy-client/src/client/baseTypes/ActionType.ts b/packages/legacy-client/src/client/baseTypes/ActionType.ts index 85022ece5..a6be0770e 100644 --- a/packages/legacy-client/src/client/baseTypes/ActionType.ts +++ b/packages/legacy-client/src/client/baseTypes/ActionType.ts @@ -15,7 +15,10 @@ */ import type { OntologyDefinition } from "@osdk/api"; -import type { SyncApplyActionResponseV2 } from "@osdk/gateway/types"; +import type { + BatchApplyActionResponseV2, + SyncApplyActionResponseV2, +} from "@osdk/gateway/types"; import type { ClientContext } from "@osdk/shared.net"; import { getObject } from "../../client/net/getObject"; import type { GetObjectError } from "../errors"; @@ -30,6 +33,11 @@ export type ActionExecutionOptions = { returnEdits?: ReturnEditsMode; }; +export type BulkActionExecutionOptions = { + mode?: never; + returnEdits?: ReturnEditsMode; +}; + export enum ActionExecutionMode { VALIDATE_ONLY = 0, VALIDATE_AND_EXECUTE = 1, @@ -116,6 +124,12 @@ export interface ActionResponse< edits: TEdits extends undefined ? never : TEdits | BulkEdits; } +export interface BulkActionResponse< + TEdits extends Edits | undefined = undefined, +> { + edits: TEdits extends undefined ? never : TEdits | BulkEdits; +} + export type ActionResponseFromOptions< TOptions extends ActionExecutionOptions | undefined = undefined, TEdits extends Edits | undefined = undefined, @@ -124,6 +138,14 @@ export type ActionResponseFromOptions< } ? ActionResponse : ActionResponse; +export type BulkActionResponseFromOptions< + TOptions extends ActionExecutionOptions | undefined = undefined, + TEdits extends Edits | undefined = undefined, +> = TOptions extends { + returnEdits: ReturnEditsMode.ALL; +} ? BulkActionResponse + : BulkActionResponse; + export const ActionResponse = { of: < TAddedObjects extends OntologyObject>, @@ -141,8 +163,8 @@ export const ActionResponse = { ], }; if (response.edits?.type === "edits") { - const added = []; - const modified = []; + const added: any[] = []; + const modified: any[] = []; for (const edit of response.edits.edits) { if (edit.type === "addObject") { added.push({ @@ -179,3 +201,52 @@ export const ActionResponse = { return { validation } as ActionResponse; }, }; + +export const BulkActionResponse = { + of: < + TAddedObjects extends OntologyObject>, + TModifiedObjects extends OntologyObject< + string, + NonNullable + >, + >( + client: ClientContext>, + response: BatchApplyActionResponseV2, + ): BulkActionResponse | undefined> => { + if (response.edits?.type === "edits") { + const added: any[] = []; + const modified: any[] = []; + for (const edit of response.edits.edits) { + if (edit.type === "addObject") { + added.push({ + apiName: edit.objectType, + primaryKey: edit.primaryKey, + get: () => getObject(client, edit.objectType, edit.primaryKey), + }); + } + if (edit.type === "modifyObject") { + modified.push({ + apiName: edit.objectType, + primaryKey: edit.primaryKey, + get: () => getObject(client, edit.objectType, edit.primaryKey), + }); + } + } + return { + edits: { + type: "edits", + added, + modified, + }, + } as BulkActionResponse>; + } + if (response.edits?.type === "largeScaleEdits") { + return { + edits: { + type: "bulkEdits", + }, + }; + } + return {} as BulkActionResponse; + }, +}; diff --git a/packages/legacy-client/src/client/net/executeAction.ts b/packages/legacy-client/src/client/net/executeAction.ts index cb2ec73c4..fbfefb109 100644 --- a/packages/legacy-client/src/client/net/executeAction.ts +++ b/packages/legacy-client/src/client/net/executeAction.ts @@ -15,7 +15,7 @@ */ import type { OntologyDefinition } from "@osdk/api"; -import { applyActionV2 } from "@osdk/gateway/requests"; +import { applyActionBatchV2, applyActionV2 } from "@osdk/gateway/requests"; import type { ApplyActionRequestOptions } from "@osdk/gateway/types"; import { createOpenApiRequest } from "@osdk/shared.net"; import type { ClientContext } from "@osdk/shared.net"; @@ -27,9 +27,13 @@ import type { import { ActionExecutionMode, ActionResponse, + BulkActionResponse, ReturnEditsMode, } from "../baseTypes"; -import type { ActionExecutionOptions } from "../baseTypes"; +import type { + ActionExecutionOptions, + BulkActionExecutionOptions, +} from "../baseTypes"; import { ExecuteActionErrorHandler, handleExecuteActionError } from "../errors"; import { getParameterValueMapping } from "./util/getParameterValueMapping"; import { wrapResult } from "./util/wrapResult"; @@ -38,12 +42,13 @@ export async function executeAction< O extends OntologyDefinition, A extends keyof O["actions"], Op extends ActionExecutionOptions, + P extends ActionArgs | undefined = undefined, >( client: ClientContext>, actionApiName: A, - params?: ActionArgs, + params?: P, options?: Op, -): WrappedActionReturnType { +): WrappedActionReturnType { return wrapResult( async () => { const response = await applyActionV2( @@ -59,7 +64,48 @@ export async function executeAction< return ActionResponse.of(client, response) as ActionReturnType< O, A, - Op + Op, + P + >; + }, + e => + handleExecuteActionError( + new ExecuteActionErrorHandler(), + e, + e.parameters, + ), + ); +} + +export async function executeBatchAction< + O extends OntologyDefinition, + A extends keyof O["actions"], + Op extends BulkActionExecutionOptions, + P extends ActionArgs[] | undefined = undefined, +>( + client: ClientContext>, + actionApiName: A, + params?: P, + options?: Op, +): WrappedActionReturnType { + return wrapResult( + async () => { + const response = await applyActionBatchV2( + createOpenApiRequest(client.stack, client.fetch), + client.ontology.metadata.ontologyApiName, + actionApiName as string, + { + requests: params + ? remapBulkActionParams(params) + : [], + options: options ? remapBulkOptions(options) : {}, + }, + ); + return BulkActionResponse.of(client, response) as ActionReturnType< + O, + A, + Op, + P >; }, e => @@ -84,6 +130,20 @@ function remapActionParams< return remappedParams; } +function remapBulkActionParams< + O extends OntologyDefinition, + A extends keyof O["actions"], +>(params: ActionArgs[]) { + const remappedParams: { parameters: { [parameterName: string]: any } }[] = + params.map( + param => { + return { parameters: remapActionParams(param) }; + }, + ); + + return remappedParams; +} + function remapOptions( options: ActionExecutionOptions, ): ApplyActionRequestOptions { @@ -97,3 +157,11 @@ function remapOptions( returnEdits: options.returnEdits === ReturnEditsMode.ALL ? "ALL" : "NONE", }; } + +function remapBulkOptions( + options: BulkActionExecutionOptions, +): ApplyActionRequestOptions { + return { + returnEdits: options.returnEdits === ReturnEditsMode.ALL ? "ALL" : "NONE", + }; +} diff --git a/packages/legacy-client/src/client/ontology.ts b/packages/legacy-client/src/client/ontology.ts index cf4413457..58d0aeb0c 100644 --- a/packages/legacy-client/src/client/ontology.ts +++ b/packages/legacy-client/src/client/ontology.ts @@ -16,8 +16,11 @@ import type { OntologyDefinition } from "@osdk/api"; import type { ClientContext } from "@osdk/shared.net"; -import type { Actions } from "./actions/actions"; -import { createActionProxy } from "./actions/createActionProxy"; +import type { Actions, BulkActions } from "./actions/actions"; +import { + createActionProxy, + createBulkActionProxy, +} from "./actions/createActionProxy"; import { Attachments } from "./baseTypes"; import type { Objects } from "./objects"; import { createBaseOsdkObjectSet } from "./objectSets/OsdkObjectSet"; @@ -38,6 +41,10 @@ export class Ontology> { return createActionProxy(this.#client); } + get bulkActions(): BulkActions { + return createBulkActionProxy(this.#client); + } + get queries(): Queries { /* this `as any` is required for ts4.9 compatability */ return createQueryProxy(this.#client) as any; diff --git a/packages/legacy-client/src/index.ts b/packages/legacy-client/src/index.ts index 40dc511f6..aa0959ffa 100644 --- a/packages/legacy-client/src/index.ts +++ b/packages/legacy-client/src/index.ts @@ -140,6 +140,8 @@ export type { Bucketing, BucketKey, BucketValue, + BulkActionExecutionOptions, + BulkActionResponseFromOptions, BulkEdits, CommonApiError, CompositePrimaryKeyNotSupported, diff --git a/packages/shared.test/src/handlers/actionEndpoints.ts b/packages/shared.test/src/handlers/actionEndpoints.ts index 12060336d..36e6e081c 100644 --- a/packages/shared.test/src/handlers/actionEndpoints.ts +++ b/packages/shared.test/src/handlers/actionEndpoints.ts @@ -15,6 +15,7 @@ */ import type { + BatchApplyActionResponse, ListActionTypesResponseV2, SyncApplyActionResponseV2, } from "@osdk/gateway/types"; @@ -103,6 +104,47 @@ export const actionHandlers: RestHandler< return res(ctx.json(actionResponse)); } + return res(ctx.status(400), ctx.json(ApplyActionFailedError)); + }, + ), + ), + /** + * Apply a Batch Action + */ + rest.post( + "https://stack.palantir.com/api/v2/ontologies/:ontologyApiName/actions/:actionType/applyBatch", + authHandlerMiddleware( + async ( + req, + res: ResponseComposition< + BatchApplyActionResponse | BaseAPIError + >, + ctx, + ) => { + const body = await req.text(); + const parsedBody = JSON.parse(body); + const ontologyApiName = req.params.ontologyApiName; + const actionType = req.params.actionType; + + if ( + typeof ontologyApiName !== "string" || typeof actionType !== "string" + ) { + return res( + ctx.status(400), + ctx.json(InvalidRequest("Invalid parameters")), + ); + } + + const actionResponse = + actionResponseMap[actionType][stableStringify(parsedBody)]; + + if ( + req.params.ontologyApiName === defaultOntology.apiName + && actionResponse + ) { + return res(ctx.json(actionResponse)); + } + return res(ctx.status(400), ctx.json(ApplyActionFailedError)); }, ), diff --git a/packages/shared.test/src/stubs/actions.ts b/packages/shared.test/src/stubs/actions.ts index 438720f91..af2c36733 100644 --- a/packages/shared.test/src/stubs/actions.ts +++ b/packages/shared.test/src/stubs/actions.ts @@ -16,6 +16,8 @@ import type { ApplyActionRequestV2, + BatchApplyActionRequestV2, + BatchApplyActionResponseV2, SyncApplyActionResponseV2, } from "@osdk/gateway/types"; import stableStringify from "json-stable-stringify"; @@ -150,6 +152,58 @@ export const actionRequestWithAttachment: ApplyActionRequestV2 = { parameters: { attachment: "attachment.rid" }, }; +export const actionRequestMoveOfficeBatch: BatchApplyActionRequestV2 = { + requests: [{ + parameters: { + officeId: "SEA", + newAddress: "456 Good Place", + newCapacity: 40, + }, + }, { + parameters: { + officeId: "NYC", + newAddress: "123 Main Street", + newCapacity: 80, + }, + }], + options: {}, +}; + +export const actionRequestMoveOfficeBatchWithEdits: BatchApplyActionRequestV2 = + { + requests: [{ + parameters: { + officeId: "SEA", + newAddress: "456 Good Place", + newCapacity: 40, + }, + }, { + parameters: { + officeId: "NYC", + newAddress: "123 Main Street", + newCapacity: 80, + }, + }], + options: { returnEdits: "ALL" }, + }; + +export const actionRequestMoveOfficeBatchInvalid: BatchApplyActionRequestV2 = { + requests: [{ + parameters: { + officeId: "SEA", + newAddress: "456 Pike Place", + newCapacity: 40, + }, + }, { + parameters: { + officeId: "NYC", + newAddress: "123 Main Street", + newCapacity: 80, + }, + }], + options: { returnEdits: "ALL" }, +}; + const actionResponseCreateOfficeAndEmployee: SyncApplyActionResponseV2 = { validation: { submissionCriteria: [], @@ -242,6 +296,24 @@ const actionResponseInvalid: SyncApplyActionResponseV2 = { }, }; +const actionResponseMoveOfficeBatch: BatchApplyActionResponseV2 = { + edits: { + type: "edits", + edits: [{ + type: "modifyObject", + primaryKey: "SEA", + objectType: officeObjectType.apiName, + }, { + type: "modifyObject", + primaryKey: "NYC", + objectType: officeObjectType.apiName, + }], + addedObjectCount: 0, + addedLinksCount: 0, + modifiedObjectsCount: 2, + }, +}; + export const actionResponseMap: { [actionApiName: string]: { [actionBody: string]: any; @@ -264,6 +336,10 @@ export const actionResponseMap: { [stableStringify(actionRequestMoveOfficeInvalid)]: actionResponseInvalid, [stableStringify(actionRequestMoveOffice2)]: undefined, [stableStringify(actionRequestMoveOffice3)]: undefined, + [stableStringify(actionRequestMoveOfficeBatch)]: {}, + [stableStringify(actionRequestMoveOfficeBatchWithEdits)]: + actionResponseMoveOfficeBatch, + [stableStringify(actionRequestMoveOfficeBatchInvalid)]: undefined, }, createOfficeAndEmployee: { [stableStringify(actionRequestCreateOfficeAndEmployee)]: From 5fa8a4ff585c0b2c9eba12cc8690255a81f1b399 Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 11:17:43 -0500 Subject: [PATCH 02/11] bulk actions fix --- .../src/generatedNoCheck/Ontology.ts | 2 + .../ontology/actions/BulkActions.ts | 3 +- .../todoapp/src/generatedNoCheck/Ontology.ts | 2 + .../ontology/actions/BulkActions.ts | 2 +- .../generator/src/v1.1/generateBulkActions.ts | 4 +- .../src/client/actions/actions.ts | 66 +++++++++++-------- .../src/client/actions/createActionProxy.ts | 7 +- .../src/client/baseTypes/ActionType.ts | 2 +- .../src/client/net/executeAction.ts | 14 ++-- 9 files changed, 57 insertions(+), 45 deletions(-) diff --git a/examples/one_dot_one/src/generatedNoCheck/Ontology.ts b/examples/one_dot_one/src/generatedNoCheck/Ontology.ts index 10e7c7005..5c6c514b0 100644 --- a/examples/one_dot_one/src/generatedNoCheck/Ontology.ts +++ b/examples/one_dot_one/src/generatedNoCheck/Ontology.ts @@ -1,6 +1,7 @@ import type { OntologyDefinition } from '@osdk/api'; import type { Ontology as ClientOntology } from '@osdk/legacy-client'; import type { Actions } from './ontology/actions/Actions'; +import type { BulkActions } from './ontology/actions/BulkActions'; import { actionTakesAllParameterTypes } from './ontology/actions/actionTakesAllParameterTypes'; import { createTodo } from './ontology/actions/createTodo'; import { ObjectTypeWithAllPropertyTypes } from './ontology/objects/ObjectTypeWithAllPropertyTypes'; @@ -58,5 +59,6 @@ export const Ontology: { export interface Ontology extends ClientOntology { objects: Objects; actions: Actions; + bulkActions: BulkActions; queries: Queries; } diff --git a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts index 50c101254..242791e97 100644 --- a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts +++ b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts @@ -12,7 +12,7 @@ import type { import type { ObjectTypeWithAllPropertyTypes } from '../objects/ObjectTypeWithAllPropertyTypes'; import type { Person } from '../objects/Person'; import type { Todo } from '../objects/Todo'; -export interface Actions { +export interface BulkActions { /** * An action which takes different types of parameters * @param {ObjectSet} params.objectSet @@ -38,7 +38,6 @@ export interface Actions { * Creates a new Todo */ createTodo( - [], options?: O, ): Promise>, ActionError>>; } diff --git a/examples/todoapp/src/generatedNoCheck/Ontology.ts b/examples/todoapp/src/generatedNoCheck/Ontology.ts index c418a6153..f63b07b65 100644 --- a/examples/todoapp/src/generatedNoCheck/Ontology.ts +++ b/examples/todoapp/src/generatedNoCheck/Ontology.ts @@ -1,6 +1,7 @@ import type { OntologyDefinition } from '@osdk/api'; import type { Ontology as ClientOntology } from '@osdk/legacy-client'; import type { Actions } from './ontology/actions/Actions'; +import type { BulkActions } from './ontology/actions/BulkActions'; import { completeTodo } from './ontology/actions/completeTodo'; import { createTodo } from './ontology/actions/createTodo'; import type { Objects } from './ontology/objects/Objects'; @@ -40,5 +41,6 @@ export const Ontology: { export interface Ontology extends ClientOntology { objects: Objects; actions: Actions; + bulkActions: BulkActions; queries: Queries; } diff --git a/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts b/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts index 6c29ef632..364ce5adf 100644 --- a/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts +++ b/examples/todoapp/src/generatedNoCheck/ontology/actions/BulkActions.ts @@ -6,7 +6,7 @@ import type { Result, } from '@osdk/legacy-client'; import type { Todo } from '../objects/Todo'; -export interface Actions { +export interface BulkActions { /** * Creates Todo * @param {string} params.Todo diff --git a/packages/generator/src/v1.1/generateBulkActions.ts b/packages/generator/src/v1.1/generateBulkActions.ts index 389b6a58e..e4856d3bc 100644 --- a/packages/generator/src/v1.1/generateBulkActions.ts +++ b/packages/generator/src/v1.1/generateBulkActions.ts @@ -61,14 +61,14 @@ export async function generateBulkActions( `* @param {${typeScriptType}} params.${parameterName}`, ); } - parameterBlock += "} "; + parameterBlock += "}[], "; } jsDocBlock.push(`*/`); actionSignatures.push( ` ${jsDocBlock.join("\n")} - ${action.apiName}(${parameterBlock}[],options?: O): + ${action.apiName}(${parameterBlock}options?: O): Promise 0 ? addedObjects.join(" | ") diff --git a/packages/legacy-client/src/client/actions/actions.ts b/packages/legacy-client/src/client/actions/actions.ts index c585c98af..09f07d273 100644 --- a/packages/legacy-client/src/client/actions/actions.ts +++ b/packages/legacy-client/src/client/actions/actions.ts @@ -133,47 +133,55 @@ export type WrappedActionReturnType< O extends OntologyDefinition, A extends keyof O["actions"], Op extends ActionExecutionOptions, - P extends ActionArgs | ActionArgs[] | undefined = undefined, > = Promise< Result< - ActionReturnType, + ActionReturnType, ActionError > >; -// export type WrappedBulkActionReturnType< -// O extends OntologyDefinition, -// A extends keyof O["actions"], -// Op extends BulkActionExecutionOptions, -// > = Promise< -// Result< -// BulkActionReturnType, -// ActionError -// > -// >; +export type WrappedBulkActionReturnType< + O extends OntologyDefinition, + A extends keyof O["actions"], + Op extends BulkActionExecutionOptions, +> = Promise< + Result< + BulkActionReturnType, + ActionError + > +>; + +export type BulkActionReturnType< + O extends OntologyDefinition, + A extends keyof O["actions"], + Op extends BulkActionExecutionOptions, +> = BulkActionResponseFromOptions< + Op, + Edits, ModifiedObjectsOrVoid> +>; -// export type BulkActionReturnType< +// export type ActionReturnType< // O extends OntologyDefinition, // A extends keyof O["actions"], -// Op extends BulkActionExecutionOptions, -// > = BulkActionResponseFromOptions< -// Op, -// Edits, ModifiedObjectsOrVoid> -// >; +// Op extends ActionExecutionOptions, +// P extends ActionArgs | ActionArgs[] | undefined, +// > = P extends ActionArgs[] ? BulkActionResponseFromOptions< +// Op, +// Edits, ModifiedObjectsOrVoid> +// > +// : ActionResponseFromOptions< +// Op, +// Edits, ModifiedObjectsOrVoid> +// >; export type ActionReturnType< O extends OntologyDefinition, A extends keyof O["actions"], Op extends ActionExecutionOptions, - P extends ActionArgs | ActionArgs[] | undefined, -> = P extends ActionArgs[] ? BulkActionResponseFromOptions< - Op, - Edits, ModifiedObjectsOrVoid> - > - : ActionResponseFromOptions< - Op, - Edits, ModifiedObjectsOrVoid> - >; +> = ActionResponseFromOptions< + Op, + Edits, ModifiedObjectsOrVoid> +>; export type Actions< O extends OntologyDefinition, @@ -194,9 +202,9 @@ export type BulkActions> = { IsEmptyRecord extends true ? ( options?: Op, - ) => WrappedActionReturnType + ) => WrappedBulkActionReturnType : []>( params: P, options?: Op, - ) => WrappedActionReturnType; + ) => WrappedBulkActionReturnType; }; diff --git a/packages/legacy-client/src/client/actions/createActionProxy.ts b/packages/legacy-client/src/client/actions/createActionProxy.ts index ec7eab8f6..748155cb2 100644 --- a/packages/legacy-client/src/client/actions/createActionProxy.ts +++ b/packages/legacy-client/src/client/actions/createActionProxy.ts @@ -24,6 +24,7 @@ import type { Actions, BulkActions, WrappedActionReturnType, + WrappedBulkActionReturnType, } from "./actions"; export function createActionProxy< @@ -53,7 +54,7 @@ export function createActionProxy< >( params: P, options?: Op, - ): Promise> { + ): Promise> { return executeAction( client, p, @@ -93,7 +94,7 @@ export function createBulkActionProxy< if (Object.keys(client.ontology.actions[p].parameters).length === 0) { return async function( options?: Op, - ): Promise> { + ): Promise> { return executeBatchAction( client, p, @@ -109,7 +110,7 @@ export function createBulkActionProxy< >( params: P, options?: Op, - ): Promise> { + ): Promise> { return executeBatchAction( client, p, diff --git a/packages/legacy-client/src/client/baseTypes/ActionType.ts b/packages/legacy-client/src/client/baseTypes/ActionType.ts index a6be0770e..5990d07ca 100644 --- a/packages/legacy-client/src/client/baseTypes/ActionType.ts +++ b/packages/legacy-client/src/client/baseTypes/ActionType.ts @@ -139,7 +139,7 @@ export type ActionResponseFromOptions< : ActionResponse; export type BulkActionResponseFromOptions< - TOptions extends ActionExecutionOptions | undefined = undefined, + TOptions extends BulkActionExecutionOptions | undefined = undefined, TEdits extends Edits | undefined = undefined, > = TOptions extends { returnEdits: ReturnEditsMode.ALL; diff --git a/packages/legacy-client/src/client/net/executeAction.ts b/packages/legacy-client/src/client/net/executeAction.ts index fbfefb109..bb3b98ee6 100644 --- a/packages/legacy-client/src/client/net/executeAction.ts +++ b/packages/legacy-client/src/client/net/executeAction.ts @@ -22,7 +22,9 @@ import type { ClientContext } from "@osdk/shared.net"; import type { ActionArgs, ActionReturnType, + BulkActionReturnType, WrappedActionReturnType, + WrappedBulkActionReturnType, } from "../actions/actions"; import { ActionExecutionMode, @@ -48,7 +50,7 @@ export async function executeAction< actionApiName: A, params?: P, options?: Op, -): WrappedActionReturnType { +): WrappedActionReturnType { return wrapResult( async () => { const response = await applyActionV2( @@ -64,8 +66,7 @@ export async function executeAction< return ActionResponse.of(client, response) as ActionReturnType< O, A, - Op, - P + Op >; }, e => @@ -87,7 +88,7 @@ export async function executeBatchAction< actionApiName: A, params?: P, options?: Op, -): WrappedActionReturnType { +): WrappedBulkActionReturnType { return wrapResult( async () => { const response = await applyActionBatchV2( @@ -101,11 +102,10 @@ export async function executeBatchAction< options: options ? remapBulkOptions(options) : {}, }, ); - return BulkActionResponse.of(client, response) as ActionReturnType< + return BulkActionResponse.of(client, response) as BulkActionReturnType< O, A, - Op, - P + Op >; }, e => From 45d9d573abd12cd42b358980f2e49fe004f1582e Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 12:02:54 -0500 Subject: [PATCH 03/11] refactor --- .../generator/src/v1.1/generateActions.ts | 2 +- .../generator/src/v1.1/generateBulkActions.ts | 41 +------------------ .../v1.1/generateClientSdkVersionOneDotOne.ts | 1 - .../src/client/actions/actions.ts | 14 ------- .../src/client/actions/createActionProxy.ts | 12 +++--- .../src/client/net/executeAction.ts | 6 +-- 6 files changed, 9 insertions(+), 67 deletions(-) diff --git a/packages/generator/src/v1.1/generateActions.ts b/packages/generator/src/v1.1/generateActions.ts index 3fe655637..5f583e3f0 100644 --- a/packages/generator/src/v1.1/generateActions.ts +++ b/packages/generator/src/v1.1/generateActions.ts @@ -98,7 +98,7 @@ export async function generateActions( ); } -function getTypeScriptTypeFromDataType( +export function getTypeScriptTypeFromDataType( actionParameter: ActionParameterType, importedObjects: Set, ): string { diff --git a/packages/generator/src/v1.1/generateBulkActions.ts b/packages/generator/src/v1.1/generateBulkActions.ts index e4856d3bc..f275e0a0e 100644 --- a/packages/generator/src/v1.1/generateBulkActions.ts +++ b/packages/generator/src/v1.1/generateBulkActions.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import type { ActionParameterType } from "@osdk/gateway/types"; import path from "node:path"; import type { MinimalFs } from "../MinimalFs"; import { getModifiedEntityTypes } from "../shared/getEditedEntities"; import { formatTs } from "../util/test/formatTs"; import type { WireOntologyDefinition } from "../WireOntologyDefinition"; +import { getTypeScriptTypeFromDataType } from "./generateActions"; export async function generateBulkActions( ontology: WireOntologyDefinition, @@ -98,42 +98,3 @@ export async function generateBulkActions( `), ); } - -function getTypeScriptTypeFromDataType( - actionParameter: ActionParameterType, - importedObjects: Set, -): string { - switch (actionParameter.type) { - case "objectSet": { - const objectType = actionParameter.objectTypeApiName!; - importedObjects.add(objectType); - return `ObjectSet<${objectType}>`; - } - case "object": { - const objectType = actionParameter.objectTypeApiName!; - importedObjects.add(objectType); - return `${objectType} | ${objectType}["__primaryKey"]`; - } - case "array": - return `Array<${ - getTypeScriptTypeFromDataType(actionParameter.subType, importedObjects) - }>`; - case "string": - return `string`; - case "boolean": - return `boolean`; - case "attachment": - return `Attachment`; - case "date": - return `LocalDate`; - case "double": - case "integer": - case "long": - return `number`; - case "timestamp": - return `Timestamp`; - default: - const _: never = actionParameter; - throw new Error(`Unsupported action parameter type: ${actionParameter}`); - } -} diff --git a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts index e9696acbc..6c1bec689 100644 --- a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts +++ b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts @@ -87,7 +87,6 @@ export async function generateClientSdkVersionOneDotOne( actionsDir, importExt, ); - await generateQueries(sanitizedOntology, fs, queriesDir, importExt); await generatePerQueryDataFiles( sanitizedOntology, diff --git a/packages/legacy-client/src/client/actions/actions.ts b/packages/legacy-client/src/client/actions/actions.ts index 09f07d273..2408cdbd2 100644 --- a/packages/legacy-client/src/client/actions/actions.ts +++ b/packages/legacy-client/src/client/actions/actions.ts @@ -160,20 +160,6 @@ export type BulkActionReturnType< Edits, ModifiedObjectsOrVoid> >; -// export type ActionReturnType< -// O extends OntologyDefinition, -// A extends keyof O["actions"], -// Op extends ActionExecutionOptions, -// P extends ActionArgs | ActionArgs[] | undefined, -// > = P extends ActionArgs[] ? BulkActionResponseFromOptions< -// Op, -// Edits, ModifiedObjectsOrVoid> -// > -// : ActionResponseFromOptions< -// Op, -// Edits, ModifiedObjectsOrVoid> -// >; - export type ActionReturnType< O extends OntologyDefinition, A extends keyof O["actions"], diff --git a/packages/legacy-client/src/client/actions/createActionProxy.ts b/packages/legacy-client/src/client/actions/createActionProxy.ts index 748155cb2..7077fac1e 100644 --- a/packages/legacy-client/src/client/actions/createActionProxy.ts +++ b/packages/legacy-client/src/client/actions/createActionProxy.ts @@ -50,12 +50,11 @@ export function createActionProxy< return async function< Op extends ActionExecutionOptions, - P extends ActionArgs, >( - params: P, + params: ActionArgs, options?: Op, ): Promise> { - return executeAction( + return executeAction( client, p, params, @@ -95,7 +94,7 @@ export function createBulkActionProxy< return async function( options?: Op, ): Promise> { - return executeBatchAction( + return executeBatchAction( client, p, undefined, @@ -106,12 +105,11 @@ export function createBulkActionProxy< return async function< Op extends BulkActionExecutionOptions, - P extends ActionArgs[], >( - params: P, + params: ActionArgs[], options?: Op, ): Promise> { - return executeBatchAction( + return executeBatchAction( client, p, params, diff --git a/packages/legacy-client/src/client/net/executeAction.ts b/packages/legacy-client/src/client/net/executeAction.ts index bb3b98ee6..c38e6dd22 100644 --- a/packages/legacy-client/src/client/net/executeAction.ts +++ b/packages/legacy-client/src/client/net/executeAction.ts @@ -44,11 +44,10 @@ export async function executeAction< O extends OntologyDefinition, A extends keyof O["actions"], Op extends ActionExecutionOptions, - P extends ActionArgs | undefined = undefined, >( client: ClientContext>, actionApiName: A, - params?: P, + params?: ActionArgs, options?: Op, ): WrappedActionReturnType { return wrapResult( @@ -82,11 +81,10 @@ export async function executeBatchAction< O extends OntologyDefinition, A extends keyof O["actions"], Op extends BulkActionExecutionOptions, - P extends ActionArgs[] | undefined = undefined, >( client: ClientContext>, actionApiName: A, - params?: P, + params?: ActionArgs[], options?: Op, ): WrappedBulkActionReturnType { return wrapResult( From 6e866dcf890a158077c605f6a819c1eb25baff3e Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 12:35:57 -0500 Subject: [PATCH 04/11] one more refactor --- .../src/handlers/actionEndpoints.ts | 103 +++++++----------- 1 file changed, 41 insertions(+), 62 deletions(-) diff --git a/packages/shared.test/src/handlers/actionEndpoints.ts b/packages/shared.test/src/handlers/actionEndpoints.ts index 36e6e081c..7c1a5ce29 100644 --- a/packages/shared.test/src/handlers/actionEndpoints.ts +++ b/packages/shared.test/src/handlers/actionEndpoints.ts @@ -23,8 +23,11 @@ import stableStringify from "json-stable-stringify"; import type { DefaultBodyType, MockedRequest, + PathParams, ResponseComposition, + RestContext, RestHandler, + RestRequest, } from "msw"; import { rest } from "msw"; import type { BaseAPIError } from "../BaseError"; @@ -76,77 +79,53 @@ export const actionHandlers: RestHandler< rest.post( "https://stack.palantir.com/api/v2/ontologies/:ontologyApiName/actions/:actionType/apply", authHandlerMiddleware( - async ( - req, - res: ResponseComposition, - ctx, - ) => { - const body = await req.text(); - const parsedBody = JSON.parse(body); - const ontologyApiName = req.params.ontologyApiName; - const actionType = req.params.actionType; - - if ( - typeof ontologyApiName !== "string" || typeof actionType !== "string" - ) { - return res( - ctx.status(400), - ctx.json(InvalidRequest("Invalid parameters")), - ); - } - - const actionResponse = - actionResponseMap[actionType][stableStringify(parsedBody)]; - if ( - req.params.ontologyApiName === defaultOntology.apiName - && actionResponse - ) { - return res(ctx.json(actionResponse)); - } - - return res(ctx.status(400), ctx.json(ApplyActionFailedError)); - }, + handleAction, ), ), + /** * Apply a Batch Action */ rest.post( "https://stack.palantir.com/api/v2/ontologies/:ontologyApiName/actions/:actionType/applyBatch", authHandlerMiddleware( - async ( - req, - res: ResponseComposition< - BatchApplyActionResponse | BaseAPIError - >, - ctx, - ) => { - const body = await req.text(); - const parsedBody = JSON.parse(body); - const ontologyApiName = req.params.ontologyApiName; - const actionType = req.params.actionType; + handleAction, + ), + ), +]; - if ( - typeof ontologyApiName !== "string" || typeof actionType !== "string" - ) { - return res( - ctx.status(400), - ctx.json(InvalidRequest("Invalid parameters")), - ); - } +async function handleAction< + T extends BatchApplyActionResponse | SyncApplyActionResponseV2, +>( + req: RestRequest>, + res: ResponseComposition< + T | BaseAPIError + >, + ctx: RestContext, +) { + const body = await req.text(); + const parsedBody = JSON.parse(body); + const ontologyApiName = req.params.ontologyApiName; + const actionType = req.params.actionType; - const actionResponse = - actionResponseMap[actionType][stableStringify(parsedBody)]; + if ( + typeof ontologyApiName !== "string" || typeof actionType !== "string" + ) { + return res( + ctx.status(400), + ctx.json(InvalidRequest("Invalid parameters")), + ); + } - if ( - req.params.ontologyApiName === defaultOntology.apiName - && actionResponse - ) { - return res(ctx.json(actionResponse)); - } + const actionResponse = + actionResponseMap[actionType][stableStringify(parsedBody)]; - return res(ctx.status(400), ctx.json(ApplyActionFailedError)); - }, - ), - ), -]; + if ( + req.params.ontologyApiName === defaultOntology.apiName + && actionResponse + ) { + return res(ctx.json(actionResponse)); + } + + return res(ctx.status(400), ctx.json(ApplyActionFailedError)); +} From 9e07b3a40776f378d83a67daa4ec88049268a0cb Mon Sep 17 00:00:00 2001 From: svc-changelog Date: Mon, 12 Feb 2024 17:45:31 +0000 Subject: [PATCH 05/11] Add generated changelog entries --- packages/generator/changelog/@unreleased/pr-53.v2.yml | 5 +++++ packages/legacy-client/changelog/@unreleased/pr-53.v2.yml | 5 +++++ packages/shared.test/changelog/@unreleased/pr-53.v2.yml | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 packages/generator/changelog/@unreleased/pr-53.v2.yml create mode 100644 packages/legacy-client/changelog/@unreleased/pr-53.v2.yml create mode 100644 packages/shared.test/changelog/@unreleased/pr-53.v2.yml diff --git a/packages/generator/changelog/@unreleased/pr-53.v2.yml b/packages/generator/changelog/@unreleased/pr-53.v2.yml new file mode 100644 index 000000000..fa9fb61ac --- /dev/null +++ b/packages/generator/changelog/@unreleased/pr-53.v2.yml @@ -0,0 +1,5 @@ +type: feature +feature: + description: Adding bulk actions to 1.1 + links: + - https://github.com/palantir/osdk-ts/pull/53 diff --git a/packages/legacy-client/changelog/@unreleased/pr-53.v2.yml b/packages/legacy-client/changelog/@unreleased/pr-53.v2.yml new file mode 100644 index 000000000..fa9fb61ac --- /dev/null +++ b/packages/legacy-client/changelog/@unreleased/pr-53.v2.yml @@ -0,0 +1,5 @@ +type: feature +feature: + description: Adding bulk actions to 1.1 + links: + - https://github.com/palantir/osdk-ts/pull/53 diff --git a/packages/shared.test/changelog/@unreleased/pr-53.v2.yml b/packages/shared.test/changelog/@unreleased/pr-53.v2.yml new file mode 100644 index 000000000..fa9fb61ac --- /dev/null +++ b/packages/shared.test/changelog/@unreleased/pr-53.v2.yml @@ -0,0 +1,5 @@ +type: feature +feature: + description: Adding bulk actions to 1.1 + links: + - https://github.com/palantir/osdk-ts/pull/53 From db62515ca28bbddbf835ae3b01edfb79a0782e73 Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 16:08:38 -0500 Subject: [PATCH 06/11] Fix bulk action type --- packages/legacy-client/src/client/baseTypes/ActionType.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/legacy-client/src/client/baseTypes/ActionType.ts b/packages/legacy-client/src/client/baseTypes/ActionType.ts index 5990d07ca..08e680ddf 100644 --- a/packages/legacy-client/src/client/baseTypes/ActionType.ts +++ b/packages/legacy-client/src/client/baseTypes/ActionType.ts @@ -34,7 +34,6 @@ export type ActionExecutionOptions = { }; export type BulkActionExecutionOptions = { - mode?: never; returnEdits?: ReturnEditsMode; }; From 3357ae840a48083239df931f9d268f6a913a6d39 Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 16:47:29 -0500 Subject: [PATCH 07/11] remove anys --- packages/legacy-client/src/client/baseTypes/ActionType.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/legacy-client/src/client/baseTypes/ActionType.ts b/packages/legacy-client/src/client/baseTypes/ActionType.ts index 08e680ddf..49aa680d1 100644 --- a/packages/legacy-client/src/client/baseTypes/ActionType.ts +++ b/packages/legacy-client/src/client/baseTypes/ActionType.ts @@ -162,8 +162,8 @@ export const ActionResponse = { ], }; if (response.edits?.type === "edits") { - const added: any[] = []; - const modified: any[] = []; + const added = []; + const modified = []; for (const edit of response.edits.edits) { if (edit.type === "addObject") { added.push({ @@ -213,8 +213,8 @@ export const BulkActionResponse = { response: BatchApplyActionResponseV2, ): BulkActionResponse | undefined> => { if (response.edits?.type === "edits") { - const added: any[] = []; - const modified: any[] = []; + const added = []; + const modified = []; for (const edit of response.edits.edits) { if (edit.type === "addObject") { added.push({ From 722ecd89990ee869ca83f3a88ce0ed2896b980c6 Mon Sep 17 00:00:00 2001 From: Saurav Date: Mon, 12 Feb 2024 17:15:52 -0500 Subject: [PATCH 08/11] use helper function --- .../src/client/baseTypes/ActionType.ts | 84 ++++++++----------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/packages/legacy-client/src/client/baseTypes/ActionType.ts b/packages/legacy-client/src/client/baseTypes/ActionType.ts index 49aa680d1..3791d75ac 100644 --- a/packages/legacy-client/src/client/baseTypes/ActionType.ts +++ b/packages/legacy-client/src/client/baseTypes/ActionType.ts @@ -16,6 +16,7 @@ import type { OntologyDefinition } from "@osdk/api"; import type { + ActionResults_Edits, BatchApplyActionResponseV2, SyncApplyActionResponseV2, } from "@osdk/gateway/types"; @@ -162,31 +163,9 @@ export const ActionResponse = { ], }; if (response.edits?.type === "edits") { - const added = []; - const modified = []; - for (const edit of response.edits.edits) { - if (edit.type === "addObject") { - added.push({ - apiName: edit.objectType, - primaryKey: edit.primaryKey, - get: () => getObject(client, edit.objectType, edit.primaryKey), - }); - } - if (edit.type === "modifyObject") { - modified.push({ - apiName: edit.objectType, - primaryKey: edit.primaryKey, - get: () => getObject(client, edit.objectType, edit.primaryKey), - }); - } - } return { validation, - edits: { - type: "edits", - added, - modified, - }, + ...getEdits(response.edits, client), } as ActionResponse>; } if (response.edits?.type === "largeScaleEdits") { @@ -213,31 +192,9 @@ export const BulkActionResponse = { response: BatchApplyActionResponseV2, ): BulkActionResponse | undefined> => { if (response.edits?.type === "edits") { - const added = []; - const modified = []; - for (const edit of response.edits.edits) { - if (edit.type === "addObject") { - added.push({ - apiName: edit.objectType, - primaryKey: edit.primaryKey, - get: () => getObject(client, edit.objectType, edit.primaryKey), - }); - } - if (edit.type === "modifyObject") { - modified.push({ - apiName: edit.objectType, - primaryKey: edit.primaryKey, - get: () => getObject(client, edit.objectType, edit.primaryKey), - }); - } - } - return { - edits: { - type: "edits", - added, - modified, - }, - } as BulkActionResponse>; + return getEdits(response.edits, client) as BulkActionResponse< + Edits + >; } if (response.edits?.type === "largeScaleEdits") { return { @@ -249,3 +206,34 @@ export const BulkActionResponse = { return {} as BulkActionResponse; }, }; + +function getEdits( + response: ActionResults_Edits, + client: ClientContext>, +) { + const added = []; + const modified = []; + for (const edit of response.edits) { + if (edit.type === "addObject") { + added.push({ + apiName: edit.objectType, + primaryKey: edit.primaryKey, + get: () => getObject(client, edit.objectType, edit.primaryKey), + }); + } + if (edit.type === "modifyObject") { + modified.push({ + apiName: edit.objectType, + primaryKey: edit.primaryKey, + get: () => getObject(client, edit.objectType, edit.primaryKey), + }); + } + } + return { + edits: { + type: "edits", + added, + modified, + }, + }; +} From 78f048cd7ecab1d9a13a59814adb9f29ba70b8cf Mon Sep 17 00:00:00 2001 From: Saurav Date: Wed, 14 Feb 2024 14:09:35 -0500 Subject: [PATCH 09/11] add bulk no params options --- .../ontology/actions/BulkActions.ts | 1 + packages/generator/src/v1.1/generateBulkActions.ts | 2 ++ .../src/client/actions/actions.test.ts | 1 + .../legacy-client/src/client/actions/actions.ts | 13 ++++--------- .../src/client/actions/createActionProxy.ts | 13 ------------- 5 files changed, 8 insertions(+), 22 deletions(-) diff --git a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts index 242791e97..7a90b46b4 100644 --- a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts +++ b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts @@ -38,6 +38,7 @@ export interface BulkActions { * Creates a new Todo */ createTodo( + params: {}[], options?: O, ): Promise>, ActionError>>; } diff --git a/packages/generator/src/v1.1/generateBulkActions.ts b/packages/generator/src/v1.1/generateBulkActions.ts index f275e0a0e..ed849163f 100644 --- a/packages/generator/src/v1.1/generateBulkActions.ts +++ b/packages/generator/src/v1.1/generateBulkActions.ts @@ -62,6 +62,8 @@ export async function generateBulkActions( ); } parameterBlock += "}[], "; + } else { + parameterBlock = `params: {}[], `; } jsDocBlock.push(`*/`); diff --git a/packages/legacy-client/src/client/actions/actions.test.ts b/packages/legacy-client/src/client/actions/actions.test.ts index 95a89028f..f1ac5ff9e 100644 --- a/packages/legacy-client/src/client/actions/actions.test.ts +++ b/packages/legacy-client/src/client/actions/actions.test.ts @@ -162,6 +162,7 @@ describe("Actions", () => { expectTypeOf>().toEqualTypeOf< [ + {}[], BulkActionExecutionOptions?, ] >(); diff --git a/packages/legacy-client/src/client/actions/actions.ts b/packages/legacy-client/src/client/actions/actions.ts index 2408cdbd2..f7c3d3ca3 100644 --- a/packages/legacy-client/src/client/actions/actions.ts +++ b/packages/legacy-client/src/client/actions/actions.ts @@ -184,13 +184,8 @@ export type Actions< }; export type BulkActions> = { - [A in keyof O["actions"]]: - IsEmptyRecord extends true - ? ( - options?: Op, - ) => WrappedBulkActionReturnType - : []>( - params: P, - options?: Op, - ) => WrappedBulkActionReturnType; + [A in keyof O["actions"]]: ( + params: ActionArgs[], + options?: Op, + ) => WrappedBulkActionReturnType; }; diff --git a/packages/legacy-client/src/client/actions/createActionProxy.ts b/packages/legacy-client/src/client/actions/createActionProxy.ts index 7077fac1e..75f111928 100644 --- a/packages/legacy-client/src/client/actions/createActionProxy.ts +++ b/packages/legacy-client/src/client/actions/createActionProxy.ts @@ -90,19 +90,6 @@ export function createBulkActionProxy< { get: (_target, p: keyof O["actions"], _receiver) => { if (typeof p === "string") { - if (Object.keys(client.ontology.actions[p].parameters).length === 0) { - return async function( - options?: Op, - ): Promise> { - return executeBatchAction( - client, - p, - undefined, - options, - ); - }; - } - return async function< Op extends BulkActionExecutionOptions, >( From 0fa395a05f121a0c69460b813e5cd2f2cf568f80 Mon Sep 17 00:00:00 2001 From: Saurav Date: Wed, 14 Feb 2024 16:20:10 -0500 Subject: [PATCH 10/11] restrict object : --- .../src/client/actions/actions.test.ts | 2 +- .../legacy-client/src/client/actions/actions.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/legacy-client/src/client/actions/actions.test.ts b/packages/legacy-client/src/client/actions/actions.test.ts index f1ac5ff9e..db1fdea25 100644 --- a/packages/legacy-client/src/client/actions/actions.test.ts +++ b/packages/legacy-client/src/client/actions/actions.test.ts @@ -162,7 +162,7 @@ describe("Actions", () => { expectTypeOf>().toEqualTypeOf< [ - {}[], + Record[], BulkActionExecutionOptions?, ] >(); diff --git a/packages/legacy-client/src/client/actions/actions.ts b/packages/legacy-client/src/client/actions/actions.ts index f7c3d3ca3..1c62f9744 100644 --- a/packages/legacy-client/src/client/actions/actions.ts +++ b/packages/legacy-client/src/client/actions/actions.ts @@ -184,8 +184,14 @@ export type Actions< }; export type BulkActions> = { - [A in keyof O["actions"]]: ( - params: ActionArgs[], - options?: Op, - ) => WrappedBulkActionReturnType; + [A in keyof O["actions"]]: + IsEmptyRecord extends true + ? ( + params: Record[], + options?: Op, + ) => WrappedBulkActionReturnType + : ( + params: ActionArgs[], + options?: Op, + ) => WrappedBulkActionReturnType; }; From 493acd03061a50471ff5263543983003551841a2 Mon Sep 17 00:00:00 2001 From: Saurav Date: Wed, 14 Feb 2024 16:24:07 -0500 Subject: [PATCH 11/11] fix generate type --- .../src/generatedNoCheck/ontology/actions/BulkActions.ts | 2 +- packages/generator/src/v1.1/generateBulkActions.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts index 7a90b46b4..e23e002b2 100644 --- a/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts +++ b/examples/one_dot_one/src/generatedNoCheck/ontology/actions/BulkActions.ts @@ -38,7 +38,7 @@ export interface BulkActions { * Creates a new Todo */ createTodo( - params: {}[], + params: Record[], options?: O, ): Promise>, ActionError>>; } diff --git a/packages/generator/src/v1.1/generateBulkActions.ts b/packages/generator/src/v1.1/generateBulkActions.ts index ed849163f..9eab825e3 100644 --- a/packages/generator/src/v1.1/generateBulkActions.ts +++ b/packages/generator/src/v1.1/generateBulkActions.ts @@ -63,7 +63,7 @@ export async function generateBulkActions( } parameterBlock += "}[], "; } else { - parameterBlock = `params: {}[], `; + parameterBlock = `params: Record[], `; } jsDocBlock.push(`*/`);