@memberjunction/server 2.111.0 → 2.112.0

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.
Files changed (250) hide show
  1. package/dist/agents/skip-agent.d.ts +4 -4
  2. package/dist/agents/skip-agent.d.ts.map +1 -1
  3. package/dist/agents/skip-agent.js +808 -951
  4. package/dist/agents/skip-agent.js.map +1 -1
  5. package/dist/agents/skip-sdk.d.ts +1 -1
  6. package/dist/agents/skip-sdk.d.ts.map +1 -1
  7. package/dist/agents/skip-sdk.js +53 -43
  8. package/dist/agents/skip-sdk.js.map +1 -1
  9. package/dist/apolloServer/index.js +1 -1
  10. package/dist/auth/AuthProviderFactory.d.ts +1 -1
  11. package/dist/auth/AuthProviderFactory.d.ts.map +1 -1
  12. package/dist/auth/AuthProviderFactory.js +1 -3
  13. package/dist/auth/AuthProviderFactory.js.map +1 -1
  14. package/dist/auth/BaseAuthProvider.d.ts +1 -1
  15. package/dist/auth/BaseAuthProvider.d.ts.map +1 -1
  16. package/dist/auth/BaseAuthProvider.js +3 -2
  17. package/dist/auth/BaseAuthProvider.js.map +1 -1
  18. package/dist/auth/IAuthProvider.d.ts +1 -1
  19. package/dist/auth/IAuthProvider.d.ts.map +1 -1
  20. package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -1
  21. package/dist/auth/exampleNewUserSubClass.js +1 -1
  22. package/dist/auth/exampleNewUserSubClass.js.map +1 -1
  23. package/dist/auth/index.d.ts +1 -1
  24. package/dist/auth/index.d.ts.map +1 -1
  25. package/dist/auth/index.js +6 -6
  26. package/dist/auth/index.js.map +1 -1
  27. package/dist/auth/initializeProviders.js +1 -1
  28. package/dist/auth/initializeProviders.js.map +1 -1
  29. package/dist/auth/newUsers.d.ts +1 -1
  30. package/dist/auth/newUsers.d.ts.map +1 -1
  31. package/dist/auth/newUsers.js +7 -7
  32. package/dist/auth/newUsers.js.map +1 -1
  33. package/dist/auth/providers/Auth0Provider.d.ts +1 -1
  34. package/dist/auth/providers/Auth0Provider.d.ts.map +1 -1
  35. package/dist/auth/providers/Auth0Provider.js +1 -1
  36. package/dist/auth/providers/Auth0Provider.js.map +1 -1
  37. package/dist/auth/providers/CognitoProvider.d.ts +1 -1
  38. package/dist/auth/providers/CognitoProvider.d.ts.map +1 -1
  39. package/dist/auth/providers/CognitoProvider.js +3 -6
  40. package/dist/auth/providers/CognitoProvider.js.map +1 -1
  41. package/dist/auth/providers/GoogleProvider.d.ts +1 -1
  42. package/dist/auth/providers/GoogleProvider.d.ts.map +1 -1
  43. package/dist/auth/providers/GoogleProvider.js +1 -1
  44. package/dist/auth/providers/GoogleProvider.js.map +1 -1
  45. package/dist/auth/providers/MSALProvider.d.ts +1 -1
  46. package/dist/auth/providers/MSALProvider.d.ts.map +1 -1
  47. package/dist/auth/providers/MSALProvider.js +1 -1
  48. package/dist/auth/providers/MSALProvider.js.map +1 -1
  49. package/dist/auth/providers/OktaProvider.d.ts +1 -1
  50. package/dist/auth/providers/OktaProvider.d.ts.map +1 -1
  51. package/dist/auth/providers/OktaProvider.js +1 -1
  52. package/dist/auth/providers/OktaProvider.js.map +1 -1
  53. package/dist/config.d.ts.map +1 -1
  54. package/dist/config.js +22 -10
  55. package/dist/config.js.map +1 -1
  56. package/dist/context.d.ts +1 -1
  57. package/dist/context.d.ts.map +1 -1
  58. package/dist/context.js +9 -7
  59. package/dist/context.js.map +1 -1
  60. package/dist/entitySubclasses/entityPermissions.server.d.ts +1 -1
  61. package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -1
  62. package/dist/entitySubclasses/entityPermissions.server.js +1 -1
  63. package/dist/entitySubclasses/entityPermissions.server.js.map +1 -1
  64. package/dist/generated/generated.d.ts +648 -648
  65. package/dist/generated/generated.d.ts.map +1 -1
  66. package/dist/generated/generated.js +2986 -1133
  67. package/dist/generated/generated.js.map +1 -1
  68. package/dist/generic/KeyInputOutputTypes.d.ts +1 -1
  69. package/dist/generic/KeyInputOutputTypes.d.ts.map +1 -1
  70. package/dist/generic/KeyInputOutputTypes.js +1 -1
  71. package/dist/generic/KeyInputOutputTypes.js.map +1 -1
  72. package/dist/generic/ResolverBase.d.ts +1 -1
  73. package/dist/generic/ResolverBase.d.ts.map +1 -1
  74. package/dist/generic/ResolverBase.js +15 -10
  75. package/dist/generic/ResolverBase.js.map +1 -1
  76. package/dist/generic/RunViewResolver.d.ts +1 -1
  77. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  78. package/dist/generic/RunViewResolver.js +15 -15
  79. package/dist/generic/RunViewResolver.js.map +1 -1
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +18 -9
  82. package/dist/index.js.map +1 -1
  83. package/dist/resolvers/ActionResolver.d.ts +2 -2
  84. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  85. package/dist/resolvers/ActionResolver.js +28 -30
  86. package/dist/resolvers/ActionResolver.js.map +1 -1
  87. package/dist/resolvers/AskSkipResolver.d.ts +2 -2
  88. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  89. package/dist/resolvers/AskSkipResolver.js +60 -50
  90. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  91. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  92. package/dist/resolvers/ComponentRegistryResolver.js +36 -38
  93. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  94. package/dist/resolvers/CreateQueryResolver.d.ts +1 -1
  95. package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
  96. package/dist/resolvers/CreateQueryResolver.js +43 -40
  97. package/dist/resolvers/CreateQueryResolver.js.map +1 -1
  98. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  99. package/dist/resolvers/DatasetResolver.js +1 -1
  100. package/dist/resolvers/DatasetResolver.js.map +1 -1
  101. package/dist/resolvers/EntityRecordNameResolver.d.ts +1 -1
  102. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  103. package/dist/resolvers/EntityRecordNameResolver.js +1 -1
  104. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  105. package/dist/resolvers/EntityResolver.d.ts.map +1 -1
  106. package/dist/resolvers/EntityResolver.js +1 -1
  107. package/dist/resolvers/EntityResolver.js.map +1 -1
  108. package/dist/resolvers/FileCategoryResolver.js +1 -1
  109. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  110. package/dist/resolvers/FileResolver.js +1 -1
  111. package/dist/resolvers/FileResolver.js.map +1 -1
  112. package/dist/resolvers/GetDataContextDataResolver.d.ts +1 -1
  113. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  114. package/dist/resolvers/GetDataContextDataResolver.js +5 -5
  115. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  116. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  117. package/dist/resolvers/GetDataResolver.js +8 -6
  118. package/dist/resolvers/GetDataResolver.js.map +1 -1
  119. package/dist/resolvers/MergeRecordsResolver.d.ts +3 -3
  120. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  121. package/dist/resolvers/MergeRecordsResolver.js +3 -3
  122. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  123. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +1 -1
  124. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
  125. package/dist/resolvers/PotentialDuplicateRecordResolver.js +1 -1
  126. package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
  127. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  128. package/dist/resolvers/QueryResolver.js +11 -11
  129. package/dist/resolvers/QueryResolver.js.map +1 -1
  130. package/dist/resolvers/ReportResolver.js +1 -1
  131. package/dist/resolvers/ReportResolver.js.map +1 -1
  132. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  133. package/dist/resolvers/RunAIAgentResolver.js +27 -28
  134. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  135. package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
  136. package/dist/resolvers/RunAIPromptResolver.js +31 -31
  137. package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
  138. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  139. package/dist/resolvers/RunTemplateResolver.js +9 -9
  140. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  141. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  142. package/dist/resolvers/SqlLoggingConfigResolver.js +10 -10
  143. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  144. package/dist/resolvers/SyncDataResolver.d.ts +1 -1
  145. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  146. package/dist/resolvers/SyncDataResolver.js +15 -14
  147. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  148. package/dist/resolvers/SyncRolesUsersResolver.d.ts +1 -1
  149. package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
  150. package/dist/resolvers/SyncRolesUsersResolver.js +48 -44
  151. package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
  152. package/dist/resolvers/TaskResolver.d.ts.map +1 -1
  153. package/dist/resolvers/TaskResolver.js +7 -7
  154. package/dist/resolvers/TaskResolver.js.map +1 -1
  155. package/dist/resolvers/TransactionGroupResolver.d.ts +1 -1
  156. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  157. package/dist/resolvers/TransactionGroupResolver.js +12 -12
  158. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  159. package/dist/resolvers/UserFavoriteResolver.d.ts +1 -1
  160. package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
  161. package/dist/resolvers/UserFavoriteResolver.js +1 -1
  162. package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
  163. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  164. package/dist/resolvers/UserViewResolver.js.map +1 -1
  165. package/dist/rest/EntityCRUDHandler.d.ts +1 -1
  166. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  167. package/dist/rest/EntityCRUDHandler.js +14 -16
  168. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  169. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  170. package/dist/rest/RESTEndpointHandler.js +23 -25
  171. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  172. package/dist/rest/ViewOperationsHandler.d.ts +1 -1
  173. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  174. package/dist/rest/ViewOperationsHandler.js +17 -21
  175. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  176. package/dist/scheduler/LearningCycleScheduler.d.ts.map +1 -1
  177. package/dist/scheduler/LearningCycleScheduler.js.map +1 -1
  178. package/dist/services/ScheduledJobsService.d.ts.map +1 -1
  179. package/dist/services/ScheduledJobsService.js +4 -6
  180. package/dist/services/ScheduledJobsService.js.map +1 -1
  181. package/dist/services/TaskOrchestrator.d.ts +1 -1
  182. package/dist/services/TaskOrchestrator.d.ts.map +1 -1
  183. package/dist/services/TaskOrchestrator.js +30 -30
  184. package/dist/services/TaskOrchestrator.js.map +1 -1
  185. package/dist/types.d.ts +3 -3
  186. package/dist/types.d.ts.map +1 -1
  187. package/dist/types.js +0 -1
  188. package/dist/types.js.map +1 -1
  189. package/dist/util.d.ts +1 -1
  190. package/dist/util.d.ts.map +1 -1
  191. package/dist/util.js +2 -2
  192. package/dist/util.js.map +1 -1
  193. package/package.json +36 -37
  194. package/src/agents/skip-agent.ts +1067 -1200
  195. package/src/agents/skip-sdk.ts +877 -851
  196. package/src/apolloServer/index.ts +2 -2
  197. package/src/auth/AuthProviderFactory.ts +8 -14
  198. package/src/auth/BaseAuthProvider.ts +5 -4
  199. package/src/auth/IAuthProvider.ts +2 -2
  200. package/src/auth/exampleNewUserSubClass.ts +9 -2
  201. package/src/auth/index.ts +31 -26
  202. package/src/auth/initializeProviders.ts +3 -3
  203. package/src/auth/newUsers.ts +166 -134
  204. package/src/auth/providers/Auth0Provider.ts +5 -5
  205. package/src/auth/providers/CognitoProvider.ts +7 -10
  206. package/src/auth/providers/GoogleProvider.ts +4 -5
  207. package/src/auth/providers/MSALProvider.ts +5 -5
  208. package/src/auth/providers/OktaProvider.ts +6 -7
  209. package/src/config.ts +63 -54
  210. package/src/context.ts +42 -30
  211. package/src/entitySubclasses/entityPermissions.server.ts +3 -3
  212. package/src/generated/generated.ts +48130 -39930
  213. package/src/generic/KeyInputOutputTypes.ts +3 -6
  214. package/src/generic/ResolverBase.ts +119 -78
  215. package/src/generic/RunViewResolver.ts +27 -23
  216. package/src/index.ts +66 -42
  217. package/src/resolvers/ActionResolver.ts +46 -57
  218. package/src/resolvers/AskSkipResolver.ts +607 -533
  219. package/src/resolvers/ComponentRegistryResolver.ts +547 -562
  220. package/src/resolvers/CreateQueryResolver.ts +683 -655
  221. package/src/resolvers/DatasetResolver.ts +5 -6
  222. package/src/resolvers/EntityCommunicationsResolver.ts +1 -1
  223. package/src/resolvers/EntityRecordNameResolver.ts +9 -5
  224. package/src/resolvers/EntityResolver.ts +9 -7
  225. package/src/resolvers/FileCategoryResolver.ts +2 -2
  226. package/src/resolvers/FileResolver.ts +4 -4
  227. package/src/resolvers/GetDataContextDataResolver.ts +106 -118
  228. package/src/resolvers/GetDataResolver.ts +194 -205
  229. package/src/resolvers/MergeRecordsResolver.ts +5 -5
  230. package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
  231. package/src/resolvers/QueryResolver.ts +95 -78
  232. package/src/resolvers/ReportResolver.ts +2 -2
  233. package/src/resolvers/RunAIAgentResolver.ts +818 -828
  234. package/src/resolvers/RunAIPromptResolver.ts +693 -709
  235. package/src/resolvers/RunTemplateResolver.ts +105 -103
  236. package/src/resolvers/SqlLoggingConfigResolver.ts +69 -72
  237. package/src/resolvers/SyncDataResolver.ts +386 -352
  238. package/src/resolvers/SyncRolesUsersResolver.ts +387 -350
  239. package/src/resolvers/TaskResolver.ts +110 -115
  240. package/src/resolvers/TransactionGroupResolver.ts +143 -138
  241. package/src/resolvers/UserFavoriteResolver.ts +17 -8
  242. package/src/resolvers/UserViewResolver.ts +17 -12
  243. package/src/rest/EntityCRUDHandler.ts +291 -268
  244. package/src/rest/RESTEndpointHandler.ts +782 -776
  245. package/src/rest/ViewOperationsHandler.ts +191 -195
  246. package/src/scheduler/LearningCycleScheduler.ts +8 -52
  247. package/src/services/ScheduledJobsService.ts +129 -132
  248. package/src/services/TaskOrchestrator.ts +792 -776
  249. package/src/types.ts +15 -9
  250. package/src/util.ts +112 -109
