@defra-fish/dynamics-lib 1.69.0-rc.6 → 1.70.0-dynamics-upgrade
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +3 -4
- package/src/__mocks__/dynamics-web-api-mock-helper.js +6 -6
- package/src/__mocks__/dynamics-web-api.js +4 -2
- package/src/client/__tests__/dynamics-client.spec.js +11 -13
- package/src/client/__tests__/entity-manager.spec.js +27 -27
- package/src/client/dynamics-client.js +7 -5
- package/src/client/entity-manager.js +12 -9
- package/src/entities/base.entity.js +1 -1
- package/src/queries/__tests__/contact.queries.spec.js +7 -5
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ shared by the different packages which comprise the Rod Licensing digital servic
|
|
|
16
16
|
| OAUTH_AUTHORITY_HOST_URL | OAuth 2.0 authority host | yes | | | |
|
|
17
17
|
| OAUTH_TENANT | OAuth 2.0 tenant | yes | | | |
|
|
18
18
|
| OAUTH_SCOPE | OAuth 2.0 scope to request (client credentials resource) | yes | | | |
|
|
19
|
-
| DYNAMICS_API_PATH |
|
|
19
|
+
| DYNAMICS_API_PATH | The root domain of the dynamics server | yes | | | The root domain of the dynamics server. e.g. https://dynamics-server |
|
|
20
20
|
| DYNAMICS_API_VERSION | The version of the Dynamics API | yes | | | The version of the dynamics web api. e.g. 9.1 |
|
|
21
21
|
| DYNAMICS_API_TIMEOUT | The Dynamics API request timeout | no | 90000 | | The time in milliseconds after which requests will timeout if Dynamics does not return a response, e.g. 90000 |
|
|
22
22
|
| DYNAMICS_CACHE_TTL | Default TTL for cached operations | no | 12 hours | | The default TTL for cached operations. Specified in seconds. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/dynamics-lib",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.70.0-dynamics-upgrade",
|
|
4
4
|
"description": "Framework to support integration with dynamics",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -36,12 +36,11 @@
|
|
|
36
36
|
"cache-manager": "3.6.0",
|
|
37
37
|
"cache-manager-ioredis": "2.1.0",
|
|
38
38
|
"debug": "4.3.3",
|
|
39
|
-
"dynamics-web-api": "
|
|
39
|
+
"dynamics-web-api": "^2.4.0",
|
|
40
40
|
"joi": "17.13.3",
|
|
41
41
|
"moment": "2.29.1",
|
|
42
42
|
"pluralize": "8.0.0",
|
|
43
43
|
"simple-oauth2": "4.3.0",
|
|
44
44
|
"uuid": "8.3.2"
|
|
45
|
-
}
|
|
46
|
-
"gitHead": "8e77ed08621e055f9c691f190f109fab84fd472e"
|
|
45
|
+
}
|
|
47
46
|
}
|
|
@@ -3,7 +3,7 @@ const { readFileSync } = jest.requireActual('fs')
|
|
|
3
3
|
const Path = jest.requireActual('path')
|
|
4
4
|
const optionSetDataPath = Path.join(Project.root, 'src', '__mocks__', 'option-set-data.json')
|
|
5
5
|
|
|
6
|
-
export const configureDynamicsWebApiMock =
|
|
6
|
+
export const configureDynamicsWebApiMock = DynamicsWebApi => {
|
|
7
7
|
let expectedResponse = {}
|
|
8
8
|
let nextResponses = {}
|
|
9
9
|
let callError = {}
|
|
@@ -53,12 +53,12 @@ export const configureDynamicsWebApiMock = (DynamicsWebApi = jest.genMockFromMod
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
DynamicsWebApi.prototype.
|
|
57
|
-
DynamicsWebApi.prototype.
|
|
58
|
-
DynamicsWebApi.prototype.
|
|
59
|
-
DynamicsWebApi.prototype.
|
|
56
|
+
DynamicsWebApi.prototype.retrieve = jest.fn(async () => responseCapableMethod('retrieve'))
|
|
57
|
+
DynamicsWebApi.prototype.create = jest.fn(async () => responseCapableMethod('create'))
|
|
58
|
+
DynamicsWebApi.prototype.update = jest.fn(async () => responseCapableMethod('update'))
|
|
59
|
+
DynamicsWebApi.prototype.retrieveMultiple = jest.fn(async () => responseCapableMethod('retrieveMultiple'))
|
|
60
60
|
DynamicsWebApi.prototype.retrieveGlobalOptionSets = jest.fn(async () => responseCapableMethod('retrieveGlobalOptionSets'))
|
|
61
|
-
DynamicsWebApi.prototype.
|
|
61
|
+
DynamicsWebApi.prototype.callFunction = jest.fn(async functionName => {
|
|
62
62
|
let returnValue = null
|
|
63
63
|
if (functionName === 'RetrieveVersion') {
|
|
64
64
|
returnValue = {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { configureDynamicsWebApiMock } from './dynamics-web-api-mock-helper.js'
|
|
2
|
-
const DynamicsWebApi = jest.
|
|
3
|
-
|
|
2
|
+
const DynamicsWebApi = jest.fn()
|
|
3
|
+
DynamicsWebApi.prototype = {}
|
|
4
|
+
configureDynamicsWebApiMock(DynamicsWebApi)
|
|
5
|
+
export { DynamicsWebApi }
|
|
@@ -3,7 +3,7 @@ import SimpleOAuth2 from 'simple-oauth2'
|
|
|
3
3
|
|
|
4
4
|
describe('dynamics-client', () => {
|
|
5
5
|
it('is configured via environment variables', async () => {
|
|
6
|
-
process.env.DYNAMICS_API_PATH = 'https://test-server
|
|
6
|
+
process.env.DYNAMICS_API_PATH = 'https://test-server'
|
|
7
7
|
process.env.DYNAMICS_API_VERSION = '9.1'
|
|
8
8
|
process.env.DYNAMICS_API_TIMEOUT = 60000
|
|
9
9
|
process.env.OAUTH_AUTHORITY_HOST_URL = 'https://test-authority/'
|
|
@@ -14,26 +14,24 @@ describe('dynamics-client', () => {
|
|
|
14
14
|
const dynamicsApiConfig = config()
|
|
15
15
|
|
|
16
16
|
expect(dynamicsApiConfig).toMatchObject({
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
serverUrl: process.env.DYNAMICS_API_PATH,
|
|
18
|
+
dataApi: { version: process.env.DYNAMICS_API_VERSION },
|
|
19
19
|
timeout: `${process.env.DYNAMICS_API_TIMEOUT}`,
|
|
20
20
|
onTokenRefresh: expect.any(Function)
|
|
21
21
|
})
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
expect(testCallback).toHaveBeenCalledWith('MOCK TOKEN')
|
|
22
|
+
const token = await dynamicsApiConfig.onTokenRefresh()
|
|
23
|
+
expect(token).toBe('MOCK TOKEN')
|
|
25
24
|
})
|
|
26
25
|
|
|
27
26
|
it('caches tokens until they expire', async () => {
|
|
28
27
|
const dynamicsApiConfig = config()
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
expect(testCallback).toHaveBeenLastCalledWith('MOCK TOKEN')
|
|
28
|
+
let token = await dynamicsApiConfig.onTokenRefresh()
|
|
29
|
+
expect(token).toBe('MOCK TOKEN')
|
|
32
30
|
SimpleOAuth2.__setMockTokenReturnValue('NEW MOCK TOKEN')
|
|
33
|
-
await dynamicsApiConfig.onTokenRefresh(
|
|
34
|
-
expect(
|
|
31
|
+
token = await dynamicsApiConfig.onTokenRefresh()
|
|
32
|
+
expect(token).toBe('MOCK TOKEN')
|
|
35
33
|
SimpleOAuth2.__setMockTokenExpired(true)
|
|
36
|
-
await dynamicsApiConfig.onTokenRefresh(
|
|
37
|
-
expect(
|
|
34
|
+
token = await dynamicsApiConfig.onTokenRefresh()
|
|
35
|
+
expect(token).toBe('NEW MOCK TOKEN')
|
|
38
36
|
})
|
|
39
37
|
})
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from '../../index.js'
|
|
14
14
|
import TestEntity from '../../__mocks__/TestEntity.js'
|
|
15
15
|
import { v4 as uuidv4 } from 'uuid'
|
|
16
|
-
import MockDynamicsWebApi from 'dynamics-web-api'
|
|
16
|
+
import { DynamicsWebApi as MockDynamicsWebApi } from 'dynamics-web-api'
|
|
17
17
|
import { PredefinedQuery } from '../../queries/predefined-query.js'
|
|
18
18
|
import { BaseEntity, EntityDefinition } from '../../entities/base.entity.js'
|
|
19
19
|
|
|
@@ -33,7 +33,7 @@ describe('entity manager', () => {
|
|
|
33
33
|
t.boolVal = true
|
|
34
34
|
|
|
35
35
|
const result = await persist([t])
|
|
36
|
-
expect(MockDynamicsWebApi.prototype.
|
|
36
|
+
expect(MockDynamicsWebApi.prototype.create).toHaveBeenCalled()
|
|
37
37
|
expect(result).toHaveLength(1)
|
|
38
38
|
expect(result[0]).toEqual(resultUuid)
|
|
39
39
|
})
|
|
@@ -54,7 +54,7 @@ describe('entity manager', () => {
|
|
|
54
54
|
)
|
|
55
55
|
|
|
56
56
|
const result = await persist([t])
|
|
57
|
-
expect(MockDynamicsWebApi.prototype.
|
|
57
|
+
expect(MockDynamicsWebApi.prototype.update).toHaveBeenCalled()
|
|
58
58
|
expect(result).toHaveLength(1)
|
|
59
59
|
expect(result[0]).toEqual(resultUuid)
|
|
60
60
|
})
|
|
@@ -69,7 +69,7 @@ describe('entity manager', () => {
|
|
|
69
69
|
t.boolVal = true
|
|
70
70
|
|
|
71
71
|
const result = await persist([t], 'foo')
|
|
72
|
-
expect(MockDynamicsWebApi.prototype.
|
|
72
|
+
expect(MockDynamicsWebApi.prototype.create).toHaveBeenCalled()
|
|
73
73
|
expect(MockDynamicsWebApi.prototype.executeBatch).toHaveBeenCalledWith(
|
|
74
74
|
expect.objectContaining({
|
|
75
75
|
impersonateAAD: 'foo'
|
|
@@ -94,10 +94,10 @@ describe('entity manager', () => {
|
|
|
94
94
|
{}
|
|
95
95
|
)
|
|
96
96
|
await expect(persist([newEntity, existingEntity])).rejects.toThrow('Test error')
|
|
97
|
-
// Expect the console error to contain details of the batch data (one
|
|
97
|
+
// Expect the console error to contain details of the batch data (one create, one update plus the exception object)
|
|
98
98
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
99
99
|
expect.stringMatching('Error persisting batch. Data: %j, Exception: %o'),
|
|
100
|
-
expect.arrayContaining([{
|
|
100
|
+
expect.arrayContaining([{ create: expect.any(Object) }, { update: expect.any(Object) }]),
|
|
101
101
|
expect.any(Error)
|
|
102
102
|
)
|
|
103
103
|
})
|
|
@@ -332,14 +332,14 @@ describe('entity manager', () => {
|
|
|
332
332
|
|
|
333
333
|
describe('findById', () => {
|
|
334
334
|
it('finds by a primary key guid', async () => {
|
|
335
|
-
MockDynamicsWebApi.__setResponse('
|
|
335
|
+
MockDynamicsWebApi.__setResponse('retrieve', {
|
|
336
336
|
'@odata.etag': 'W/"202465000"',
|
|
337
337
|
idval: '9f1b34a0-0c66-e611-80dc-c4346bad0190',
|
|
338
338
|
strval: 'example'
|
|
339
339
|
})
|
|
340
340
|
|
|
341
341
|
const result = await findById(TestEntity, '9f1b34a0-0c66-e611-80dc-c4346bad0190')
|
|
342
|
-
expect(MockDynamicsWebApi.prototype.
|
|
342
|
+
expect(MockDynamicsWebApi.prototype.retrieve).toBeCalledWith({
|
|
343
343
|
key: '9f1b34a0-0c66-e611-80dc-c4346bad0190',
|
|
344
344
|
collection: TestEntity.definition.dynamicsCollection,
|
|
345
345
|
select: TestEntity.definition.select
|
|
@@ -350,13 +350,13 @@ describe('entity manager', () => {
|
|
|
350
350
|
it('returns null if not found', async () => {
|
|
351
351
|
const notFoundError = new Error('Not found')
|
|
352
352
|
notFoundError.status = 404
|
|
353
|
-
MockDynamicsWebApi.__throwWithErrorOn('
|
|
353
|
+
MockDynamicsWebApi.__throwWithErrorOn('retrieve', notFoundError)
|
|
354
354
|
const result = await findById(TestEntity, '9f1b34a0-0c66-e611-80dc-c4346bad0190')
|
|
355
355
|
expect(result).toEqual(null)
|
|
356
356
|
})
|
|
357
357
|
|
|
358
358
|
it('throws an exception on general errors', async () => {
|
|
359
|
-
MockDynamicsWebApi.__throwWithErrorOn('
|
|
359
|
+
MockDynamicsWebApi.__throwWithErrorOn('retrieve')
|
|
360
360
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
|
|
361
361
|
await expect(findById(TestEntity, '9f1b34a0-0c66-e611-80dc-c4346bad0190')).rejects.toThrow('Test error')
|
|
362
362
|
expect(consoleErrorSpy).toHaveBeenCalled()
|
|
@@ -365,13 +365,13 @@ describe('entity manager', () => {
|
|
|
365
365
|
|
|
366
366
|
describe('findByAlternateKey', () => {
|
|
367
367
|
it('finds by an alternate key', async () => {
|
|
368
|
-
MockDynamicsWebApi.__setResponse('
|
|
368
|
+
MockDynamicsWebApi.__setResponse('retrieve', {
|
|
369
369
|
'@odata.etag': 'W/"202465000"',
|
|
370
370
|
idval: '9f1b34a0-0c66-e611-80dc-c4346bad0190',
|
|
371
371
|
strval: 'example'
|
|
372
372
|
})
|
|
373
373
|
const result = await findByAlternateKey(TestEntity, 'example')
|
|
374
|
-
expect(MockDynamicsWebApi.prototype.
|
|
374
|
+
expect(MockDynamicsWebApi.prototype.retrieve).toBeCalledWith({
|
|
375
375
|
key: "strval='example'",
|
|
376
376
|
collection: TestEntity.definition.dynamicsCollection,
|
|
377
377
|
select: TestEntity.definition.select
|
|
@@ -381,13 +381,13 @@ describe('entity manager', () => {
|
|
|
381
381
|
})
|
|
382
382
|
|
|
383
383
|
it('escapes special characters in the key', async () => {
|
|
384
|
-
MockDynamicsWebApi.__setResponse('
|
|
384
|
+
MockDynamicsWebApi.__setResponse('retrieve', {
|
|
385
385
|
'@odata.etag': 'W/"202465000"',
|
|
386
386
|
idval: '9f1b34a0-0c66-e611-80dc-c4346bad0190',
|
|
387
387
|
strval: 'example'
|
|
388
388
|
})
|
|
389
389
|
const result = await findByAlternateKey(TestEntity, "test & example'")
|
|
390
|
-
expect(MockDynamicsWebApi.prototype.
|
|
390
|
+
expect(MockDynamicsWebApi.prototype.retrieve).toBeCalledWith({
|
|
391
391
|
key: "strval='test %26 example'''",
|
|
392
392
|
collection: TestEntity.definition.dynamicsCollection,
|
|
393
393
|
select: TestEntity.definition.select
|
|
@@ -399,7 +399,7 @@ describe('entity manager', () => {
|
|
|
399
399
|
|
|
400
400
|
describe('findByExample', () => {
|
|
401
401
|
it('builds a select statement appropriate to the type definition for each field', async () => {
|
|
402
|
-
MockDynamicsWebApi.__setResponse('
|
|
402
|
+
MockDynamicsWebApi.__setResponse('retrieveMultiple', { value: [{}] })
|
|
403
403
|
|
|
404
404
|
const lookup = new TestEntity()
|
|
405
405
|
lookup.strVal = 'StringData'
|
|
@@ -412,7 +412,7 @@ describe('entity manager', () => {
|
|
|
412
412
|
const expectedLookupSelect =
|
|
413
413
|
"strval eq 'StringData' and intval eq 123 and decval eq 123.45 and boolval eq true and dateval eq 1946-01-01 and datetimeval eq 1946-01-01T01:02:03Z and optionsetval eq 910400000"
|
|
414
414
|
const result = await findByExample(lookup)
|
|
415
|
-
expect(MockDynamicsWebApi.prototype.
|
|
415
|
+
expect(MockDynamicsWebApi.prototype.retrieveMultiple).toBeCalledWith({
|
|
416
416
|
collection: TestEntity.definition.dynamicsCollection,
|
|
417
417
|
select: TestEntity.definition.select,
|
|
418
418
|
filter: expect.stringMatching(`${TestEntity.definition.defaultFilter} and ${expectedLookupSelect}`)
|
|
@@ -422,7 +422,7 @@ describe('entity manager', () => {
|
|
|
422
422
|
})
|
|
423
423
|
|
|
424
424
|
it('does not require the entity to define a default filter', async () => {
|
|
425
|
-
MockDynamicsWebApi.__setResponse('
|
|
425
|
+
MockDynamicsWebApi.__setResponse('retrieveMultiple', { value: [{}] })
|
|
426
426
|
|
|
427
427
|
class SameEntity extends BaseEntity {
|
|
428
428
|
static _definition = new EntityDefinition(() => ({
|
|
@@ -458,7 +458,7 @@ describe('entity manager', () => {
|
|
|
458
458
|
lookup.testVal = 'StringData'
|
|
459
459
|
const expectedLookupSelect = "testval eq 'StringData'"
|
|
460
460
|
const result = await findByExample(lookup)
|
|
461
|
-
expect(MockDynamicsWebApi.prototype.
|
|
461
|
+
expect(MockDynamicsWebApi.prototype.retrieveMultiple).toBeCalledWith({
|
|
462
462
|
collection: SameEntity.definition.dynamicsCollection,
|
|
463
463
|
select: SameEntity.definition.select,
|
|
464
464
|
filter: expect.stringMatching(`${expectedLookupSelect}`)
|
|
@@ -468,13 +468,13 @@ describe('entity manager', () => {
|
|
|
468
468
|
})
|
|
469
469
|
|
|
470
470
|
it('only serializes fields into the select statement if they are set', async () => {
|
|
471
|
-
MockDynamicsWebApi.__setResponse('
|
|
471
|
+
MockDynamicsWebApi.__setResponse('retrieveMultiple', { value: [{}] })
|
|
472
472
|
|
|
473
473
|
const lookup = new TestEntity()
|
|
474
474
|
lookup.strVal = 'StringData'
|
|
475
475
|
const expectedLookupSelect = "strval eq 'StringData'"
|
|
476
476
|
const result = await findByExample(lookup)
|
|
477
|
-
expect(MockDynamicsWebApi.prototype.
|
|
477
|
+
expect(MockDynamicsWebApi.prototype.retrieveMultiple).toBeCalledWith({
|
|
478
478
|
collection: TestEntity.definition.dynamicsCollection,
|
|
479
479
|
select: TestEntity.definition.select,
|
|
480
480
|
filter: expect.stringMatching(`${TestEntity.definition.defaultFilter} and ${expectedLookupSelect}`)
|
|
@@ -484,7 +484,7 @@ describe('entity manager', () => {
|
|
|
484
484
|
})
|
|
485
485
|
|
|
486
486
|
it('throws an error object on failure', async () => {
|
|
487
|
-
MockDynamicsWebApi.__throwWithErrorOn('
|
|
487
|
+
MockDynamicsWebApi.__throwWithErrorOn('retrieveMultiple')
|
|
488
488
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
|
|
489
489
|
await expect(findByExample(new TestEntity())).rejects.toThrow('Test error')
|
|
490
490
|
expect(consoleErrorSpy).toHaveBeenCalled()
|
|
@@ -492,8 +492,8 @@ describe('entity manager', () => {
|
|
|
492
492
|
})
|
|
493
493
|
|
|
494
494
|
describe('executeQuery', () => {
|
|
495
|
-
it('calls
|
|
496
|
-
MockDynamicsWebApi.__setResponse('
|
|
495
|
+
it('calls retrieveMultiple on the Dynamics API with the request data', async () => {
|
|
496
|
+
MockDynamicsWebApi.__setResponse('retrieveMultiple', {
|
|
497
497
|
value: [
|
|
498
498
|
{
|
|
499
499
|
'@odata.etag': 'W/"202465000"',
|
|
@@ -504,7 +504,7 @@ describe('entity manager', () => {
|
|
|
504
504
|
})
|
|
505
505
|
|
|
506
506
|
const result = await executeQuery(new PredefinedQuery({ root: TestEntity, filter: "strval eq 'example'" }))
|
|
507
|
-
expect(MockDynamicsWebApi.prototype.
|
|
507
|
+
expect(MockDynamicsWebApi.prototype.retrieveMultiple).toBeCalledWith({
|
|
508
508
|
collection: TestEntity.definition.dynamicsCollection,
|
|
509
509
|
filter: "strval eq 'example'",
|
|
510
510
|
select: TestEntity.definition.select
|
|
@@ -516,7 +516,7 @@ describe('entity manager', () => {
|
|
|
516
516
|
})
|
|
517
517
|
|
|
518
518
|
it('throws an error object on failure', async () => {
|
|
519
|
-
MockDynamicsWebApi.__throwWithErrorOn('
|
|
519
|
+
MockDynamicsWebApi.__throwWithErrorOn('retrieveMultiple')
|
|
520
520
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
|
|
521
521
|
await expect(executeQuery(new PredefinedQuery({ root: TestEntity, filter: "strval eq 'example'" }))).rejects.toThrow('Test error')
|
|
522
522
|
expect(consoleErrorSpy).toHaveBeenCalled()
|
|
@@ -527,7 +527,7 @@ describe('entity manager', () => {
|
|
|
527
527
|
beforeEach(async () => {
|
|
528
528
|
MockDynamicsWebApi.__reset()
|
|
529
529
|
MockDynamicsWebApi.__setNextResponses(
|
|
530
|
-
'
|
|
530
|
+
'retrieveMultiple',
|
|
531
531
|
{
|
|
532
532
|
value: [
|
|
533
533
|
{
|
|
@@ -592,7 +592,7 @@ describe('entity manager', () => {
|
|
|
592
592
|
})
|
|
593
593
|
|
|
594
594
|
it('throws an error object on failure', async () => {
|
|
595
|
-
MockDynamicsWebApi.__throwWithErrorOn('
|
|
595
|
+
MockDynamicsWebApi.__throwWithErrorOn('retrieveMultiple')
|
|
596
596
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
|
|
597
597
|
await expect(
|
|
598
598
|
executePagedQuery(new PredefinedQuery({ root: TestEntity, filter: "strval eq 'example'" }), () => {}, 1)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import DynamicsWebApi from 'dynamics-web-api'
|
|
1
|
+
import { DynamicsWebApi } from 'dynamics-web-api'
|
|
2
2
|
import SimpleOAuth2 from 'simple-oauth2'
|
|
3
3
|
const PREEMPTIVE_TOKEN_EXPIRY_SECONDS = 60
|
|
4
4
|
|
|
@@ -21,14 +21,16 @@ export function config () {
|
|
|
21
21
|
|
|
22
22
|
let accessToken = null
|
|
23
23
|
return {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
serverUrl: process.env.DYNAMICS_API_PATH,
|
|
25
|
+
dataApi: {
|
|
26
|
+
version: process.env.DYNAMICS_API_VERSION
|
|
27
|
+
},
|
|
26
28
|
timeout: process.env.DYNAMICS_API_TIMEOUT || 90000,
|
|
27
|
-
onTokenRefresh: async
|
|
29
|
+
onTokenRefresh: async () => {
|
|
28
30
|
if (!accessToken || accessToken.expired(PREEMPTIVE_TOKEN_EXPIRY_SECONDS)) {
|
|
29
31
|
accessToken = await oauthClient.getToken({ scope: process.env.OAUTH_SCOPE })
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
return accessToken.token.access_token
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -13,9 +13,9 @@ export async function persist (entities, createdBy) {
|
|
|
13
13
|
dynamicsClient.startBatch()
|
|
14
14
|
entities.forEach(entity => {
|
|
15
15
|
if (entity.isNew()) {
|
|
16
|
-
dynamicsClient.
|
|
16
|
+
dynamicsClient.create(entity.toPersistRequest())
|
|
17
17
|
} else {
|
|
18
|
-
dynamicsClient.
|
|
18
|
+
dynamicsClient.update(entity.toPersistRequest())
|
|
19
19
|
}
|
|
20
20
|
})
|
|
21
21
|
return await dynamicsClient.executeBatch({
|
|
@@ -23,7 +23,7 @@ export async function persist (entities, createdBy) {
|
|
|
23
23
|
})
|
|
24
24
|
} catch (e) {
|
|
25
25
|
const error = e.length ? e[0] : e
|
|
26
|
-
const requestDetails = entities.map(entity => ({ [entity.isNew() ? '
|
|
26
|
+
const requestDetails = entities.map(entity => ({ [entity.isNew() ? 'create' : 'update']: entity.toPersistRequest() }))
|
|
27
27
|
console.error('Error persisting batch. Data: %j, Exception: %o', requestDetails, error)
|
|
28
28
|
throw error
|
|
29
29
|
}
|
|
@@ -32,7 +32,7 @@ export async function persist (entities, createdBy) {
|
|
|
32
32
|
const retrieveMultipleFetchOperation = async entityClasses => {
|
|
33
33
|
try {
|
|
34
34
|
dynamicsClient.startBatch()
|
|
35
|
-
entityClasses.forEach(cls => dynamicsClient.
|
|
35
|
+
entityClasses.forEach(cls => dynamicsClient.retrieveMultiple(cls.definition.toRetrieveRequest()))
|
|
36
36
|
return await dynamicsClient.executeBatch()
|
|
37
37
|
} catch (e) {
|
|
38
38
|
const error = e.length ? e[0] : e
|
|
@@ -97,7 +97,10 @@ export function retrieveGlobalOptionSets () {
|
|
|
97
97
|
'dynamics_optionsetmap',
|
|
98
98
|
async () => {
|
|
99
99
|
try {
|
|
100
|
-
const data = await dynamicsClient.retrieveGlobalOptionSets(
|
|
100
|
+
const data = await dynamicsClient.retrieveGlobalOptionSets({
|
|
101
|
+
castType: 'Microsoft.Dynamics.CRM.OptionSetMetadata',
|
|
102
|
+
select: ['Name', 'Options']
|
|
103
|
+
})
|
|
101
104
|
return data.value.reduce((acc, { Name: name, Options: options }) => {
|
|
102
105
|
acc[name] = {
|
|
103
106
|
name,
|
|
@@ -131,7 +134,7 @@ export function retrieveGlobalOptionSets () {
|
|
|
131
134
|
*/
|
|
132
135
|
export async function findById (entityType, key) {
|
|
133
136
|
try {
|
|
134
|
-
const record = await dynamicsClient.
|
|
137
|
+
const record = await dynamicsClient.retrieve({ key: key, ...entityType.definition.toRetrieveRequest(null) })
|
|
135
138
|
const optionSetData = await retrieveGlobalOptionSets().cached()
|
|
136
139
|
return entityType.fromResponse(record, optionSetData)
|
|
137
140
|
} catch (e) {
|
|
@@ -179,7 +182,7 @@ export async function findByExample (entity) {
|
|
|
179
182
|
return acc
|
|
180
183
|
}, [])
|
|
181
184
|
].join(' and ')
|
|
182
|
-
const results = await dynamicsClient.
|
|
185
|
+
const results = await dynamicsClient.retrieveMultiple(entity.constructor.definition.toRetrieveRequest(filter))
|
|
183
186
|
const optionSetData = await retrieveGlobalOptionSets().cached()
|
|
184
187
|
return results.value.map(result => entity.constructor.fromResponse(result, optionSetData))
|
|
185
188
|
} catch (e) {
|
|
@@ -198,7 +201,7 @@ export async function findByExample (entity) {
|
|
|
198
201
|
*/
|
|
199
202
|
export async function executeQuery (query) {
|
|
200
203
|
try {
|
|
201
|
-
const response = await dynamicsClient.
|
|
204
|
+
const response = await dynamicsClient.retrieveMultiple(query.toRetrieveRequest())
|
|
202
205
|
const optionSetData = await retrieveGlobalOptionSets().cached()
|
|
203
206
|
return query.fromResponse(response.value, optionSetData)
|
|
204
207
|
} catch (e) {
|
|
@@ -225,7 +228,7 @@ export async function executePagedQuery (query, onPageReceived, maxPages) {
|
|
|
225
228
|
const optionSetData = await retrieveGlobalOptionSets().cached()
|
|
226
229
|
let nextLink = null
|
|
227
230
|
do {
|
|
228
|
-
const response = await dynamicsClient.
|
|
231
|
+
const response = await dynamicsClient.retrieveMultiple(query.toRetrieveRequest(), nextLink)
|
|
229
232
|
nextLink = response.oDataNextLink
|
|
230
233
|
await onPageReceived(query.fromResponse(response.value, optionSetData))
|
|
231
234
|
processed += response.value.length
|
|
@@ -4,11 +4,13 @@ import { Permission } from '../../entities/permission.entity.js'
|
|
|
4
4
|
import { PredefinedQuery } from '../predefined-query.js'
|
|
5
5
|
|
|
6
6
|
jest.mock('dynamics-web-api', () => {
|
|
7
|
-
return
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
return {
|
|
8
|
+
DynamicsWebApi: jest.fn().mockImplementation(() => {
|
|
9
|
+
return {
|
|
10
|
+
callAction: jest.fn()
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
}
|
|
12
14
|
})
|
|
13
15
|
|
|
14
16
|
describe('Contact Queries', () => {
|