@contember/engine-actions 1.3.0-alpha.4

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 (289) hide show
  1. package/dist/src/ActionsExecutionContainerHookFactory.d.ts +8 -0
  2. package/dist/src/ActionsExecutionContainerHookFactory.d.ts.map +1 -0
  3. package/dist/src/ActionsExecutionContainerHookFactory.js +28 -0
  4. package/dist/src/ActionsExecutionContainerHookFactory.js.map +1 -0
  5. package/dist/src/ImplementationException.d.ts +3 -0
  6. package/dist/src/ImplementationException.d.ts.map +1 -0
  7. package/dist/src/ImplementationException.js +7 -0
  8. package/dist/src/ImplementationException.js.map +1 -0
  9. package/dist/src/ListenerStoreProvider.d.ts +7 -0
  10. package/dist/src/ListenerStoreProvider.d.ts.map +1 -0
  11. package/dist/src/ListenerStoreProvider.js +21 -0
  12. package/dist/src/ListenerStoreProvider.js.map +1 -0
  13. package/dist/src/dispatch/DispatchWorkerSupervisor.d.ts +17 -0
  14. package/dist/src/dispatch/DispatchWorkerSupervisor.d.ts.map +1 -0
  15. package/dist/src/dispatch/DispatchWorkerSupervisor.js +123 -0
  16. package/dist/src/dispatch/DispatchWorkerSupervisor.js.map +1 -0
  17. package/dist/src/dispatch/EventDispatcher.d.ts +25 -0
  18. package/dist/src/dispatch/EventDispatcher.d.ts.map +1 -0
  19. package/dist/src/dispatch/EventDispatcher.js +46 -0
  20. package/dist/src/dispatch/EventDispatcher.js.map +1 -0
  21. package/dist/src/dispatch/EventsRepository.d.ts +22 -0
  22. package/dist/src/dispatch/EventsRepository.d.ts.map +1 -0
  23. package/dist/src/dispatch/EventsRepository.js +138 -0
  24. package/dist/src/dispatch/EventsRepository.js.map +1 -0
  25. package/dist/src/dispatch/ProjectDispatcher.d.ts +22 -0
  26. package/dist/src/dispatch/ProjectDispatcher.d.ts.map +1 -0
  27. package/dist/src/dispatch/ProjectDispatcher.js +103 -0
  28. package/dist/src/dispatch/ProjectDispatcher.js.map +1 -0
  29. package/dist/src/dispatch/TargetHandlerResolver.d.ts +9 -0
  30. package/dist/src/dispatch/TargetHandlerResolver.d.ts.map +1 -0
  31. package/dist/src/dispatch/TargetHandlerResolver.js +17 -0
  32. package/dist/src/dispatch/TargetHandlerResolver.js.map +1 -0
  33. package/dist/src/dispatch/WebhookTargetHandler.d.ts +7 -0
  34. package/dist/src/dispatch/WebhookTargetHandler.d.ts.map +1 -0
  35. package/dist/src/dispatch/WebhookTargetHandler.js +85 -0
  36. package/dist/src/dispatch/WebhookTargetHandler.js.map +1 -0
  37. package/dist/src/dispatch/types.d.ts +27 -0
  38. package/dist/src/dispatch/types.d.ts.map +1 -0
  39. package/dist/src/dispatch/types.js +3 -0
  40. package/dist/src/dispatch/types.js.map +1 -0
  41. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.d.ts +10 -0
  42. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.d.ts.map +1 -0
  43. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.js +31 -0
  44. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.js.map +1 -0
  45. package/dist/src/graphql/http/ActionsContextResolver.d.ts +11 -0
  46. package/dist/src/graphql/http/ActionsContextResolver.d.ts.map +1 -0
  47. package/dist/src/graphql/http/ActionsContextResolver.js +33 -0
  48. package/dist/src/graphql/http/ActionsContextResolver.js.map +1 -0
  49. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.d.ts +8 -0
  50. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.d.ts.map +1 -0
  51. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.js +21 -0
  52. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.js.map +1 -0
  53. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.d.ts +11 -0
  54. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.d.ts.map +1 -0
  55. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.js +150 -0
  56. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.js.map +1 -0
  57. package/dist/src/graphql/resolvers/ActionsContext.d.ts +9 -0
  58. package/dist/src/graphql/resolvers/ActionsContext.d.ts.map +1 -0
  59. package/dist/src/graphql/resolvers/ActionsContext.js +3 -0
  60. package/dist/src/graphql/resolvers/ActionsContext.js.map +1 -0
  61. package/dist/src/graphql/resolvers/ResolversFactory.d.ts +13 -0
  62. package/dist/src/graphql/resolvers/ResolversFactory.d.ts.map +1 -0
  63. package/dist/src/graphql/resolvers/ResolversFactory.js +32 -0
  64. package/dist/src/graphql/resolvers/ResolversFactory.js.map +1 -0
  65. package/dist/src/graphql/resolvers/index.d.ts +3 -0
  66. package/dist/src/graphql/resolvers/index.d.ts.map +1 -0
  67. package/dist/src/graphql/resolvers/index.js +19 -0
  68. package/dist/src/graphql/resolvers/index.js.map +1 -0
  69. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.d.ts +11 -0
  70. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.d.ts.map +1 -0
  71. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.js +16 -0
  72. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.js.map +1 -0
  73. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.d.ts +11 -0
  74. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.d.ts.map +1 -0
  75. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js +16 -0
  76. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js.map +1 -0
  77. package/dist/src/graphql/resolvers/mutation/index.d.ts +3 -0
  78. package/dist/src/graphql/resolvers/mutation/index.d.ts.map +1 -0
  79. package/dist/src/graphql/resolvers/mutation/index.js +19 -0
  80. package/dist/src/graphql/resolvers/mutation/index.js.map +1 -0
  81. package/dist/src/graphql/resolvers/query/EventsQueryResolver.d.ts +11 -0
  82. package/dist/src/graphql/resolvers/query/EventsQueryResolver.d.ts.map +1 -0
  83. package/dist/src/graphql/resolvers/query/EventsQueryResolver.js +43 -0
  84. package/dist/src/graphql/resolvers/query/EventsQueryResolver.js.map +1 -0
  85. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.d.ts +12 -0
  86. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.d.ts.map +1 -0
  87. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.js +16 -0
  88. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.js.map +1 -0
  89. package/dist/src/graphql/resolvers/query/index.d.ts +2 -0
  90. package/dist/src/graphql/resolvers/query/index.d.ts.map +1 -0
  91. package/dist/src/graphql/resolvers/query/index.js +18 -0
  92. package/dist/src/graphql/resolvers/query/index.js.map +1 -0
  93. package/dist/src/graphql/schema/actions.graphql.d.ts +3 -0
  94. package/dist/src/graphql/schema/actions.graphql.d.ts.map +1 -0
  95. package/dist/src/graphql/schema/actions.graphql.js +93 -0
  96. package/dist/src/graphql/schema/actions.graphql.js.map +1 -0
  97. package/dist/src/graphql/schema/index.d.ts +224 -0
  98. package/dist/src/graphql/schema/index.d.ts.map +1 -0
  99. package/dist/src/graphql/schema/index.js +3 -0
  100. package/dist/src/graphql/schema/index.js.map +1 -0
  101. package/dist/src/index.d.ts +13 -0
  102. package/dist/src/index.d.ts.map +1 -0
  103. package/dist/src/index.js +81 -0
  104. package/dist/src/index.js.map +1 -0
  105. package/dist/src/migrations/2023-03-10-145000-actions-variables.d.ts +3 -0
  106. package/dist/src/migrations/2023-03-10-145000-actions-variables.d.ts.map +1 -0
  107. package/dist/src/migrations/2023-03-10-145000-actions-variables.js +17 -0
  108. package/dist/src/migrations/2023-03-10-145000-actions-variables.js.map +1 -0
  109. package/dist/src/migrations/index.d.ts +3 -0
  110. package/dist/src/migrations/index.d.ts.map +1 -0
  111. package/dist/src/migrations/index.js +13 -0
  112. package/dist/src/migrations/index.js.map +1 -0
  113. package/dist/src/migrations/snapshot.d.ts +3 -0
  114. package/dist/src/migrations/snapshot.d.ts.map +1 -0
  115. package/dist/src/migrations/snapshot.js +49 -0
  116. package/dist/src/migrations/snapshot.js.map +1 -0
  117. package/dist/src/model/EventsInProcessingQuery.d.ts +9 -0
  118. package/dist/src/model/EventsInProcessingQuery.d.ts.map +1 -0
  119. package/dist/src/model/EventsInProcessingQuery.js +22 -0
  120. package/dist/src/model/EventsInProcessingQuery.js.map +1 -0
  121. package/dist/src/model/EventsToProcessQuery.d.ts +9 -0
  122. package/dist/src/model/EventsToProcessQuery.d.ts.map +1 -0
  123. package/dist/src/model/EventsToProcessQuery.js +22 -0
  124. package/dist/src/model/EventsToProcessQuery.js.map +1 -0
  125. package/dist/src/model/EventsToProcessSpecification.d.ts +4 -0
  126. package/dist/src/model/EventsToProcessSpecification.d.ts.map +1 -0
  127. package/dist/src/model/EventsToProcessSpecification.js +14 -0
  128. package/dist/src/model/EventsToProcessSpecification.js.map +1 -0
  129. package/dist/src/model/FailedEventsQuery.d.ts +9 -0
  130. package/dist/src/model/FailedEventsQuery.d.ts.map +1 -0
  131. package/dist/src/model/FailedEventsQuery.js +22 -0
  132. package/dist/src/model/FailedEventsQuery.js.map +1 -0
  133. package/dist/src/model/SetVariableCommand.d.ts +8 -0
  134. package/dist/src/model/SetVariableCommand.d.ts.map +1 -0
  135. package/dist/src/model/SetVariableCommand.js +26 -0
  136. package/dist/src/model/SetVariableCommand.js.map +1 -0
  137. package/dist/src/model/VariablesManager.d.ts +8 -0
  138. package/dist/src/model/VariablesManager.d.ts.map +1 -0
  139. package/dist/src/model/VariablesManager.js +46 -0
  140. package/dist/src/model/VariablesManager.js.map +1 -0
  141. package/dist/src/model/VariablesQuery.d.ts +12 -0
  142. package/dist/src/model/VariablesQuery.d.ts.map +1 -0
  143. package/dist/src/model/VariablesQuery.js +13 -0
  144. package/dist/src/model/VariablesQuery.js.map +1 -0
  145. package/dist/src/model/types.d.ts +16 -0
  146. package/dist/src/model/types.d.ts.map +1 -0
  147. package/dist/src/model/types.js +3 -0
  148. package/dist/src/model/types.js.map +1 -0
  149. package/dist/src/triggers/Payload.d.ts +62 -0
  150. package/dist/src/triggers/Payload.d.ts.map +1 -0
  151. package/dist/src/triggers/Payload.js +3 -0
  152. package/dist/src/triggers/Payload.js.map +1 -0
  153. package/dist/src/triggers/TriggerHandler.d.ts +26 -0
  154. package/dist/src/triggers/TriggerHandler.d.ts.map +1 -0
  155. package/dist/src/triggers/TriggerHandler.js +130 -0
  156. package/dist/src/triggers/TriggerHandler.js.map +1 -0
  157. package/dist/src/triggers/TriggerIndirectChangesFetcher.d.ts +11 -0
  158. package/dist/src/triggers/TriggerIndirectChangesFetcher.d.ts.map +1 -0
  159. package/dist/src/triggers/TriggerIndirectChangesFetcher.js +24 -0
  160. package/dist/src/triggers/TriggerIndirectChangesFetcher.js.map +1 -0
  161. package/dist/src/triggers/TriggerListeners.d.ts +9 -0
  162. package/dist/src/triggers/TriggerListeners.d.ts.map +1 -0
  163. package/dist/src/triggers/TriggerListeners.js +3 -0
  164. package/dist/src/triggers/TriggerListeners.js.map +1 -0
  165. package/dist/src/triggers/TriggerListenersBuilder.d.ts +15 -0
  166. package/dist/src/triggers/TriggerListenersBuilder.d.ts.map +1 -0
  167. package/dist/src/triggers/TriggerListenersBuilder.js +169 -0
  168. package/dist/src/triggers/TriggerListenersBuilder.js.map +1 -0
  169. package/dist/src/triggers/TriggerListenersFactory.d.ts +8 -0
  170. package/dist/src/triggers/TriggerListenersFactory.d.ts.map +1 -0
  171. package/dist/src/triggers/TriggerListenersFactory.js +18 -0
  172. package/dist/src/triggers/TriggerListenersFactory.js.map +1 -0
  173. package/dist/src/triggers/TriggerListenersStore.d.ts +48 -0
  174. package/dist/src/triggers/TriggerListenersStore.d.ts.map +1 -0
  175. package/dist/src/triggers/TriggerListenersStore.js +30 -0
  176. package/dist/src/triggers/TriggerListenersStore.js.map +1 -0
  177. package/dist/src/triggers/TriggerPayloadBuilder.d.ts +14 -0
  178. package/dist/src/triggers/TriggerPayloadBuilder.d.ts.map +1 -0
  179. package/dist/src/triggers/TriggerPayloadBuilder.js +140 -0
  180. package/dist/src/triggers/TriggerPayloadBuilder.js.map +1 -0
  181. package/dist/src/triggers/TriggerPayloadManager.d.ts +27 -0
  182. package/dist/src/triggers/TriggerPayloadManager.d.ts.map +1 -0
  183. package/dist/src/triggers/TriggerPayloadManager.js +26 -0
  184. package/dist/src/triggers/TriggerPayloadManager.js.map +1 -0
  185. package/dist/src/triggers/TriggerPayloadPersister.d.ts +18 -0
  186. package/dist/src/triggers/TriggerPayloadPersister.d.ts.map +1 -0
  187. package/dist/src/triggers/TriggerPayloadPersister.js +44 -0
  188. package/dist/src/triggers/TriggerPayloadPersister.js.map +1 -0
  189. package/dist/src/triggers/index.d.ts +8 -0
  190. package/dist/src/triggers/index.d.ts.map +1 -0
  191. package/dist/src/triggers/index.js +24 -0
  192. package/dist/src/triggers/index.js.map +1 -0
  193. package/dist/src/tsconfig.tsbuildinfo +1 -0
  194. package/dist/src/utils/assertNever.d.ts +2 -0
  195. package/dist/src/utils/assertNever.d.ts.map +1 -0
  196. package/dist/src/utils/assertNever.js +8 -0
  197. package/dist/src/utils/assertNever.js.map +1 -0
  198. package/dist/src/utils/map.d.ts +2 -0
  199. package/dist/src/utils/map.d.ts.map +1 -0
  200. package/dist/src/utils/map.js +14 -0
  201. package/dist/src/utils/map.js.map +1 -0
  202. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.d.ts +2 -0
  203. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.d.ts.map +1 -0
  204. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.js +442 -0
  205. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.js.map +1 -0
  206. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.d.ts +2 -0
  207. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.d.ts.map +1 -0
  208. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.js +449 -0
  209. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.js.map +1 -0
  210. package/dist/tests/cases/integration/triggers.rootWatch.test.d.ts +2 -0
  211. package/dist/tests/cases/integration/triggers.rootWatch.test.d.ts.map +1 -0
  212. package/dist/tests/cases/integration/triggers.rootWatch.test.js +159 -0
  213. package/dist/tests/cases/integration/triggers.rootWatch.test.js.map +1 -0
  214. package/dist/tests/cases/integration/utils.d.ts +4 -0
  215. package/dist/tests/cases/integration/utils.d.ts.map +1 -0
  216. package/dist/tests/cases/integration/utils.js +12 -0
  217. package/dist/tests/cases/integration/utils.js.map +1 -0
  218. package/dist/tests/cases/unit/generator.test.d.ts +2 -0
  219. package/dist/tests/cases/unit/generator.test.d.ts.map +1 -0
  220. package/dist/tests/cases/unit/generator.test.js +627 -0
  221. package/dist/tests/cases/unit/generator.test.js.map +1 -0
  222. package/dist/tests/src/gql.d.ts +2 -0
  223. package/dist/tests/src/gql.d.ts.map +1 -0
  224. package/dist/tests/src/gql.js +14 -0
  225. package/dist/tests/src/gql.js.map +1 -0
  226. package/dist/tests/tsconfig.tsbuildinfo +1 -0
  227. package/graphql-actions.codegen.yml +21 -0
  228. package/package.json +41 -0
  229. package/src/ActionsExecutionContainerHookFactory.ts +28 -0
  230. package/src/ImplementationException.ts +2 -0
  231. package/src/ListenerStoreProvider.ts +17 -0
  232. package/src/dispatch/DispatchWorkerSupervisor.ts +137 -0
  233. package/src/dispatch/EventDispatcher.ts +64 -0
  234. package/src/dispatch/EventsRepository.ts +165 -0
  235. package/src/dispatch/ProjectDispatcher.ts +119 -0
  236. package/src/dispatch/TargetHandlerResolver.ts +18 -0
  237. package/src/dispatch/WebhookTargetHandler.ts +88 -0
  238. package/src/dispatch/types.ts +31 -0
  239. package/src/graphql/http/ActionsApiMiddlewareFactory.ts +36 -0
  240. package/src/graphql/http/ActionsContextResolver.ts +38 -0
  241. package/src/graphql/http/ActionsGraphQLHandlerFactory.ts +23 -0
  242. package/src/graphql/http/ActionsWebsocketControllerFactory.ts +143 -0
  243. package/src/graphql/resolvers/ActionsContext.ts +9 -0
  244. package/src/graphql/resolvers/ResolversFactory.ts +35 -0
  245. package/src/graphql/resolvers/index.ts +2 -0
  246. package/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.ts +16 -0
  247. package/src/graphql/resolvers/mutation/SetVariablesMutationResolver.ts +19 -0
  248. package/src/graphql/resolvers/mutation/index.ts +2 -0
  249. package/src/graphql/resolvers/query/EventsQueryResolver.ts +55 -0
  250. package/src/graphql/resolvers/query/VariablesQueryResolver.ts +18 -0
  251. package/src/graphql/resolvers/query/index.ts +1 -0
  252. package/src/graphql/schema/actions.graphql.ts +91 -0
  253. package/src/graphql/schema/index.ts +295 -0
  254. package/src/index.ts +88 -0
  255. package/src/migrations/2023-03-10-145000-actions-variables.ts +16 -0
  256. package/src/migrations/index.ts +7 -0
  257. package/src/migrations/snapshot.ts +47 -0
  258. package/src/model/EventsInProcessingQuery.ts +21 -0
  259. package/src/model/EventsToProcessQuery.ts +21 -0
  260. package/src/model/EventsToProcessSpecification.ts +11 -0
  261. package/src/model/FailedEventsQuery.ts +21 -0
  262. package/src/model/SetVariableCommand.ts +26 -0
  263. package/src/model/VariablesManager.ts +49 -0
  264. package/src/model/VariablesQuery.ts +17 -0
  265. package/src/model/types.ts +15 -0
  266. package/src/triggers/Payload.ts +82 -0
  267. package/src/triggers/TriggerHandler.ts +161 -0
  268. package/src/triggers/TriggerIndirectChangesFetcher.ts +30 -0
  269. package/src/triggers/TriggerListeners.ts +16 -0
  270. package/src/triggers/TriggerListenersBuilder.ts +190 -0
  271. package/src/triggers/TriggerListenersFactory.ts +19 -0
  272. package/src/triggers/TriggerListenersStore.ts +76 -0
  273. package/src/triggers/TriggerPayloadBuilder.ts +148 -0
  274. package/src/triggers/TriggerPayloadManager.ts +47 -0
  275. package/src/triggers/TriggerPayloadPersister.ts +43 -0
  276. package/src/triggers/index.ts +7 -0
  277. package/src/tsconfig.json +21 -0
  278. package/src/utils/assertNever.ts +3 -0
  279. package/src/utils/map.ts +13 -0
  280. package/tests/cases/integration/triggers.manyHasManyWatch.test.ts +437 -0
  281. package/tests/cases/integration/triggers.manyHasOneWatch.test.ts +446 -0
  282. package/tests/cases/integration/triggers.rootWatch.test.ts +152 -0
  283. package/tests/cases/integration/utils.ts +9 -0
  284. package/tests/cases/unit/generator.test.ts +689 -0
  285. package/tests/src/gql.ts +7 -0
  286. package/tests/tsconfig.json +16 -0
  287. package/tsconfig.json +5 -0
  288. package/tsconfig.settings.json +8 -0
  289. package/vite.config.js +3 -0