@@ -1,90 +1,95 @@
1
1
  import { Arg, Ctx, Field, InputType, Mutation, ObjectType, registerEnumType } from 'type-graphql';
2
2
  import { AppContext, UserPayload } from '../types.js';
3
- import { BaseEntity, CompositeKey, EntityDeleteOptions, EntitySaveOptions, LogError, Metadata, RunView, UserInfo } from '@memberjunction/core';
3
+ import {
4
+ BaseEntity,
5
+ CompositeKey,
6
+ EntityDeleteOptions,
7
+ EntitySaveOptions,
8
+ LogError,
9
+ Metadata,
10
+ RunView,
11
+ UserInfo,
12
+ } from '@memberjunction/global';
4
13
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
5
14
  import { CompositeKeyInputType, CompositeKeyOutputType } from '../generic/KeyInputOutputTypes.js';
6
15
  import { DatasetItemEntity } from '@memberjunction/core-entities';
7
16
 
8
-
9
-
10
17
  /**
11
18
  * This type defines the possible list of actions that can be taken in syncing data: Create, Update, CreateOrUpdate, Delete, or DeleteWithFilter
12
19
  * DeleteWithFilter is where you specify a valid SQL expression that can be used in a where clause to get a list of records in a given entity to delete
13
20
  * this can be used to ensure cleaning out data from a subset of a given table.
14
21
  */
