diff --git a/src/dataverse-ify/DataverseClient/DataverseClient.ts b/src/dataverse-ify/DataverseClient/DataverseClient.ts index a66e0d7..f3d9676 100644 --- a/src/dataverse-ify/DataverseClient/DataverseClient.ts +++ b/src/dataverse-ify/DataverseClient/DataverseClient.ts @@ -41,5 +41,5 @@ export interface DataverseClient { relatedEntities: EntityReference[], ): Promise; execute(request: WebApiExecuteRequest): Promise; - executeMultiple(requests: WebApiExecuteRequest[]): Promise; + executeMultiple(requests: (WebApiExecuteRequest | WebApiExecuteRequest[])[]): Promise; } diff --git a/src/dataverse-ify/__tests__/integration-tests/odata-retrievemultiple.test.ts b/src/dataverse-ify/__tests__/integration-tests/odata-retrievemultiple.test.ts index 06b1f15..ea30bbf 100644 --- a/src/dataverse-ify/__tests__/integration-tests/odata-retrievemultiple.test.ts +++ b/src/dataverse-ify/__tests__/integration-tests/odata-retrievemultiple.test.ts @@ -28,7 +28,7 @@ describe("retrieveMultiple", () => { const client = new XrmContextDataverseClient(Xrm.WebApi); // Create 12 records - const name = `fetch test ${new Date()}`; + const name = `fetch test ${new Date().toISOString()}`; const testRecord = { logicalName: cdsify_integrationtestMetadata.logicalName, cdsify_name: name, diff --git a/src/dataverse-ify/__tests__/unit-tests/field-lookup.test.ts b/src/dataverse-ify/__tests__/unit-tests/field-lookup.test.ts index bd4e9b4..721dee1 100644 --- a/src/dataverse-ify/__tests__/unit-tests/field-lookup.test.ts +++ b/src/dataverse-ify/__tests__/unit-tests/field-lookup.test.ts @@ -47,3 +47,67 @@ test("odataify lookups", async () => { }; expect(JSON.stringify(sdkRecord)).toBe(JSON.stringify(expectedSdk)); }); + +test("odataify lookups with undefined", async () => { + setMetadataCache({ entities: { account: accountMetadata } }); + const accountSdk = { + logicalName: accountMetadata.logicalName, + parentaccountid: undefined, + } as Account; + + const accountOdata = await odataify("Create", accountSdk); + expect(accountOdata).toBeDefined(); + const expectedOdata = { + "@odata.type": "Microsoft.Dynamics.CRM.account", + parentaccountid: null, + }; + expect(accountOdata).toEqual(expectedOdata); +}); + +test("odataify lookups with null", async () => { + setMetadataCache({ entities: { account: accountMetadata } }); + const accountSdk = { + logicalName: accountMetadata.logicalName, + parentaccountid: null, + } as Account; + + const accountOdata = await odataify("Create", accountSdk); + expect(accountOdata).toBeDefined(); + const expectedOdata = { + "@odata.type": "Microsoft.Dynamics.CRM.account", + parentaccountid: null, + }; + expect(accountOdata).toEqual(expectedOdata); +}); + +test("odataify lookups with undefined and navigation property", async () => { + setMetadataCache({ entities: { account: accountMetadata } }); + const accountSdk = { + logicalName: accountMetadata.logicalName, + cdsify_account1: undefined, + } as Account; + + const accountOdata = await odataify("Create", accountSdk); + expect(accountOdata).toBeDefined(); + const expectedOdata = { + "@odata.type": "Microsoft.Dynamics.CRM.account", + cdsify_Account1: null, + }; + expect(accountOdata).toEqual(expectedOdata); +}); + +test("odataify lookups with null and navigation property", async () => { + setMetadataCache({ entities: { account: accountMetadata } }); + const accountSdk = { + logicalName: accountMetadata.logicalName, + cdsify_account1: null, + } as Account; + + const accountOdata = await odataify("Create", accountSdk); + expect(accountOdata).toBeDefined(); + const expectedOdata = { + "@odata.type": "Microsoft.Dynamics.CRM.account", + cdsify_Account1: null, + }; + expect(accountOdata).toEqual(expectedOdata); +}); diff --git a/src/dataverse-ify/__tests__/unit-tests/field-primitive.test.ts b/src/dataverse-ify/__tests__/unit-tests/field-primitive.test.ts index c2576f7..3c61eb5 100644 --- a/src/dataverse-ify/__tests__/unit-tests/field-primitive.test.ts +++ b/src/dataverse-ify/__tests__/unit-tests/field-primitive.test.ts @@ -52,6 +52,30 @@ test("Empty String, Integer, Double, Money, Date Attributes", async () => { expect(JSON.stringify(accountOdata)).toBe(JSON.stringify(expectedOdata)); }); +test("Null String, Integer, Double, Money, Date Attributes", async () => { + setMetadataCache({ entities: { account: accountMetadata } }); + const accountSdk = { + logicalName: accountMetadata.logicalName, + description: null, // String + address1_utcoffset: null, // Integer + address1_latitude: null, // Double + revenue: null, // Money + lastonholdtime: null, // Date + } as Account; + + const accountOdata = await odataify("Create", accountSdk); + expect(accountOdata).toBeDefined(); + const expectedOdata = { + description: null, + address1_utcoffset: null, // Int should be truncated + address1_latitude: null, + revenue: null, + lastonholdtime: null, + "@odata.type": "Microsoft.Dynamics.CRM.account", + }; + expect(accountOdata).toEqual(expectedOdata); +}); + test("sdkify Date fields", async () => { setMetadataCache({ entities: { account: accountMetadata } }); const accountOdata = { diff --git a/src/dataverse-ify/odataify/odataifyFields.ts b/src/dataverse-ify/odataify/odataifyFields.ts index 3753582..4aa002a 100644 --- a/src/dataverse-ify/odataify/odataifyFields.ts +++ b/src/dataverse-ify/odataify/odataifyFields.ts @@ -73,10 +73,10 @@ async function addNullValueToOutput(field: string, metadata: EntityWebApiMetadat // if lookup field, use the Schema Name from navigation // TODO: I don't think this is strictly necessary const navigation = caseInsensitiveSearch(field, metadata.navigation as Dictionary); - if (navigation) { - output[navigation.key] = null; - // Do not delete the field since this fails the nullvalues.test.ts integration test - // delete output[field]; + if (navigation && navigation.key !== field) { + // only needed if the field is different from navigation key (e.g. cdsify_account1 vs cdsify_Account1) + output[navigation.key] = null; // set cdsify_Account1 to null + delete output[field]; // remove cdsify_account1 } } diff --git a/src/webapi/node/__tests__/CRUD/response-errors.test.ts b/src/webapi/node/__tests__/CRUD/response-errors.test.ts index 199df02..624e2ff 100644 --- a/src/webapi/node/__tests__/CRUD/response-errors.test.ts +++ b/src/webapi/node/__tests__/CRUD/response-errors.test.ts @@ -30,7 +30,7 @@ describe("XrmWebApiNode", () => { await Xrm.WebApi.deleteRecord("account", "f0161204-0f0a-ed11-82e6-0022483d2320"); } catch (e) { expect((e as Error).message).toMatch( - /(Id = f0161204-0f0a-ed11-82e6-0022483d2320 Does Not Exist)|(The requested record was not found or you do not have sufficient permissions to view it)/, + /(Account With Id = f0161204-0f0a-ed11-82e6-0022483d2320 Does Not Exist)|(The requested record was not found or you do not have sufficient permissions to view it)|Entity 'account' With Id = f0161204-0f0a-ed11-82e6-0022483d2320 Does Not Exist/, ); } }, 10000);