@@ -0,0 +1,82 @@
1
+ import { Input, JSONObject, JSONValue } from '@contember/schema'
2
+
3
+ export type UpdateEvent = {
4
+ operation: 'update'
5
+ entity: string
6
+ id: Input.PrimaryValue
7
+ values: JSONObject
8
+ old?: JSONObject
9
+ selection?: any
10
+ path?: string[]
11
+ }
12
+
13
+ export type CreateEvent = {
14
+ operation: 'create'
15
+ entity: string
16
+ id: Input.PrimaryValue
17
+ values: JSONObject
18
+ selection?: any
19
+ path?: string[]
20
+ }
21
+
22
+ export type DeleteEvent = {
23
+ operation: 'delete'
24
+ entity: string
25
+ id: Input.PrimaryValue
26
+ selection?: any
27
+ path?: string[]
28
+ }
29
+
30
+ export type JunctionConnectEvent = {
31
+ operation: 'junction_connect'
32
+ entity: string
33
+ id: Input.PrimaryValue
34
+ relation: string
35
+ inverseId: Input.PrimaryValue
36
+ selection?: any
37
+ path?: string[]
38
+ }
39
+
40
+ export type JunctionDisconnectEvent = {
41
+ operation: 'junction_disconnect'
42
+ entity: string
43
+ id: Input.PrimaryValue
44
+ relation: string
45
+ inverseId: Input.PrimaryValue
46
+ selection?: any
47
+ path?: string[]
48
+ }
49
+
50
+ export type WatchEventPayload = {
51
+ operation: 'watch'
52
+ trigger: string
53
+ entity: string
54
+ id: Input.PrimaryValue
55
+ events: BaseEventPayload[]
56
+ selection?: any
57
+ }
58
+
59
+ export type BaseEventPayload =
60
+ | CreateEvent
61
+ | UpdateEvent
62
+ | DeleteEvent
63
+ | JunctionConnectEvent
64
+ | JunctionDisconnectEvent
65
+
66
+ export type BasicEventPayload =
67
+ & BaseEventPayload
68
+ & {
69
+ trigger: string
70
+ }
71
+
72
+ export type AnyEventPayload =
73
+ | BasicEventPayload
74
+ | WatchEventPayload
75
+
76
+ export interface TriggerPayload {
77
+ // identityId: string
78
+ // apiKeyId: string
79
+ transactionId: string
80
+ createdAt: string
81
+ event: AnyEventPayload
82
+ }
@@ -0,0 +1,161 @@
1
+ import {
2
+ AfterInsertEvent,
3
+ AfterJunctionUpdateEvent,
4
+ AfterUpdateEvent,
5
+ BeforeDeleteEvent,
6
+ BeforeUpdateEvent,
7
+ EventManager,
8
+ } from '@contember/engine-content-api'
9
+ import { Input } from '@contember/schema'
10
+ import { IndirectListener, JunctionListener, TriggerListenersStore } from './TriggerListenersStore'
11
+ import { TriggerPayloadManager } from './TriggerPayloadManager'
12
+ import { TriggerIndirectChangesFetcher } from './TriggerIndirectChangesFetcher'
13
+
14
+ export type EventCause =
15
+ | BeforeUpdateEvent
16
+ | AfterUpdateEvent
17
+ | BeforeDeleteEvent
18
+ | AfterInsertEvent
19
+ | AfterJunctionUpdateEvent
20
+
21
+ export class TriggerHandler {
22
+ constructor(
23
+ private readonly payloadManager: TriggerPayloadManager,
24
+ private readonly listenersStore: TriggerListenersStore,
25
+ private readonly changesFetcher: TriggerIndirectChangesFetcher,
26
+ ) {
27
+ }
28
+
29
+ attach(evm: EventManager) {
30
+ evm.listen('BeforeDeleteEvent', async event => {
31
+ await this.directDeleteHandler(event)
32
+ await this.indirectChangesEntityHandler(event)
33
+ })
34
+ evm.listen('AfterInsertEvent', async event => {
35
+ await this.indirectChangesEntityHandler(event)
36
+ await this.directCreateHandler(event)
37
+ })
38
+ evm.listen('BeforeUpdateEvent', async event => {
39
+ await this.indirectChangesRelationHandler(event)
40
+ })
41
+ evm.listen('AfterUpdateEvent', async event => {
42
+ if (event.hasChanges) {
43
+ await this.indirectChangesUpdatesHandler(event)
44
+ await this.directUpdateHandler(event)
45
+ }
46
+ })
47
+ evm.listen('AfterJunctionUpdateEvent', async event => {
48
+ if (event.hasChanges) {
49
+ await this.junctionHandler(event)
50
+ }
51
+ })
52
+ evm.listen('BeforeCommitEvent', async event => {
53
+ await this.payloadManager.persist()
54
+ })
55
+ }
56
+
57
+ private async directDeleteHandler(event: BeforeDeleteEvent) {
58
+ const deleteListeners = this.listenersStore.getDeleteListener(event.entity.name)
59
+ if (!deleteListeners) {
60
+ return
61
+ }
62
+ await Promise.all(deleteListeners.map(listener => {
63
+ return this.payloadManager.add({
64
+ listener,
65
+ entity: event.entity,
66
+ primary: event.id,
67
+ cause: event,
68
+ })
69
+ }))
70
+ }
71
+
72
+ private async directUpdateHandler(event: AfterUpdateEvent) {
73
+ const updateListeners = this.listenersStore.getUpdateListeners(event.entity.name)
74
+ updateListeners.map(listener => {
75
+ if (event.data.some(it => listener.fields.has(it.fieldName))) {
76
+ this.payloadManager.add({
77
+ listener,
78
+ entity: event.entity,
79
+ primary: event.id,
80
+ cause: event,
81
+ })
82
+ }
83
+ })
84
+ }
85
+
86
+ private async directCreateHandler(event: AfterInsertEvent) {
87
+ const createListeners = this.listenersStore.getCreateListener(event.entity.name)
88
+ createListeners.map(listener => {
89
+ this.payloadManager.add({
90
+ listener,
91
+ entity: event.entity,
92
+ primary: event.id,
93
+ cause: event,
94
+ })
95
+ })
96
+ }
97
+
98
+
99
+ /**
100
+ * Collect affected triggers after entity was created or before it was deleted.
101
+ * todo: after insert, it should probably check only owning relations, because other relations are connected later, so it would be always empty
102
+ */
103
+ private async indirectChangesEntityHandler(event: BeforeDeleteEvent | AfterInsertEvent) {
104
+ //
105
+ const indirectEntityListeners = this.listenersStore.getIndirectListeners(event.entity.name)
106
+ const promises = indirectEntityListeners.map(listener => this.collectDeepChanges(event, listener, {
107
+ [event.entity.primary]: { eq: event.id },
108
+ }))
109
+ await Promise.all(promises)
110
+ }
111
+
112
+ private async indirectChangesRelationHandler(event: BeforeUpdateEvent) {
113
+ await this.indirectChangesUpdatesHandlerInner(event, 'relations')
114
+ }
115
+
116
+ private async indirectChangesUpdatesHandler(event: AfterUpdateEvent) {
117
+ await this.indirectChangesUpdatesHandlerInner(event, 'fields')
118
+ }
119
+ private async indirectChangesUpdatesHandlerInner(event: AfterUpdateEvent | BeforeUpdateEvent, type: 'fields' | 'relations') {
120
+ const indirectEntityListeners = this.listenersStore.getIndirectListeners(event.entity.name)
121
+ const promises = indirectEntityListeners.map(listener => {
122
+ if (event.data.some(val => listener[type].has(val.fieldName))) {
123
+ return this.collectDeepChanges(event, listener, {
124
+ [event.entity.primary]: { eq: event.id },
125
+ })
126
+ }
127
+ })
128
+ await Promise.all(promises)
129
+ }
130
+
131
+ private async junctionHandler(event: AfterJunctionUpdateEvent) {
132
+ const listeners = this.listenersStore.getJunctionListeners(event.owningEntity.name, event.owningRelation.name)
133
+ const promises = listeners.map(listener => {
134
+ const primary = listener.context.type === 'owning'
135
+ ? event.owningId
136
+ : event.inverseId
137
+ const entity = listener.context.entity
138
+ return this.collectDeepChanges(event, listener, {
139
+ [entity.primary]: { eq: primary },
140
+ })
141
+ })
142
+ await Promise.all(promises)
143
+ }
144
+
145
+
146
+ private async collectDeepChanges(
147
+ cause: EventCause,
148
+ listener: IndirectListener | JunctionListener,
149
+ where: Input.Where,
150
+ ) {
151
+ const result = await this.changesFetcher.fetch(listener, where)
152
+ for (const row of result) {
153
+ this.payloadManager.add({
154
+ listener,
155
+ entity: listener.rootEntity,
156
+ primary: row,
157
+ cause,
158
+ })
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,30 @@
1
+ import { Mapper, PathFactory, WhereBuilder } from '@contember/engine-content-api'
2
+ import { IndirectListener, JunctionListener } from './TriggerListenersStore'
3
+ import { SelectBuilder } from '@contember/database'
4
+ import { Input } from '@contember/schema'
5
+
6
+ export class TriggerIndirectChangesFetcher {
7
+ constructor(
8
+ private readonly mapper: Mapper,
9
+ private readonly whereBuilder: WhereBuilder,
10
+ private readonly pathFactory: PathFactory,
11
+ ) {
12
+ }
13
+
14
+ public async fetch(
15
+ listener: IndirectListener | JunctionListener,
16
+ where: Input.Where,
17
+ ): Promise<Input.PrimaryValue[]> {
18
+ for (const key of listener.path.reverse()) {
19
+ where = { [key]: where }
20
+ }
21
+ const qb = SelectBuilder.create<{ id: Input.PrimaryValue }>()
22
+ .from(listener.rootEntity.tableName, 'root_')
23
+ .select(['root_', listener.rootEntity.primaryColumn], 'id')
24
+ const path = this.pathFactory.create([])
25
+ const qbWithWhere = this.whereBuilder.build(qb, listener.rootEntity, path, where)
26
+
27
+ return (await qbWithWhere.getResult(this.mapper.db)).map(it => it.id)
28
+ }
29
+
30
+ }
@@ -0,0 +1,16 @@
1
+ import {
2
+ CreateListener,
3
+ DeleteListener,
4
+ IndirectListener,
5
+ JunctionListener,
6
+ UpdateListener,
7
+ } from './TriggerListenersStore'
8
+
9
+ export interface TriggerListeners {
10
+ readonly deleteListeners: Map<string, DeleteListener[]>
11
+ readonly createListeners: Map<string, CreateListener[]>
12
+ readonly updateListeners: Map<string, UpdateListener[]>
13
+ readonly indirectListeners: Map<string, IndirectListener[]>
14
+ readonly junctionListeners: Map<string, Map<string, JunctionListener[]>>
15
+ }
16
+
@@ -0,0 +1,190 @@
1
+ import { Actions, Model } from '@contember/schema'
2
+ import { TriggerListeners } from './TriggerListeners'
3
+ import { JunctionListener, TriggerListenersStore } from './TriggerListenersStore'
4
+ import { acceptFieldVisitor, getEntity } from '@contember/schema-utils'
5
+ import { mapGetOrPut } from '../utils/map'
6
+ import { ImplementationException } from '../ImplementationException'
7
+
8
+ export class TriggerListenerBuilder {
9
+
10
+ private readonly data: TriggerListeners = {
11
+ createListeners: new Map(),
12
+ updateListeners: new Map(),
13
+ deleteListeners: new Map(),
14
+ indirectListeners: new Map(),
15
+ junctionListeners: new Map(),
16
+ }
17
+
18
+ constructor(
19
+ private readonly model: Model.Schema,
20
+ ) {
21
+ }
22
+
23
+ public add(trigger: Actions.AnyTrigger) {
24
+ if (trigger.type === 'basic') {
25
+ this.processBasicTrigger(trigger)
26
+ } else if (trigger.type === 'watch') {
27
+ this.processIndirectListeners(trigger)
28
+ } else {
29
+ ((_: never) => {
30
+ throw new ImplementationException(`Unhandled trigger ${(trigger as any).type}`)
31
+ })(trigger)
32
+ }
33
+ }
34
+
35
+ private processBasicTrigger(trigger: Actions.BasicTrigger) {
36
+ const entity = getEntity(this.model, trigger.entity)
37
+ if (trigger.create) {
38
+ this.addListener('createListeners', trigger.entity, {
39
+ type: 'create',
40
+ entity,
41
+ trigger,
42
+ })
43
+ }
44
+ if (trigger.delete) {
45
+ this.addListener('deleteListeners', trigger.entity, {
46
+ type: 'delete',
47
+ entity,
48
+ trigger,
49
+ })
50
+ }
51
+ if (trigger.update) {
52
+ this.addListener('updateListeners', trigger.entity, {
53
+ type: 'update',
54
+ entity,
55
+ trigger,
56
+ fields: new Set(Object.keys(entity.fields)), // todo: only columns and owning
57
+ })
58
+ }
59
+ }
60
+
61
+ private processIndirectListeners(
62
+ trigger: Actions.WatchTrigger,
63
+ ) {
64
+ const entity = getEntity(this.model, trigger.entity)
65
+ this.addListener('createListeners', trigger.entity, {
66
+ type: 'create',
67
+ entity,
68
+ trigger,
69
+ })
70
+ this.addListener('deleteListeners', trigger.entity, {
71
+ type: 'delete',
72
+ entity,
73
+ trigger,
74
+ })
75
+ this.processIndirectListenersNode(trigger, entity, entity, trigger.watch, [])
76
+ }
77
+ private processIndirectListenersNode(
78
+ trigger: Actions.WatchTrigger,
79
+ rootEntity: Model.Entity,
80
+ entity: Model.Entity,
81
+ node: Actions.SelectionNode,
82
+ path: string[],
83
+ ) {
84
+ const fields = new Set<string>()
85
+ const relations = new Set<string>()
86
+ for (const entry of node) {
87
+ const [field, args, selection] = Array.isArray(entry) ? entry : [entry, undefined, undefined]
88
+ acceptFieldVisitor(this.model, entity, field, {
89
+ visitColumn: ({ entity, column }) => {
90
+ if (selection?.length > 0) {
91
+ throw new ImplementationException(`Column ${field} cannot have sub-selection`)
92
+ }
93
+ fields.add(column.name)
94
+ },
95
+ visitManyHasOne: ({ entity, relation, targetEntity, targetRelation }) => {
96
+ fields.add(relation.name)
97
+ relations.add(relation.name)
98
+ if (selection?.length > 0) {
99
+ this.processIndirectListenersNode(trigger, rootEntity, targetEntity, selection, [...path, relation.name])
100
+ }
101
+ },
102
+ visitOneHasMany: ({ entity, relation, targetEntity, targetRelation }) => {
103
+ this.processIndirectListenersNode(trigger, rootEntity, targetEntity, [...selection ?? [], targetRelation.name], [...path, relation.name])
104
+ },
105
+ visitOneHasOneOwning: ({ entity, relation, targetEntity, targetRelation }) => {
106
+ fields.add(relation.name)
107
+ relations.add(relation.name)
108
+ if (selection?.length > 0) {
109
+ this.processIndirectListenersNode(trigger, rootEntity, targetEntity, selection, [...path, relation.name])
110
+ }
111
+ },
112
+ visitOneHasOneInverse: ({ entity, relation, targetEntity, targetRelation }) => {
113
+ this.processIndirectListenersNode(trigger, rootEntity, targetEntity, [...selection ?? [], targetRelation.name], [...path, relation.name])
114
+ },
115
+ visitManyHasManyOwning: ({ entity, relation, targetEntity, targetRelation }) => {
116
+ this.addJunctionListener(entity.name, relation.name, {
117
+ type: 'junction',
118
+ rootEntity,
119
+ path: path,
120
+ trigger,
121
+ context: {
122
+ entity,
123
+ relation,
124
+ type: 'owning',
125
+ },
126
+ })
127
+ if (selection?.length > 0) {
128
+ this.processIndirectListenersNode(trigger, rootEntity, targetEntity, selection, [...path, relation.name])
129
+ }
130
+ },
131
+ visitManyHasManyInverse: ({ entity, relation, targetEntity, targetRelation }) => {
132
+ this.addJunctionListener(targetEntity.name, targetRelation.name, {
133
+ type: 'junction',
134
+ rootEntity,
135
+ path: path,
136
+ trigger,
137
+ context: {
138
+ entity,
139
+ relation,
140
+ type: 'inverse',
141
+ },
142
+ })
143
+ if (selection?.length > 0) {
144
+ this.processIndirectListenersNode(trigger, rootEntity, targetEntity, selection, [...path, relation.name])
145
+ }
146
+ },
147
+ })
148
+ }
149
+ if (path.length === 0) {
150
+ this.addListener('updateListeners', entity.name, {
151
+ type: 'update',
152
+ entity: rootEntity,
153
+ fields,
154
+ trigger,
155
+ })
156
+ } else {
157
+ this.addListener('indirectListeners', entity.name, {
158
+ type: 'indirect',
159
+ rootEntity: rootEntity,
160
+ fields,
161
+ relations,
162
+ path,
163
+ trigger,
164
+ })
165
+ }
166
+ }
167
+
168
+ public createStore(): TriggerListenersStore {
169
+ return new TriggerListenersStore(this.data)
170
+ }
171
+
172
+
173
+ private addListener<
174
+ K extends Exclude<keyof TriggerListeners, 'junctionListeners'>,
175
+ V extends TriggerListeners[K] extends Map<string, infer V extends any[]> ? V[number] : never
176
+ >
177
+ (
178
+ type: K,
179
+ entityName: string,
180
+ value: V,
181
+ ) {
182
+ mapGetOrPut<string, V[], []>(this.data[type] as Map<string, V[]>, entityName, () => []).push(value)
183
+ }
184
+
185
+ private addJunctionListener(entityName: string, relationName: string, listener: JunctionListener) {
186
+ const entityJunctionListeners = mapGetOrPut(this.data.junctionListeners, entityName, () => new Map())
187
+ const relationListeners = mapGetOrPut(entityJunctionListeners, relationName, () => [])
188
+ relationListeners.push(listener)
189
+ }
190
+ }
@@ -0,0 +1,19 @@
1
+ import { TriggerListenersStore } from './TriggerListenersStore'
2
+ import { TriggerListenerBuilder } from './TriggerListenersBuilder'
3
+ import { Schema } from '@contember/schema'
4
+
5
+ export class TriggerListenersFactory {
6
+ constructor(
7
+ private readonly schema: Schema,
8
+ ) {
9
+ }
10
+
11
+ public create(): TriggerListenersStore {
12
+ const builder = new TriggerListenerBuilder(this.schema.model)
13
+ for (const trigger of Object.values(this.schema.actions.triggers)) {
14
+ builder.add(trigger)
15
+ }
16
+
17
+ return builder.createStore()
18
+ }
19
+ }
@@ -0,0 +1,76 @@
1
+ import { Actions, Model } from '@contember/schema'
2
+ import { TriggerListeners } from './TriggerListeners'
3
+
4
+ export interface IndirectListener {
5
+ type: 'indirect'
6
+ trigger: Actions.AnyTrigger
7
+ rootEntity: Model.Entity
8
+ fields: Set<string>
9
+ relations: Set<string>
10
+ path: string[]
11
+ }
12
+
13
+ export interface JunctionListener {
14
+ type: 'junction'
15
+ trigger: Actions.AnyTrigger
16
+ rootEntity: Model.Entity
17
+ path: string[]
18
+ context: {
19
+ entity: Model.Entity
20
+ relation: Model.ManyHasManyOwningRelation | Model.ManyHasManyInverseRelation
21
+ type: 'owning' | 'inverse'
22
+ }
23
+ }
24
+
25
+ export interface DeleteListener {
26
+ type: 'delete'
27
+ trigger: Actions.AnyTrigger
28
+ entity: Model.Entity
29
+ }
30
+
31
+ export interface CreateListener {
32
+ type: 'create'
33
+ trigger: Actions.AnyTrigger
34
+ entity: Model.Entity
35
+ }
36
+
37
+ export interface UpdateListener {
38
+ type: 'update'
39
+ trigger: Actions.AnyTrigger
40
+ entity: Model.Entity
41
+ fields: Set<string>
42
+ }
43
+
44
+ export type AnyListener =
45
+ | JunctionListener
46
+ | UpdateListener
47
+ | CreateListener
48
+ | DeleteListener
49
+ | IndirectListener
50
+
51
+ export class TriggerListenersStore {
52
+ constructor(
53
+ private readonly listeners: TriggerListeners,
54
+ ) {
55
+ }
56
+
57
+ public getUpdateListeners(entityName: string): UpdateListener[] {
58
+ return this.listeners.updateListeners.get(entityName) ?? []
59
+ }
60
+
61
+ public getDeleteListener(entityName: string): DeleteListener[] {
62
+ return this.listeners.deleteListeners.get(entityName) ?? []
63
+ }
64
+
65
+ public getCreateListener(entityName: string): CreateListener[] {
66
+ return this.listeners.createListeners.get(entityName) ?? []
67
+ }
68
+
69
+ public getIndirectListeners(entityName: string): IndirectListener[] {
70
+ return this.listeners.indirectListeners.get(entityName) ?? []
71
+ }
72
+
73
+ public getJunctionListeners(entityName: string, relationName: string): JunctionListener[] {
74
+ return this.listeners.junctionListeners.get(entityName)?.get(relationName) ?? []
75
+ }
76
+ }