15
22
  export enum SyncDataActionType {
16
- Create = "Create",
17
- Update = "Update",
18
- CreateOrUpdate = "CreateOrUpdate",
19
- Delete = "Delete",
20
- DeleteWithFilter = "DeleteWithFilter"
21
- }
22
-
23
- registerEnumType(SyncDataActionType, {
24
- name: "SyncDataActionType", // GraphQL Enum Name
25
- description: "Specifies the type of action to be taken in syncing, Create, Update, CreateOrUpdate, Delete" // Description,
26
- });
27
-
28
-
29
- @InputType()
30
- export class ActionItemInputType {
31
- @Field(() => String)
32
- EntityName!: string;
33
-
34
- @Field(() => CompositeKeyInputType, {nullable: true})
35
- PrimaryKey?: CompositeKeyInputType;
36
-
37
- @Field(() => CompositeKeyInputType, {nullable: true})
38
- AlternateKey?: CompositeKeyInputType;
39
-
40
- @Field(() => SyncDataActionType)
41
- Type!: SyncDataActionType;
42
-
43
- /**
44
- * This field is a JSON representation of the field values of the entity to be created or updated. It is used for all ActionTypes except for
45
- */
46
- @Field(() => String, {nullable: true})
47
- RecordJSON?: string;
48
-
49
- /**
50
- * This field is only provided when the Action Type is DeleteWithFilter. It is a valid SQL expression that can be used in a where clause to get a list of records in a given entity to delete
51
- */
52
- @Field(() => String, {nullable: true})
53
- DeleteFilter?: string;
54
- }
55
-
56
-
23
+ Create = 'Create',
24
+ Update = 'Update',
25
+ CreateOrUpdate = 'CreateOrUpdate',
26
+ Delete = 'Delete',
27
+ DeleteWithFilter = 'DeleteWithFilter',
28
+ }
29
+
30
+ registerEnumType(SyncDataActionType, {
31
+ name: 'SyncDataActionType', // GraphQL Enum Name
32
+ description: 'Specifies the type of action to be taken in syncing, Create, Update, CreateOrUpdate, Delete', // Description,
33
+ });
34
+
35
+ @InputType()
36
+ export class ActionItemInputType {
37
+ @Field(() => String)
38
+ EntityName!: string;
39
+
40
+ @Field(() => CompositeKeyInputType, { nullable: true })
41
+ PrimaryKey?: CompositeKeyInputType;
42
+
43
+ @Field(() => CompositeKeyInputType, { nullable: true })
44
+ AlternateKey?: CompositeKeyInputType;
45
+
46
+ @Field(() => SyncDataActionType)
47
+ Type!: SyncDataActionType;
48
+
49
+ /**
50
+ * This field is a JSON representation of the field values of the entity to be created or updated. It is used for all ActionTypes except for
51
+ */
52
+ @Field(() => String, { nullable: true })
53
+ RecordJSON?: string;
54
+
55
+ /**
56
+ * This field is only provided when the Action Type is DeleteWithFilter. It is a valid SQL expression that can be used in a where clause to get a list of records in a given entity to delete
57
+ */
58
+ @Field(() => String, { nullable: true })
59
+ DeleteFilter?: string;
60
+ }
61
+
57
62
  @ObjectType()
58
63
  export class ActionItemOutputType {
59
- @Field(() => Boolean)
60
- Success: boolean;
64
+ @Field(() => Boolean)
65
+ Success: boolean;
61
66
 
62
- @Field(() => String)
63
- ErrorMessage: string;
67
+ @Field(() => String)
68
+ ErrorMessage: string;
64
69
 
65
- @Field(() => String)
66
- EntityName!: string;
70
+ @Field(() => String)
71
+ EntityName!: string;
67
72
 
68
- @Field(() => CompositeKeyOutputType, {nullable: true})
69
- PrimaryKey?: CompositeKeyOutputType;
73
+ @Field(() => CompositeKeyOutputType, { nullable: true })
74
+ PrimaryKey?: CompositeKeyOutputType;
70
75
 
71
- @Field(() => CompositeKeyOutputType, {nullable: true})
72
- AlternateKey?: CompositeKeyOutputType;
76
+ @Field(() => CompositeKeyOutputType, { nullable: true })
77
+ AlternateKey?: CompositeKeyOutputType;
73
78
 
74
- @Field(() => SyncDataActionType)
75
- Type!: SyncDataActionType;
79
+ @Field(() => SyncDataActionType)
80
+ Type!: SyncDataActionType;
76
81
 
77
- /**
78
- * This field is a JSON representation of the field values of the entity to be created or updated. It is used for all ActionTypes except for
79
- */
80
- @Field(() => String, {nullable: true})
81
- RecordJSON?: string;
82
+ /**
83
+ * This field is a JSON representation of the field values of the entity to be created or updated. It is used for all ActionTypes except for
84
+ */
85
+ @Field(() => String, { nullable: true })
86
+ RecordJSON?: string;
82
87
 
83
- /**
84
- * This field is only provided when the Action Type is DeleteWithFilter. It is a valid SQL expression that can be used in a where clause to get a list of records in a given entity to delete
85
- */
86
- @Field(() => String, {nullable: true})
87
- DeleteFilter?: string;
88
+ /**
89
+ * This field is only provided when the Action Type is DeleteWithFilter. It is a valid SQL expression that can be used in a where clause to get a list of records in a given entity to delete
90
+ */
91
+ @Field(() => String, { nullable: true })
92
+ DeleteFilter?: string;
88
93
  }
89
94
 
90
95
  @ObjectType()
@@ -96,318 +101,347 @@ export class SyncDataResultType {
96
101
  Results: ActionItemOutputType[] = [];
97
102
  }
98
103
 
99
-
100
104
  const __metadata_DatasetItems: string[] = [];
101
105
 
102
106
  export class SyncDataResolver {
103
- /**
104
- * This mutation will sync the specified items with the existing system. Items will be processed in order and the results of each operation will be returned in the Results array within the return value.
105
- * @param items - an array of ActionItemInputType objects that specify the action to be taken on the specified entity with the specified primary key and the JSON representation of the field values.
106
- */
107
- @RequireSystemUser()
108
- @Mutation(() => SyncDataResultType)
109
- async SyncData(
110
- @Arg('items', () => [ActionItemInputType] ) items: ActionItemInputType[],
111
- @Ctx() context: AppContext
112
- ) {
113
- try {
114
- // iterate through the items
115
- const md = new Metadata();
116
- const results: ActionItemOutputType[] = [];
117
- for (const item of items) {
118
- results.push(await this.SyncSingleItem(item, context, md, context.userPayload));
119
- }
120
-
121
- if (await this.DoSyncItemsAffectMetadata(context.userPayload.userRecord, items)) {
122
- await md.Refresh(); // force refesh the metadata which will cause a reload from the DB
123
- }
124
-
125
- const overallSuccess = !results.some((r) => !r.Success); // if any element in the array of results has a Success value of false, then the overall success is false
126
- return { Success: overallSuccess, Results: results };
127
- }
128
- catch (err) {
129
- LogError(err);
130
- throw new Error('SyncDataResolver::SyncData --- Error Syncing Data\n\n' + err);
131
- }
132
- }
107
+ /**
108
+ * This mutation will sync the specified items with the existing system. Items will be processed in order and the results of each operation will be returned in the Results array within the return value.
109
+ * @param items - an array of ActionItemInputType objects that specify the action to be taken on the specified entity with the specified primary key and the JSON representation of the field values.
110
+ */
111
+ @RequireSystemUser()
112
+ @Mutation(() => SyncDataResultType)
113
+ async SyncData(@Arg('items', () => [ActionItemInputType]) items: ActionItemInputType[], @Ctx() context: AppContext) {
114
+ try {
115
+ // iterate through the items
116
+ const md = new Metadata();
117
+ const results: ActionItemOutputType[] = [];
118
+ for (const item of items) {
119
+ results.push(await this.SyncSingleItem(item, context, md, context.userPayload));
120
+ }
133
121
 
134
- protected async GetLowercaseMetadataEntitiesList(user: UserInfo, forceRefresh: boolean = false): Promise<string[]> {
135
- if (forceRefresh || __metadata_DatasetItems.length === 0) {
136
- const rv = new RunView(); // cache this, veyr simple - should use an engine for this stuff later
137
- const result = await rv.RunView<DatasetItemEntity>({
138
- EntityName: "Dataset Items",
139
- ExtraFilter: "Dataset = 'MJ_Metadata'",
140
- }, user)
141
- if (result && result.Success) {
142
- __metadata_DatasetItems.length = 0;
143
- __metadata_DatasetItems.push(...result.Results.map((r) => {
144
- return r.Entity.trim().toLowerCase();
145
- }));
146
- }
147
- }
148
- // now return the list of entities
149
- return __metadata_DatasetItems;
150
- }
122
+ if (await this.DoSyncItemsAffectMetadata(context.userPayload.userRecord, items)) {
123
+ await md.Refresh(); // force refesh the metadata which will cause a reload from the DB
124
+ }
151
125
 
152
- protected async DoSyncItemsAffectMetadata(user: UserInfo, items: ActionItemInputType[]): Promise<boolean> {
153
- // check to see if any of the items affect any of these entities:
154
- const entitiesToCheck = await this.GetLowercaseMetadataEntitiesList(user, false);
155
- for (const item of items) {
156
- if (entitiesToCheck.find(e => e === item.EntityName.trim().toLowerCase()) ) {
157
- return true;
158
- }
159
- }
160
- return false; // didn't find any
126
+ const overallSuccess = !results.some((r) => !r.Success); // if any element in the array of results has a Success value of false, then the overall success is false
127
+ return { Success: overallSuccess, Results: results };
128
+ } catch (err) {
129
+ LogError(err);
130
+ throw new Error('SyncDataResolver::SyncData --- Error Syncing Data\n\n' + err);
161
131
  }
132
+ }
162
133
 
163
- protected async SyncSingleItem(item: ActionItemInputType, context: AppContext, md: Metadata, userPayload: UserPayload): Promise<ActionItemOutputType> {
164
- const result = new ActionItemOutputType();
165
- result.AlternateKey = item.AlternateKey;
166
- result.PrimaryKey = item.PrimaryKey;
167
- result.DeleteFilter = item.DeleteFilter;
168
- result.EntityName = item.EntityName;
169
- result.RecordJSON = item.RecordJSON;
170
- result.Type = item.Type;
171
- result.Success = false;
172
- result.ErrorMessage = '';
173
- try {
174
- const e = md.Entities.find((e) => e.Name === item.EntityName);
175
- if (e) {
176
- const pk = item.PrimaryKey ? new CompositeKey(item.PrimaryKey.KeyValuePairs) : null;
177
- const ak = item.AlternateKey ? new CompositeKey(item.AlternateKey.KeyValuePairs) : null;
178
- const entityObject = item.Type === SyncDataActionType.DeleteWithFilter ? null : await md.GetEntityObject(e.Name, context.userPayload.userRecord);
179
- const fieldValues = item.RecordJSON ? JSON.parse(item.RecordJSON) : {};
180
- switch (item.Type) {
181
- case SyncDataActionType.Create:
182
- await this.SyncSingleItemCreate(entityObject, fieldValues, result, userPayload);
183
- break;
184
- case SyncDataActionType.Update:
185
- await this.SyncSingleItemUpdate(entityObject, pk, ak, fieldValues, result, userPayload);
186
- break;
187
- case SyncDataActionType.CreateOrUpdate:
188
- // in this case we attempt to load the item first, if it is not possible to load the item, then we create it
189
- await this.SyncSingleItemCreateOrUpdate(entityObject, pk, ak, fieldValues, result, userPayload);
190
- break;
191
- case SyncDataActionType.Delete:
192
- await this.SyncSingleItemDelete(entityObject, pk, ak, result, userPayload);
193
- break;
194
- case SyncDataActionType.DeleteWithFilter:
195
- await this.SyncSingleItemDeleteWithFilter(item.EntityName, item.DeleteFilter, result, context.userPayload.userRecord, userPayload);
196
- break;
197
- default:
198
- throw new Error('Invalid SyncDataActionType');
199
- }
200
- } else {
201
- throw new Error('Entity not found');
202
- }
203
- }
204
- catch (err) {
205
- result.ErrorMessage = typeof err === 'string' ? err : (err as any).message;
206
- LogError(err);
207
- }
208
- finally {
209
- return result;
210
- }
134
+ protected async GetLowercaseMetadataEntitiesList(user: UserInfo, forceRefresh: boolean = false): Promise<string[]> {
135
+ if (forceRefresh || __metadata_DatasetItems.length === 0) {
136
+ const rv = new RunView(); // cache this, veyr simple - should use an engine for this stuff later
137
+ const result = await rv.RunView<DatasetItemEntity>(
138
+ {
139
+ EntityName: 'Dataset Items',
140
+ ExtraFilter: "Dataset = 'MJ_Metadata'",
141
+ },
142
+ user
143
+ );
144
+ if (result && result.Success) {
145
+ __metadata_DatasetItems.length = 0;
146
+ __metadata_DatasetItems.push(
147
+ ...result.Results.map((r) => {
148
+ return r.Entity.trim().toLowerCase();
149
+ })
150
+ );
151
+ }
211
152
  }
153
+ // now return the list of entities
154
+ return __metadata_DatasetItems;
155
+ }
212
156
 
157
+ protected async DoSyncItemsAffectMetadata(user: UserInfo, items: ActionItemInputType[]): Promise<boolean> {
158
+ // check to see if any of the items affect any of these entities:
159
+ const entitiesToCheck = await this.GetLowercaseMetadataEntitiesList(user, false);
160
+ for (const item of items) {
161
+ if (entitiesToCheck.find((e) => e === item.EntityName.trim().toLowerCase())) {
162
+ return true;
163
+ }
164
+ }
165
+ return false; // didn't find any
166
+ }
213
167
 
214
- protected async SyncSingleItemDeleteWithFilter(entityName: string, filter: string, result: ActionItemOutputType, user: UserInfo, userPayload: UserPayload) {
215
- try {
216
- // here we will iterate through the result of a RunView on the entityname/filter and delete each matching record
217
- let overallSuccess: boolean = true;
218
- let combinedErrorMessage: string = "";
219
- const rv = new RunView();
220
- const data = await rv.RunView<BaseEntity>({
221
- EntityName: entityName,
222
- ExtraFilter: filter,
223
- ResultType: 'entity_object'
224
- }, user);
225
- if (data && data.Success) {
226
- for (const entityObject of data.Results) {
227
- if (!await entityObject.Delete()) {
228
- overallSuccess = false;
229
- combinedErrorMessage += 'Failed to delete the item :' + entityObject.LatestResult.Message + '\n';
230
- }
231
- }
232
- result.Success = overallSuccess
233
- if (!overallSuccess) {
234
- result.ErrorMessage = combinedErrorMessage
235
- }
236
- }
237
- else {
238
- result.Success = false;
239
- result.ErrorMessage = 'Failed to run the view to get the list of items to delete for entity: ' + entityName + ' with filter: ' + filter + '\n';
240
- }
241
- }
242
- catch (e) {
243
- result.ErrorMessage = typeof e === 'string' ? e : (e as any).message;
168
+ protected async SyncSingleItem(
169
+ item: ActionItemInputType,
170
+ context: AppContext,
171
+ md: Metadata,
172
+ userPayload: UserPayload
173
+ ): Promise<ActionItemOutputType> {
174
+ const result = new ActionItemOutputType();
175
+ result.AlternateKey = item.AlternateKey;
176
+ result.PrimaryKey = item.PrimaryKey;
177
+ result.DeleteFilter = item.DeleteFilter;
178
+ result.EntityName = item.EntityName;
179
+ result.RecordJSON = item.RecordJSON;
180
+ result.Type = item.Type;
181
+ result.Success = false;
182
+ result.ErrorMessage = '';
183
+ try {
184
+ const e = md.Entities.find((e) => e.Name === item.EntityName);
185
+ if (e) {
186
+ const pk = item.PrimaryKey ? new CompositeKey(item.PrimaryKey.KeyValuePairs) : null;
187
+ const ak = item.AlternateKey ? new CompositeKey(item.AlternateKey.KeyValuePairs) : null;
188
+ const entityObject =
189
+ item.Type === SyncDataActionType.DeleteWithFilter ? null : await md.GetEntityObject(e.Name, context.userPayload.userRecord);
190
+ const fieldValues = item.RecordJSON ? JSON.parse(item.RecordJSON) : {};
191
+ switch (item.Type) {
192
+ case SyncDataActionType.Create:
193
+ await this.SyncSingleItemCreate(entityObject, fieldValues, result, userPayload);
194
+ break;
195
+ case SyncDataActionType.Update:
196
+ await this.SyncSingleItemUpdate(entityObject, pk, ak, fieldValues, result, userPayload);
197
+ break;
198
+ case SyncDataActionType.CreateOrUpdate:
199
+ // in this case we attempt to load the item first, if it is not possible to load the item, then we create it
200
+ await this.SyncSingleItemCreateOrUpdate(entityObject, pk, ak, fieldValues, result, userPayload);
201
+ break;
202
+ case SyncDataActionType.Delete:
203
+ await this.SyncSingleItemDelete(entityObject, pk, ak, result, userPayload);
204
+ break;
205
+ case SyncDataActionType.DeleteWithFilter:
206
+ await this.SyncSingleItemDeleteWithFilter(
207
+ item.EntityName,
208
+ item.DeleteFilter,
209
+ result,
210
+ context.userPayload.userRecord,
211
+ userPayload
212
+ );
213
+ break;
214
+ default:
215
+ throw new Error('Invalid SyncDataActionType');
244
216
  }
217
+ } else {
218
+ throw new Error('Entity not found');
219
+ }
220
+ } catch (err) {
221
+ result.ErrorMessage = typeof err === 'string' ? err : (err as any).message;
222
+ LogError(err);
223
+ } finally {
224
+ return result;
245
225
  }
226
+ }
246
227
 
247
- protected async LoadFromAlternateKey(entityName: string, alternateKey: CompositeKey, user: UserInfo): Promise<BaseEntity> {
248
- try {
249
- // no primary key provided, attempt to look up the primary key based on the
250
- const rv = new RunView();
251
- const md = new Metadata();
252
- const entity = md.EntityByName(entityName);
253
- const r = await rv.RunView<BaseEntity>({
254
- EntityName: entityName,
255
- ExtraFilter: alternateKey.KeyValuePairs.map((kvp) => {
256
- const fieldInfo = entity.Fields.find((f) => f.Name === kvp.FieldName);
257
- const quotes = fieldInfo.NeedsQuotes ? "'" : '';
258
- return `${kvp.FieldName} = ${quotes}${kvp.Value}${quotes}`;
259
- }).join(' AND '),
260
- ResultType: 'entity_object'
261
- }, user);
262
- if (r && r.Success && r.Results.length === 1) {
263
- return r.Results[0];
264
- }
265
- else {
266
- //LogError (`Failed to load the item with alternate key: ${alternateKey.KeyValuePairs.map((kvp) => `${kvp.FieldName} = ${kvp.Value}`).join(' AND ')}. Result: ${r.Success} and ${r.Results?.length} items returned`);
267
- return null;
268
- }
228
+ protected async SyncSingleItemDeleteWithFilter(
229
+ entityName: string,
230
+ filter: string,
231
+ result: ActionItemOutputType,
232
+ user: UserInfo,
233
+ userPayload: UserPayload
234
+ ) {
235
+ try {
236
+ // here we will iterate through the result of a RunView on the entityname/filter and delete each matching record
237
+ let overallSuccess: boolean = true;
238
+ let combinedErrorMessage: string = '';
239
+ const rv = new RunView();
240
+ const data = await rv.RunView<BaseEntity>(
241
+ {
242
+ EntityName: entityName,
243
+ ExtraFilter: filter,
244
+ ResultType: 'entity_object',
245
+ },
246
+ user
247
+ );
248
+ if (data && data.Success) {
249
+ for (const entityObject of data.Results) {
250
+ if (!(await entityObject.Delete())) {
251
+ overallSuccess = false;
252
+ combinedErrorMessage += 'Failed to delete the item :' + entityObject.LatestResult.Message + '\n';
253
+ }
269
254
  }
270
- catch (e) {
271
- LogError(e);
272
- return null;
255
+ result.Success = overallSuccess;
256
+ if (!overallSuccess) {
257
+ result.ErrorMessage = combinedErrorMessage;
273
258
  }
259
+ } else {
260
+ result.Success = false;
261
+ result.ErrorMessage =
262
+ 'Failed to run the view to get the list of items to delete for entity: ' + entityName + ' with filter: ' + filter + '\n';
263
+ }
264
+ } catch (e) {
265
+ result.ErrorMessage = typeof e === 'string' ? e : (e as any).message;
274
266
  }
267
+ }
275
268
 
276
- protected async SyncSingleItemCreateOrUpdate(entityObject: BaseEntity, pk: CompositeKey, ak: CompositeKey, fieldValues: any, result: ActionItemOutputType, userPayload: UserPayload) {
277
- if (!pk || pk.KeyValuePairs.length === 0) {
278
- // no primary key try to load from alt key
279
- const altKeyResult = await this.LoadFromAlternateKey(entityObject.EntityInfo.Name, ak, entityObject.ContextCurrentUser);
280
- if (!altKeyResult) {
281
- // no record found, create a new one
282
- await this.SyncSingleItemCreate(entityObject, fieldValues, result, userPayload);
283
- }
284
- else {
285
- await this.InnerSyncSingleItemUpdate(altKeyResult, fieldValues, result, userPayload);
286
- }
287
- }
288
- else {
289
- // have a primary key do the usual load
290
- if (await entityObject.InnerLoad(pk)) {
291
- await this.InnerSyncSingleItemUpdate(entityObject, fieldValues, result, userPayload);
292
- }
293
- else {
294
- await this.SyncSingleItemCreate(entityObject, fieldValues, result, userPayload);
295
- }
296
- }
269
+ protected async LoadFromAlternateKey(entityName: string, alternateKey: CompositeKey, user: UserInfo): Promise<BaseEntity> {
270
+ try {
271
+ // no primary key provided, attempt to look up the primary key based on the
272
+ const rv = new RunView();
273
+ const md = new Metadata();
274
+ const entity = md.EntityByName(entityName);
275
+ const r = await rv.RunView<BaseEntity>(
276
+ {
277
+ EntityName: entityName,
278
+ ExtraFilter: alternateKey.KeyValuePairs.map((kvp) => {
279
+ const fieldInfo = entity.Fields.find((f) => f.Name === kvp.FieldName);
280
+ const quotes = fieldInfo.NeedsQuotes ? "'" : '';
281
+ return `${kvp.FieldName} = ${quotes}${kvp.Value}${quotes}`;
282
+ }).join(' AND '),
283
+ ResultType: 'entity_object',
284
+ },
285
+ user
286
+ );
287
+ if (r && r.Success && r.Results.length === 1) {
288
+ return r.Results[0];
289
+ } else {
290
+ //LogError (`Failed to load the item with alternate key: ${alternateKey.KeyValuePairs.map((kvp) => `${kvp.FieldName} = ${kvp.Value}`).join(' AND ')}. Result: ${r.Success} and ${r.Results?.length} items returned`);
291
+ return null;
292
+ }
293
+ } catch (e) {
294
+ LogError(e);
295
+ return null;
297
296
  }
297
+ }
298
298
 
299
- protected async SyncSingleItemDelete(entityObject: BaseEntity, pk: CompositeKey, ak: CompositeKey, result: ActionItemOutputType, userPayload: UserPayload) {
300
- if (!pk || pk.KeyValuePairs.length === 0) {
301
- const altKeyResult = await this.LoadFromAlternateKey(entityObject.EntityInfo.Name, ak, entityObject.ContextCurrentUser);
302
- if (!altKeyResult) {
303
- result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified primary key does not exist';
304
- }
305
- else {
306
- // pass back the full record as it was JUST BEFORE the delete, often quite useful on the other end
307
- result.RecordJSON = await altKeyResult.GetDataObjectJSON({
308
- includeRelatedEntityData: false,
309
- excludeFields: [],
310
- omitEmptyStrings: false,
311
- relatedEntityList: [],
312
- omitNullValues: false,
313
- oldValues: false
314
- });
315
- if (await altKeyResult.Delete()) {
316
- result.Success = true;
317
- }
318
- else {
319
- result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.Message;
320
- }
321
- }
322
- }
323
- else if (await entityObject.InnerLoad(pk)) {
324
- // pass back the full record as it was JUST BEFORE the delete, often quite useful on the other end
325
- result.RecordJSON = await entityObject.GetDataObjectJSON({
326
- includeRelatedEntityData: false,
327
- excludeFields: [],
328
- omitEmptyStrings: false,
329
- relatedEntityList: [],
330
- omitNullValues: false,
331
- oldValues: false
332
- });
333
- if (await entityObject.Delete()) {
334
- result.Success = true;
335
- }
336
- else {
337
- result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.Message;
338
- }
339
- }
340
- else {
341
- result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified primary key does not exist';
342
- }
299
+ protected async SyncSingleItemCreateOrUpdate(
300
+ entityObject: BaseEntity,
301
+ pk: CompositeKey,
302
+ ak: CompositeKey,
303
+ fieldValues: any,
304
+ result: ActionItemOutputType,
305
+ userPayload: UserPayload
306
+ ) {
307
+ if (!pk || pk.KeyValuePairs.length === 0) {
308
+ // no primary key try to load from alt key
309
+ const altKeyResult = await this.LoadFromAlternateKey(entityObject.EntityInfo.Name, ak, entityObject.ContextCurrentUser);
310
+ if (!altKeyResult) {
311
+ // no record found, create a new one
312
+ await this.SyncSingleItemCreate(entityObject, fieldValues, result, userPayload);
313
+ } else {
314
+ await this.InnerSyncSingleItemUpdate(altKeyResult, fieldValues, result, userPayload);
315
+ }
316
+ } else {
317
+ // have a primary key do the usual load
318
+ if (await entityObject.InnerLoad(pk)) {
319
+ await this.InnerSyncSingleItemUpdate(entityObject, fieldValues, result, userPayload);
320
+ } else {
321
+ await this.SyncSingleItemCreate(entityObject, fieldValues, result, userPayload);
322
+ }
343
323
  }
324
+ }
344
325
 
345
- protected async SyncSingleItemCreate(entityObject: BaseEntity, fieldValues: any, result: ActionItemOutputType, userPayload: UserPayload) {
346
- // make sure we strip out the primary key from fieldValues before we pass it in because otherwise it will appear to be an existing record to the BaseEntity
347
- const noPKValues = {...fieldValues};
348
- entityObject.EntityInfo.PrimaryKeys.forEach((pk) => {
349
- delete noPKValues[pk.Name];
326
+ protected async SyncSingleItemDelete(
327
+ entityObject: BaseEntity,
328
+ pk: CompositeKey,
329
+ ak: CompositeKey,
330
+ result: ActionItemOutputType,
331
+ userPayload: UserPayload
332
+ ) {
333
+ if (!pk || pk.KeyValuePairs.length === 0) {
334
+ const altKeyResult = await this.LoadFromAlternateKey(entityObject.EntityInfo.Name, ak, entityObject.ContextCurrentUser);
335
+ if (!altKeyResult) {
336
+ result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified primary key does not exist';
337
+ } else {
338
+ // pass back the full record as it was JUST BEFORE the delete, often quite useful on the other end
339
+ result.RecordJSON = await altKeyResult.GetDataObjectJSON({
340
+ includeRelatedEntityData: false,
341
+ excludeFields: [],
342
+ omitEmptyStrings: false,
343
+ relatedEntityList: [],
344
+ omitNullValues: false,
345
+ oldValues: false,
350
346
  });
351
- entityObject.SetMany(noPKValues);
352
- if (await entityObject.Save()) {
353
- result.Success = true;
354
- result.PrimaryKey = new CompositeKey(entityObject.PrimaryKeys.map((pk) => ({FieldName: pk.Name, Value: pk.Value})));
355
- // pass back the full record AFTER the sync, that's often quite useful on the other end
356
- result.RecordJSON = await entityObject.GetDataObjectJSON({
357
- includeRelatedEntityData: false,
358
- excludeFields: [],
359
- omitEmptyStrings: false,
360
- relatedEntityList: [],
361
- omitNullValues: false,
362
- oldValues: false
363
- });
364
- }
365
- else {
366
- result.ErrorMessage = 'Failed to create the item :' + entityObject.LatestResult.Message;
347
+ if (await altKeyResult.Delete()) {
348
+ result.Success = true;
349
+ } else {
350
+ result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.Message;
367
351
  }
352
+ }
353
+ } else if (await entityObject.InnerLoad(pk)) {
354
+ // pass back the full record as it was JUST BEFORE the delete, often quite useful on the other end
355
+ result.RecordJSON = await entityObject.GetDataObjectJSON({
356
+ includeRelatedEntityData: false,
357
+ excludeFields: [],
358
+ omitEmptyStrings: false,
359
+ relatedEntityList: [],
360
+ omitNullValues: false,
361
+ oldValues: false,
362
+ });
363
+ if (await entityObject.Delete()) {
364
+ result.Success = true;
365
+ } else {
366
+ result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.Message;
367
+ }
368
+ } else {
369
+ result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified primary key does not exist';
368
370
  }
371
+ }
369
372
 
370
- protected async SyncSingleItemUpdate(entityObject: BaseEntity, pk: CompositeKey, ak: CompositeKey, fieldValues: any, result: ActionItemOutputType, userPayload: UserPayload) {
371
- if (!pk || pk.KeyValuePairs.length === 0) {
372
- // no pk, attempt to load by alt key
373
- const altKeyResult = await this.LoadFromAlternateKey(entityObject.EntityInfo.Name, ak, entityObject.ContextCurrentUser);
374
- if (!altKeyResult) {
375
- // no record found, create a new one
376
- result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified alternate key does not exist';
377
- }
378
- else {
379
- await this.InnerSyncSingleItemUpdate(altKeyResult, fieldValues, result, userPayload);
380
- }
381
- }
382
- else if (await entityObject.InnerLoad(pk)) {
383
- await this.InnerSyncSingleItemUpdate(entityObject, fieldValues, result, userPayload);
384
- }
385
- else {
386
- // failed to load the item
387
- result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified primary key does not exist';
388
- }
373
+ protected async SyncSingleItemCreate(entityObject: BaseEntity, fieldValues: any, result: ActionItemOutputType, userPayload: UserPayload) {
374
+ // make sure we strip out the primary key from fieldValues before we pass it in because otherwise it will appear to be an existing record to the BaseEntity
375
+ const noPKValues = { ...fieldValues };
376
+ entityObject.EntityInfo.PrimaryKeys.forEach((pk) => {
377
+ delete noPKValues[pk.Name];
378
+ });
379
+ entityObject.SetMany(noPKValues);
380
+ if (await entityObject.Save()) {
381
+ result.Success = true;
382
+ result.PrimaryKey = new CompositeKey(entityObject.PrimaryKeys.map((pk) => ({ FieldName: pk.Name, Value: pk.Value })));
383
+ // pass back the full record AFTER the sync, that's often quite useful on the other end
384
+ result.RecordJSON = await entityObject.GetDataObjectJSON({
385
+ includeRelatedEntityData: false,
386
+ excludeFields: [],
387
+ omitEmptyStrings: false,
388
+ relatedEntityList: [],
389
+ omitNullValues: false,
390
+ oldValues: false,
391
+ });
392
+ } else {
393
+ result.ErrorMessage = 'Failed to create the item :' + entityObject.LatestResult.Message;
389
394
  }
395
+ }
390
396
 
391
- protected async InnerSyncSingleItemUpdate(entityObject: BaseEntity, fieldValues: any, result: ActionItemOutputType, userPayload: UserPayload) {
392
- entityObject.SetMany(fieldValues);
393
- if (await entityObject.Save()) {
394
- result.Success = true;
395
- if (!result.PrimaryKey || result.PrimaryKey.KeyValuePairs.length === 0) {
396
- result.PrimaryKey = new CompositeKey(entityObject.PrimaryKeys.map((pk) => ({FieldName: pk.Name, Value: pk.Value})));
397
- }
398
- // pass back the full record AFTER the sync, that's often quite useful on the other end
399
- result.RecordJSON = await entityObject.GetDataObjectJSON({
400
- includeRelatedEntityData: false,
401
- excludeFields: [],
402
- omitEmptyStrings: false,
403
- relatedEntityList: [],
404
- omitNullValues: false,
405
- oldValues: false
406
- });
407
- }
408
- else {
409
- result.ErrorMessage = 'Failed to update the item :' + entityObject.LatestResult.Message;
410
- }
397
+ protected async SyncSingleItemUpdate(
398
+ entityObject: BaseEntity,
399
+ pk: CompositeKey,
400
+ ak: CompositeKey,
401
+ fieldValues: any,
402
+ result: ActionItemOutputType,
403
+ userPayload: UserPayload
404
+ ) {
405
+ if (!pk || pk.KeyValuePairs.length === 0) {
406
+ // no pk, attempt to load by alt key
407
+ const altKeyResult = await this.LoadFromAlternateKey(entityObject.EntityInfo.Name, ak, entityObject.ContextCurrentUser);
408
+ if (!altKeyResult) {
409
+ // no record found, create a new one
410
+ result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified alternate key does not exist';
411
+ } else {
412
+ await this.InnerSyncSingleItemUpdate(altKeyResult, fieldValues, result, userPayload);
413
+ }
414
+ } else if (await entityObject.InnerLoad(pk)) {
415
+ await this.InnerSyncSingleItemUpdate(entityObject, fieldValues, result, userPayload);
416
+ } else {
417
+ // failed to load the item
418
+ result.ErrorMessage = 'Failed to load the item, it is possible the record with the specified primary key does not exist';
419
+ }
420
+ }
421
+
422
+ protected async InnerSyncSingleItemUpdate(
423
+ entityObject: BaseEntity,
424
+ fieldValues: any,
425
+ result: ActionItemOutputType,
426
+ userPayload: UserPayload
427
+ ) {
428
+ entityObject.SetMany(fieldValues);
429
+ if (await entityObject.Save()) {
430
+ result.Success = true;
431
+ if (!result.PrimaryKey || result.PrimaryKey.KeyValuePairs.length === 0) {
432
+ result.PrimaryKey = new CompositeKey(entityObject.PrimaryKeys.map((pk) => ({ FieldName: pk.Name, Value: pk.Value })));
433
+ }
434
+ // pass back the full record AFTER the sync, that's often quite useful on the other end
435
+ result.RecordJSON = await entityObject.GetDataObjectJSON({
436
+ includeRelatedEntityData: false,
437
+ excludeFields: [],
438
+ omitEmptyStrings: false,
439
+ relatedEntityList: [],
440
+ omitNullValues: false,
441
+ oldValues: false,
442
+ });
443
+ } else {
444
+ result.ErrorMessage = 'Failed to update the item :' + entityObject.LatestResult.Message;
411
445
  }
446
+ }
412
447
  }
413
-