@elyx-code/editor-ui 0.0.2

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 (452) hide show
  1. package/README.md +2 -0
  2. package/package.json +109 -0
  3. package/src/App.tsx +31 -0
  4. package/src/Router.tsx +115 -0
  5. package/src/__mocks__/defaultModuleMock.ts +1 -0
  6. package/src/__mocks__/fileMock.ts +1 -0
  7. package/src/__mocks__/styleMock.ts +1 -0
  8. package/src/assets/Clock-11.1s-18px.svg +16 -0
  9. package/src/assets/Clock-11.1s-28px.svg +16 -0
  10. package/src/assets/authentication.svg +1 -0
  11. package/src/assets/canvas-backdrop-0.png +0 -0
  12. package/src/assets/canvas-backdrop-1.png +0 -0
  13. package/src/assets/canvas-backdrop-2.png +0 -0
  14. package/src/assets/canvas-backdrop-3.png +0 -0
  15. package/src/assets/canvas-backdrop-4.png +0 -0
  16. package/src/assets/canvas-backdrop-5.png +0 -0
  17. package/src/assets/canvas-backdrop.png +0 -0
  18. package/src/assets/checkmark-animation.gif +0 -0
  19. package/src/assets/checkmark-animation.mp4 +0 -0
  20. package/src/assets/code-formatting/format-black.svg +6 -0
  21. package/src/assets/code-formatting/format-dark-grey.svg +6 -0
  22. package/src/assets/code-formatting/format-light-grey.svg +6 -0
  23. package/src/assets/code-formatting/format-white.svg +6 -0
  24. package/src/assets/code-formatting/inline-black.svg +5 -0
  25. package/src/assets/code-formatting/inline-dark-grey.svg +5 -0
  26. package/src/assets/code-formatting/inline-light-grey.svg +5 -0
  27. package/src/assets/code-formatting/inline-white.svg +5 -0
  28. package/src/assets/contained-logo-full-word.png +0 -0
  29. package/src/assets/cron-job-color.png +0 -0
  30. package/src/assets/cron-job.png +0 -0
  31. package/src/assets/database-table-color.png +0 -0
  32. package/src/assets/database-table.png +0 -0
  33. package/src/assets/datatype-icons/black/any.svg +1 -0
  34. package/src/assets/datatype-icons/black/binary.svg +1 -0
  35. package/src/assets/datatype-icons/black/boolean.svg +3 -0
  36. package/src/assets/datatype-icons/black/date-time.svg +3 -0
  37. package/src/assets/datatype-icons/black/definition-entity.svg +6 -0
  38. package/src/assets/datatype-icons/black/key-file.svg +1 -0
  39. package/src/assets/datatype-icons/black/list.svg +3 -0
  40. package/src/assets/datatype-icons/black/null.svg +3 -0
  41. package/src/assets/datatype-icons/black/number.svg +13 -0
  42. package/src/assets/datatype-icons/black/project.svg +12 -0
  43. package/src/assets/datatype-icons/black/sql-program.svg +2 -0
  44. package/src/assets/datatype-icons/black/text.svg +3 -0
  45. package/src/assets/datatype-icons/black/unknown.svg +3 -0
  46. package/src/assets/datatype-icons/black/uuid.svg +4 -0
  47. package/src/assets/datatype-icons/black/void.svg +1 -0
  48. package/src/assets/datatype-icons/dark-grey/any.svg +1 -0
  49. package/src/assets/datatype-icons/dark-grey/boolean.svg +3 -0
  50. package/src/assets/datatype-icons/dark-grey/date-time.svg +3 -0
  51. package/src/assets/datatype-icons/dark-grey/definition-entity.svg +6 -0
  52. package/src/assets/datatype-icons/dark-grey/list.svg +3 -0
  53. package/src/assets/datatype-icons/dark-grey/null.svg +3 -0
  54. package/src/assets/datatype-icons/dark-grey/number.svg +13 -0
  55. package/src/assets/datatype-icons/dark-grey/project.svg +12 -0
  56. package/src/assets/datatype-icons/dark-grey/sql-program.svg +2 -0
  57. package/src/assets/datatype-icons/dark-grey/text.svg +3 -0
  58. package/src/assets/datatype-icons/dark-grey/unknown.svg +3 -0
  59. package/src/assets/datatype-icons/dark-grey/uuid.svg +4 -0
  60. package/src/assets/datatype-icons/dark-grey/void.svg +1 -0
  61. package/src/assets/datatype-icons/light-grey/any.svg +1 -0
  62. package/src/assets/datatype-icons/light-grey/boolean.svg +3 -0
  63. package/src/assets/datatype-icons/light-grey/date-time.svg +3 -0
  64. package/src/assets/datatype-icons/light-grey/definition-entity.svg +6 -0
  65. package/src/assets/datatype-icons/light-grey/list.svg +3 -0
  66. package/src/assets/datatype-icons/light-grey/null.svg +3 -0
  67. package/src/assets/datatype-icons/light-grey/number.svg +13 -0
  68. package/src/assets/datatype-icons/light-grey/project.svg +12 -0
  69. package/src/assets/datatype-icons/light-grey/sql-program.svg +2 -0
  70. package/src/assets/datatype-icons/light-grey/text.svg +3 -0
  71. package/src/assets/datatype-icons/light-grey/unknown.svg +3 -0
  72. package/src/assets/datatype-icons/light-grey/uuid.svg +4 -0
  73. package/src/assets/datatype-icons/light-grey/void.svg +1 -0
  74. package/src/assets/edit.png +0 -0
  75. package/src/assets/execution.svg +13 -0
  76. package/src/assets/favicon.svg +14 -0
  77. package/src/assets/file-search.svg +1 -0
  78. package/src/assets/http-endpoint.png +0 -0
  79. package/src/assets/image-input-placeholder.png +0 -0
  80. package/src/assets/logo-full-word-white.png +0 -0
  81. package/src/assets/logo-full-word.png +0 -0
  82. package/src/assets/password.svg +85 -0
  83. package/src/assets/pencil.png +0 -0
  84. package/src/assets/publish-project-rich-icon-2.svg +1 -0
  85. package/src/assets/publish-project-rich-icon.svg +1 -0
  86. package/src/assets/relational-database.png +0 -0
  87. package/src/assets/resources.svg +3 -0
  88. package/src/assets/resume-icon-14px.png +0 -0
  89. package/src/assets/server.png +0 -0
  90. package/src/assets/small-status/checkmark.svg +4 -0
  91. package/src/assets/small-status/error.svg +4 -0
  92. package/src/assets/small-status/loading.svg +4 -0
  93. package/src/assets/small-status/skipped.svg +11 -0
  94. package/src/assets/sql-connection-config.svg +1 -0
  95. package/src/assets/sql-row-transformer.svg +1 -0
  96. package/src/assets/ssl-certificate-config.svg +1 -0
  97. package/src/assets/sync.svg +1 -0
  98. package/src/assets/testing-logic-icon.svg +1 -0
  99. package/src/assets/versions.svg +25 -0
  100. package/src/assets/visual-programming-icon.svg +1 -0
  101. package/src/assets/warning-sign-24px.png +0 -0
  102. package/src/auth/index.ts +318 -0
  103. package/src/components/DialogLoader.tsx +94 -0
  104. package/src/components/EntityDialogHeader.tsx +110 -0
  105. package/src/components/EntityDialogSectionHeader.tsx +214 -0
  106. package/src/components/GalleryAddExternalIntegrationInfoDialog.tsx +87 -0
  107. package/src/components/GenerateProjectStartingLogicPromptDialog.tsx +281 -0
  108. package/src/components/LegacyRouteRedirector.tsx +55 -0
  109. package/src/components/ProPlanChip.tsx +23 -0
  110. package/src/components/ReportBugDialog.tsx +412 -0
  111. package/src/components/RequestIntegrationAccessDialog.tsx +261 -0
  112. package/src/components/UseTemplateProjectDialog.tsx +193 -0
  113. package/src/components/WorkspaceLayout.tsx +152 -0
  114. package/src/components/animated-svg/AnimatedCheckmark.tsx +41 -0
  115. package/src/components/animated-svg/AnimatedCrossmark.tsx +51 -0
  116. package/src/components/animated-svg/AnimatedEmailSending.tsx +38 -0
  117. package/src/components/animated-svg/AnimatedLoading.tsx +72 -0
  118. package/src/components/animated-svg/animated-svg.css +239 -0
  119. package/src/components/canvas/Canvas.tsx +16 -0
  120. package/src/components/canvas/CreateEntityMenu.tsx +2020 -0
  121. package/src/components/canvas/canvas.css +10 -0
  122. package/src/components/canvas/create-entity-menu.css +579 -0
  123. package/src/components/canvas-search/CanvasSearch.tsx +501 -0
  124. package/src/components/canvas-search/canvas-search.css +126 -0
  125. package/src/components/canvas-settings-menu/CanvasSettingsMenuButton.tsx +515 -0
  126. package/src/components/canvas-settings-menu/canvas-settings-menu.css +96 -0
  127. package/src/components/circular-image-upload/CircularImageUpload.tsx +113 -0
  128. package/src/components/circular-image-upload/circular-image-upload.css +69 -0
  129. package/src/components/costs/CostsDialog.tsx +459 -0
  130. package/src/components/data-type/DataTypeBuilder.tsx +3127 -0
  131. package/src/components/data-type/data-type-builder.css +45 -0
  132. package/src/components/dialogs/BetaAcknowledgeDialog.tsx +43 -0
  133. package/src/components/dialogs/ComplexDataDialog.tsx +458 -0
  134. package/src/components/dialogs/CronBuilderDialog.tsx +2145 -0
  135. package/src/components/dialogs/ExternalIntegrationConnections.tsx +565 -0
  136. package/src/components/dialogs/JsonEditorDialog.tsx +1392 -0
  137. package/src/components/dialogs/StringEditorDialog.tsx +268 -0
  138. package/src/components/dialogs/argument-declaration/ArgumentDeclaration.tsx +1167 -0
  139. package/src/components/dialogs/argument-declaration/ArgumentDeclarationDialogContent.tsx +128 -0
  140. package/src/components/dialogs/beta-dialog.css +165 -0
  141. package/src/components/dialogs/condition/Condition.tsx +431 -0
  142. package/src/components/dialogs/condition/ConditionDialogContent.tsx +126 -0
  143. package/src/components/dialogs/definition-entity/DefinitionEntityDialogContent.tsx +973 -0
  144. package/src/components/dialogs/function-call/FunctionCall.tsx +442 -0
  145. package/src/components/dialogs/function-call/FunctionCallDialogContent.tsx +126 -0
  146. package/src/components/dialogs/function-declaration/FunctionDeclaration.tsx +926 -0
  147. package/src/components/dialogs/function-declaration/FunctionDeclarationDialogContent.tsx +124 -0
  148. package/src/components/dialogs/generating-project-starting-logic-overlay/GeneratingProjectStartingLogicOverlay.tsx +176 -0
  149. package/src/components/dialogs/generating-project-starting-logic-overlay/generating-project-starting-logic-overlay.css +13 -0
  150. package/src/components/dialogs/global-event/GlobalEvent.tsx +475 -0
  151. package/src/components/dialogs/global-event/GlobalEventDialogContent.tsx +126 -0
  152. package/src/components/dialogs/help/HelpDialog.tsx +217 -0
  153. package/src/components/dialogs/help/HelpDilalogHomeContent.tsx +178 -0
  154. package/src/components/dialogs/help/help-dialog.css +116 -0
  155. package/src/components/dialogs/help/help-icon/HelpIconButton.tsx +41 -0
  156. package/src/components/dialogs/help/help-icon/help-icon.css +9 -0
  157. package/src/components/dialogs/input-map/InputMap.tsx +635 -0
  158. package/src/components/dialogs/input-map/InputMapDialogContent.tsx +126 -0
  159. package/src/components/dialogs/json-editor-dialog.css +4 -0
  160. package/src/components/dialogs/loop/Loop.tsx +650 -0
  161. package/src/components/dialogs/loop/LoopDialogContent.tsx +122 -0
  162. package/src/components/dialogs/operation/Operation.tsx +440 -0
  163. package/src/components/dialogs/operation/OperationDialogContent.tsx +126 -0
  164. package/src/components/dialogs/output-map/OutputMap.tsx +536 -0
  165. package/src/components/dialogs/output-map/OutputMapDialogContent.tsx +126 -0
  166. package/src/components/dialogs/property/Property.tsx +1490 -0
  167. package/src/components/dialogs/property/PropertyDialogContent.tsx +106 -0
  168. package/src/components/dialogs/search-statement/ColumnSelector.tsx +334 -0
  169. package/src/components/dialogs/search-statement/ConditionBuilder.tsx +750 -0
  170. package/src/components/dialogs/search-statement/DataAggregationSection.tsx +621 -0
  171. package/src/components/dialogs/search-statement/DataSourceSelection.tsx +734 -0
  172. package/src/components/dialogs/search-statement/EntityMetadataSection.tsx +135 -0
  173. package/src/components/dialogs/search-statement/FilterConditionsSection.tsx +151 -0
  174. package/src/components/dialogs/search-statement/InlineInputMap.tsx +153 -0
  175. package/src/components/dialogs/search-statement/LiteralValue.tsx +616 -0
  176. package/src/components/dialogs/search-statement/MainSourceAndInputsSection.tsx +271 -0
  177. package/src/components/dialogs/search-statement/NestedSearchStatementBuilder.tsx +170 -0
  178. package/src/components/dialogs/search-statement/OutputFormatSection.tsx +1779 -0
  179. package/src/components/dialogs/search-statement/ResultsSection.tsx +344 -0
  180. package/src/components/dialogs/search-statement/SearchStatementBuilder.tsx +251 -0
  181. package/src/components/dialogs/search-statement/SearchStatementDialogContent.tsx +398 -0
  182. package/src/components/dialogs/search-statement/ValueSelector.tsx +766 -0
  183. package/src/components/dialogs/search-statement/search-statement-context.tsx +1630 -0
  184. package/src/components/dialogs/search-statement/search-statement-dialog.css +56 -0
  185. package/src/components/dialogs/search-statement/test.sql +111 -0
  186. package/src/components/dialogs/value-descriptor/ValueDescriptor.tsx +824 -0
  187. package/src/components/dialogs/value-descriptor/ValueDescriptorDialogContent.tsx +124 -0
  188. package/src/components/dialogs/variable-declaration/VariableDeclaration.tsx +836 -0
  189. package/src/components/dialogs/variable-declaration/VariableDeclarationDialogContent.tsx +106 -0
  190. package/src/components/dialogs/variable-instance/VariableInstance.tsx +443 -0
  191. package/src/components/dialogs/variable-instance/VariableInstanceDialogContent.tsx +124 -0
  192. package/src/components/draggable-entity-card/ArgumentDeclaration.tsx +736 -0
  193. package/src/components/draggable-entity-card/CollapseEntityButton.tsx +170 -0
  194. package/src/components/draggable-entity-card/ConditionCard.tsx +1062 -0
  195. package/src/components/draggable-entity-card/ConnectionDeleteButton.tsx +309 -0
  196. package/src/components/draggable-entity-card/DataTypeIcon.tsx +624 -0
  197. package/src/components/draggable-entity-card/DraggableEntityCard.tsx +617 -0
  198. package/src/components/draggable-entity-card/ErrorMapProperty.tsx +464 -0
  199. package/src/components/draggable-entity-card/EventCard.tsx +700 -0
  200. package/src/components/draggable-entity-card/ExecutionInProgressValue.tsx +327 -0
  201. package/src/components/draggable-entity-card/FunctionDeclarationCard.tsx +819 -0
  202. package/src/components/draggable-entity-card/InputMapProperty.tsx +1067 -0
  203. package/src/components/draggable-entity-card/InternalCall.tsx +978 -0
  204. package/src/components/draggable-entity-card/InternalCallExecutionNode.tsx +643 -0
  205. package/src/components/draggable-entity-card/LogicScopeCallerNode.tsx +262 -0
  206. package/src/components/draggable-entity-card/LoopCard.tsx +791 -0
  207. package/src/components/draggable-entity-card/MainValueInput.tsx +523 -0
  208. package/src/components/draggable-entity-card/MainValueOutput.tsx +458 -0
  209. package/src/components/draggable-entity-card/MethodDeclaration.tsx +1088 -0
  210. package/src/components/draggable-entity-card/NestedCondition.tsx +1025 -0
  211. package/src/components/draggable-entity-card/OutputMapProperty.tsx +843 -0
  212. package/src/components/draggable-entity-card/PassthroughEntityCard.tsx +1247 -0
  213. package/src/components/draggable-entity-card/ReturnedError.tsx +549 -0
  214. package/src/components/draggable-entity-card/SmallSuccessFailureNodes.tsx +523 -0
  215. package/src/components/draggable-entity-card/SuccessFailureNodes.tsx +509 -0
  216. package/src/components/draggable-entity-card/TestEntityButton.tsx +946 -0
  217. package/src/components/draggable-entity-card/TestMenu.tsx +523 -0
  218. package/src/components/draggable-entity-card/TestMenuValidationDropdown.tsx +84 -0
  219. package/src/components/draggable-entity-card/UnreachableMarker.tsx +114 -0
  220. package/src/components/draggable-entity-card/VariableCard.tsx +1577 -0
  221. package/src/components/draggable-entity-card/VariableScopeMarker.tsx +117 -0
  222. package/src/components/draggable-entity-card/collapse-entity-button.css +44 -0
  223. package/src/components/draggable-entity-card/definition-entity/DefinitionEntityCard.tsx +1181 -0
  224. package/src/components/draggable-entity-card/definition-entity/DefinitionEntityIcon.tsx +36 -0
  225. package/src/components/draggable-entity-card/definition-entity/DefinitionEntityProperty.tsx +478 -0
  226. package/src/components/draggable-entity-card/definition-entity/DynamicFooterActions.tsx +112 -0
  227. package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/ExportCredentialsFooterAction.tsx +461 -0
  228. package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/RestablishConnectionFooterAction.tsx +199 -0
  229. package/src/components/draggable-entity-card/definition-entity/actions/external-integration-connection/restablish-connection-footer-action.css +85 -0
  230. package/src/components/draggable-entity-card/definition-entity/actions/google-drive/GoogleDriveFilePickerAPIFooterAction.tsx +277 -0
  231. package/src/components/draggable-entity-card/definition-entity/actions/google-drive/google-drive-file-picker-api-footer-action.css +107 -0
  232. package/src/components/draggable-entity-card/definition-entity/actions/persisted-entity/DatabaseFooterAction.tsx +452 -0
  233. package/src/components/draggable-entity-card/definition-entity/actions/persisted-entity/database-footer-action.css +86 -0
  234. package/src/components/draggable-entity-card/definition-entity/definition-entity-card.css +17 -0
  235. package/src/components/draggable-entity-card/draggable-entity-card.css +1140 -0
  236. package/src/components/draggable-entity-card/entity-locked-icon/EntityLockedIcon.tsx +133 -0
  237. package/src/components/draggable-entity-card/entity-locked-icon/entity-locked.css +8 -0
  238. package/src/components/draggable-entity-card/expand-properties-icon-button/ExpandPropertiesIconButton.tsx +84 -0
  239. package/src/components/draggable-entity-card/expand-properties-icon-button/expand-properties-icon-button.css +21 -0
  240. package/src/components/draggable-entity-card/implement-entity-icon/ImplementEntityIcon.tsx +74 -0
  241. package/src/components/draggable-entity-card/implement-entity-icon/implement-entity-icon.css +13 -0
  242. package/src/components/draggable-entity-card/logic-error/LogicErrorIconMenu.tsx +424 -0
  243. package/src/components/draggable-entity-card/logic-error/logic-error.css +23 -0
  244. package/src/components/draggable-entity-card/new-card-input-button/NewCardInputButton.tsx +193 -0
  245. package/src/components/draggable-entity-card/new-card-input-button/NewDynamicInputButton.tsx +214 -0
  246. package/src/components/draggable-entity-card/new-card-input-button/new-card-input-button.css +71 -0
  247. package/src/components/draggable-entity-card/new-card-output-button/NewCardOutputButton.tsx +192 -0
  248. package/src/components/draggable-entity-card/new-card-output-button/new-card-output-button.css +71 -0
  249. package/src/components/draggable-entity-card/termination-statement/TerminationStatementCard.tsx +1543 -0
  250. package/src/components/draggable-entity-card/termination-statement/termination-statement-card.css +17 -0
  251. package/src/components/draggable-entity-card/test-entity-button.css +55 -0
  252. package/src/components/draggable-entity-card/test-menu.css +181 -0
  253. package/src/components/draggable-entity-card/unreachable-marker.css +43 -0
  254. package/src/components/draggable-entity-card/variable-scope-marker.css +22 -0
  255. package/src/components/dynamic-value/DynamicValue.tsx +2395 -0
  256. package/src/components/dynamic-value/DynamicValueEntry.tsx +1957 -0
  257. package/src/components/dynamic-value/dynamic-value.css +230 -0
  258. package/src/components/editor/ElyxMonacoEditor.tsx +38 -0
  259. package/src/components/entity-error/EntityErrorListItem.tsx +47 -0
  260. package/src/components/entity-error/entity-error.css +198 -0
  261. package/src/components/entity-icon/EntityIcon.tsx +292 -0
  262. package/src/components/entity-icon/entity-icon.css +39 -0
  263. package/src/components/gallery-card/CreateNewProject.tsx +222 -0
  264. package/src/components/gallery-card/GalleryCard.tsx +171 -0
  265. package/src/components/gallery-card/MarketplaceCard.tsx +87 -0
  266. package/src/components/gallery-card/ProjectDuplicationCard.tsx +575 -0
  267. package/src/components/gallery-card/gallery-card.css +25 -0
  268. package/src/components/notifications/NotificationsIconButton.tsx +124 -0
  269. package/src/components/notifications/NotificationsPanel.tsx +385 -0
  270. package/src/components/notifications/notifications.css +189 -0
  271. package/src/components/online-users/LocalOnlineUsers.tsx +175 -0
  272. package/src/components/online-users/PageOnlineUsers.tsx +297 -0
  273. package/src/components/online-users/online-users.css +72 -0
  274. package/src/components/page-backdrop/PageBackdrop.tsx +8 -0
  275. package/src/components/page-backdrop/page-backdrop.css +7 -0
  276. package/src/components/project-configuration/DeleteProjectConfirmationDialog.tsx +134 -0
  277. package/src/components/project-configuration/ProjectConfigurationDialog.tsx +972 -0
  278. package/src/components/project-configuration/ProjectDataForm.tsx +121 -0
  279. package/src/components/project-configuration/UnpublishProjectConfirmationDialog.tsx +162 -0
  280. package/src/components/project-configuration/project-configuration-content.css +209 -0
  281. package/src/components/project-name/ProjectName.tsx +2025 -0
  282. package/src/components/project-name/project-name.css +599 -0
  283. package/src/components/publishing/Publication.tsx +133 -0
  284. package/src/components/publishing/history/PublicationHistoryContent.tsx +414 -0
  285. package/src/components/publishing/history/PublicationHistoryDialog.tsx +234 -0
  286. package/src/components/publishing/preview/PublicationPreviewDialog.tsx +1158 -0
  287. package/src/components/publishing/preview/PublishingPriceForecast.tsx +160 -0
  288. package/src/components/publishing/preview/PublishingResourcesDetails.tsx +91 -0
  289. package/src/components/publishing/publication-sequence/PublishingSequenceContent.tsx +375 -0
  290. package/src/components/publishing/publication-sequence/PublishingSequenceDialog.tsx +344 -0
  291. package/src/components/publishing/publishing-dialog.css +142 -0
  292. package/src/components/publishing/utils.ts +227 -0
  293. package/src/components/resources/ResourcesDialog.tsx +591 -0
  294. package/src/components/resources/UpgradeBanner.tsx +102 -0
  295. package/src/components/resources/codebase/CodebaseDetails.tsx +156 -0
  296. package/src/components/resources/cron-job/CronJobsList.tsx +532 -0
  297. package/src/components/resources/functions/FunctionsList.tsx +454 -0
  298. package/src/components/resources/http-api/HttpAPI.tsx +566 -0
  299. package/src/components/resources/http-api/HttpAPIClientModule.tsx +37 -0
  300. package/src/components/resources/logs/LogsViewer.tsx +768 -0
  301. package/src/components/resources/query.ts +74 -0
  302. package/src/components/resources/relational-database/DatabaseTable.tsx +905 -0
  303. package/src/components/resources/relational-database/RelationalDatabase.tsx +83 -0
  304. package/src/components/resources/relational-database/RelationalDatabaseSecrets.tsx +361 -0
  305. package/src/components/resources/resources-dialog.css +74 -0
  306. package/src/components/test-relational-database/DatabaseTable.tsx +913 -0
  307. package/src/components/test-relational-database/TestDatabaseDialogContent.tsx +670 -0
  308. package/src/components/test-relational-database/query.ts +74 -0
  309. package/src/components/toolbar/ToolBar.tsx +236 -0
  310. package/src/components/toolbar/toolbar.css +78 -0
  311. package/src/components/transaction-history/TransactionHistoryDialog.tsx +268 -0
  312. package/src/components/user/CurrentUserAvatar.tsx +65 -0
  313. package/src/components/user/UserChip.tsx +62 -0
  314. package/src/components/user/user.css +39 -0
  315. package/src/components/user-profile/ChangePasswordForm.tsx +67 -0
  316. package/src/components/user-profile/OwnUserProfileContent.tsx +665 -0
  317. package/src/components/user-profile/PublicUserProfileContent.tsx +99 -0
  318. package/src/components/user-profile/UserDataForm.tsx +75 -0
  319. package/src/components/user-profile/UserProfileDialog.tsx +110 -0
  320. package/src/components/user-profile/user-profile-content.css +25 -0
  321. package/src/config.ts +130 -0
  322. package/src/globals.d.ts +13 -0
  323. package/src/index.html +27 -0
  324. package/src/index.tsx +23 -0
  325. package/src/lib/badge/Badge.tsx +35 -0
  326. package/src/lib/badge/badge.css +32 -0
  327. package/src/lib/button/Button.tsx +129 -0
  328. package/src/lib/button/button.css +145 -0
  329. package/src/lib/canvas/canvas-undo-redo.ts +263 -0
  330. package/src/lib/canvas/defs.ts +170 -0
  331. package/src/lib/canvas/index.test.ts +189 -0
  332. package/src/lib/canvas/index.ts +6999 -0
  333. package/src/lib/canvas/utils.ts +59 -0
  334. package/src/lib/card/Card.tsx +62 -0
  335. package/src/lib/card/LoadingCard.tsx +82 -0
  336. package/src/lib/card/card.css +259 -0
  337. package/src/lib/chip/Chip.tsx +79 -0
  338. package/src/lib/chip/chip.css +0 -0
  339. package/src/lib/dialog/Dialog.tsx +122 -0
  340. package/src/lib/dialog/SmallDialog.tsx +61 -0
  341. package/src/lib/dialog/dialog.css +40 -0
  342. package/src/lib/display-data-structure/index.tsx +21 -0
  343. package/src/lib/dropdown/CanvasDropdownMenuCard.tsx +68 -0
  344. package/src/lib/dropdown/CanvasDropdownMenuCardOption.tsx +136 -0
  345. package/src/lib/dropdown/DropdownButton.tsx +104 -0
  346. package/src/lib/dropdown/DropdownMenuCard.tsx +324 -0
  347. package/src/lib/dropdown/DropdownMenuPopup.tsx +27 -0
  348. package/src/lib/dropdown/dropdown-button.css +76 -0
  349. package/src/lib/dropdown/dropdown-menu.css +151 -0
  350. package/src/lib/json-editor/RawJsonEditor.tsx +137 -0
  351. package/src/lib/json-editor/json-editor.css +35 -0
  352. package/src/lib/loader/Loader.tsx +120 -0
  353. package/src/lib/loader/loader.css +38 -0
  354. package/src/lib/pagination/Pagination.tsx +64 -0
  355. package/src/lib/popup/CanvasPopupBaseComponent.tsx +103 -0
  356. package/src/lib/popup/Popup.tsx +243 -0
  357. package/src/lib/popup/popup.css +16 -0
  358. package/src/lib/table/RowForm.tsx +301 -0
  359. package/src/lib/table/Table.tsx +1069 -0
  360. package/src/lib/table/table.css +249 -0
  361. package/src/lib/table/types.ts +108 -0
  362. package/src/lib/text-area/TextArea.tsx +183 -0
  363. package/src/lib/text-area/text-area.css +156 -0
  364. package/src/lib/text-field/TextField.tsx +218 -0
  365. package/src/lib/text-field/index.ts +8 -0
  366. package/src/lib/text-field/text-field.css +201 -0
  367. package/src/lib/tooltip/Tooltip.tsx +24 -0
  368. package/src/lib/tooltip/tooltip.css +17 -0
  369. package/src/localization/index.ts +47 -0
  370. package/src/main.css +343 -0
  371. package/src/pages/Auth.tsx +848 -0
  372. package/src/pages/Editor.tsx +883 -0
  373. package/src/pages/ErrorPage.tsx +179 -0
  374. package/src/pages/Gallery.tsx +1693 -0
  375. package/src/pages/NewPaymentMethodCallback.tsx +53 -0
  376. package/src/pages/NotFoundPage.tsx +126 -0
  377. package/src/pages/PricingPlans.tsx +155 -0
  378. package/src/pages/auth.css +304 -0
  379. package/src/pages/gallery.css +421 -0
  380. package/src/payments/index.ts +187 -0
  381. package/src/popup-notification/index.ts +90 -0
  382. package/src/services/database/index.ts +1 -0
  383. package/src/services/database/utils.ts +1301 -0
  384. package/src/services/editor/CanvasElement.tsx +2934 -0
  385. package/src/services/editor/CanvasElementConnectionDeleteButton.ts +204 -0
  386. package/src/services/editor/CanvasPopup.tsx +749 -0
  387. package/src/services/editor/EditorService.ts +8157 -0
  388. package/src/services/editor/area.ts +1312 -0
  389. package/src/services/editor/connections.ts +1019 -0
  390. package/src/services/editor/create/condition.ts +25 -0
  391. package/src/services/editor/create/definition-entity.ts +29 -0
  392. package/src/services/editor/create/function-call.ts +25 -0
  393. package/src/services/editor/create/global-event.ts +33 -0
  394. package/src/services/editor/create/loop.ts +25 -0
  395. package/src/services/editor/create/operation.ts +30 -0
  396. package/src/services/editor/create/utils.ts +140 -0
  397. package/src/services/editor/create/variable-declaration.ts +135 -0
  398. package/src/services/editor/create/variable-instance.ts +100 -0
  399. package/src/services/editor/editor-ui-extensions-context.ts +43 -0
  400. package/src/services/editor/entities-metadata.json +9310 -0
  401. package/src/services/editor/icons.ts +1093 -0
  402. package/src/services/editor/index.ts +1 -0
  403. package/src/services/editor/layout.ts +102 -0
  404. package/src/services/editor/modules/built-in-function-implementations/base.ts +14 -0
  405. package/src/services/editor/modules/built-in-function-implementations/create-persisted-entity/index.ts +56 -0
  406. package/src/services/editor/modules/built-in-function-implementations/delete-persisted-entity/index.ts +55 -0
  407. package/src/services/editor/modules/built-in-function-implementations/index.ts +4 -0
  408. package/src/services/editor/modules/built-in-function-implementations/update-persisted-entity/index.ts +56 -0
  409. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/get-files.ts +183 -0
  410. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/list-drives.ts +124 -0
  411. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/list-root-folders.ts +125 -0
  412. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/smart-fetch-document.ts +702 -0
  413. package/src/services/editor/modules/operations-implementations/external-integrations/google-drive/upload-document.ts +535 -0
  414. package/src/services/editor/modules/operations-implementations/external-integrations/google-gemini/generate-content.ts +193 -0
  415. package/src/services/editor/modules/operations-implementations/external-integrations/google-mail/get-emails.ts +586 -0
  416. package/src/services/editor/modules/operations-implementations/external-integrations/google-mail/send-email.ts +386 -0
  417. package/src/services/editor/modules/operations-implementations/external-integrations/index.ts +12 -0
  418. package/src/services/editor/modules/operations-implementations/external-integrations/slack/channels.ts +240 -0
  419. package/src/services/editor/modules/operations-implementations/external-integrations/slack/messages.ts +210 -0
  420. package/src/services/editor/modules/operations-implementations/external-integrations/slack/replies.ts +200 -0
  421. package/src/services/editor/modules/operations-implementations/external-integrations/slack/send-message.ts +177 -0
  422. package/src/services/editor/modules/operations-implementations/index.ts +1 -0
  423. package/src/services/editor/modules/search-node-implementation/index.ts +42 -0
  424. package/src/services/editor/modules/sql-migrations-generation.tsx +1054 -0
  425. package/src/services/editor/publication/publication.ts +578 -0
  426. package/src/services/editor/ui.ts +1348 -0
  427. package/src/services/editor/utils.ts +5868 -0
  428. package/src/services/editor/value-store.ts +619 -0
  429. package/src/services/execution/built-in-function-implementations.ts +422 -0
  430. package/src/services/execution/index.ts +4747 -0
  431. package/src/services/execution/logic.ts +121 -0
  432. package/src/services/execution/test-instance.tsx +2296 -0
  433. package/src/services/execution/utils.ts +33 -0
  434. package/src/services/execution/value-resolution.test.ts +424 -0
  435. package/src/services/execution/value-resolution.ts +4087 -0
  436. package/src/services/integrations/ExternalIntegrationsService.ts +439 -0
  437. package/src/services/integrations/api.ts +175 -0
  438. package/src/services/local-relational-database/idb_helper.ts +66 -0
  439. package/src/services/local-relational-database/index.ts +3308 -0
  440. package/src/services/local-relational-database/utils.ts +403 -0
  441. package/src/services/notifications/index.ts +525 -0
  442. package/src/services/user/index.ts +144 -0
  443. package/src/setupTests.ts +1 -0
  444. package/src/socket/socket.ts +248 -0
  445. package/src/socket/utils.ts +10 -0
  446. package/src/store/workspace.ts +12 -0
  447. package/src/theme.ts +19 -0
  448. package/src/utils/DOM.ts +39 -0
  449. package/src/utils/date.ts +169 -0
  450. package/src/utils/index.ts +158 -0
  451. package/src/utils/react.tsx +679 -0
  452. package/src/utils/testing.ts +103 -0
@@ -0,0 +1,1630 @@
1
+ import React, {
2
+ createContext,
3
+ ReactNode,
4
+ useContext,
5
+ useEffect,
6
+ useMemo,
7
+ useState
8
+ } from 'react';
9
+ import {
10
+ EntityId,
11
+ EntityType,
12
+ ProjectState,
13
+ SearchState,
14
+ ChangeSet,
15
+ SQLAST as SQLASTLib,
16
+ searchStatementState as searchStatementStateLib,
17
+ SQLAST,
18
+ searchStatementUtils,
19
+ syncSearchEntityOutput,
20
+ searchStatementDefs,
21
+ StateMutationAction
22
+ } from '@elyx-code/project-logic-tree';
23
+ import { EditorService } from '../../../services/editor';
24
+ import { IDialogProps } from '../../../lib/dialog/Dialog';
25
+ import { useParams } from 'react-router-dom';
26
+ import { Database } from '../../../services/local-relational-database';
27
+ import { popupNotification } from '../../../popup-notification';
28
+ import { Logger } from '@elyx-code/common-ts-utils';
29
+
30
+ const { parse, cstVisitor } = SQLASTLib;
31
+ const { SearchStatementLiteralValue } = searchStatementStateLib;
32
+
33
+ const { SearchStatementNodeType, SearchLiteralValueType } = searchStatementDefs;
34
+
35
+ type AggregationStatement = searchStatementStateLib.AggregationStatement;
36
+ type AllColumnsSelector = searchStatementStateLib.AllColumnsSelector;
37
+ type FunctionCall = searchStatementStateLib.FunctionCall;
38
+ type ColumnRef = searchStatementStateLib.ColumnRef;
39
+ type DataSource = searchStatementStateLib.DataSource;
40
+ type SearchStatementLiteralValue =
41
+ searchStatementStateLib.SearchStatementLiteralValue;
42
+ type ValueRef = searchStatementStateLib.ValueRef;
43
+ type SearchStatementState = searchStatementStateLib.SearchStatementState;
44
+ type SortStatement = searchStatementStateLib.SortStatement;
45
+ type WhereStatement = searchStatementStateLib.WhereStatement;
46
+ type SearchLiteralValueType = searchStatementDefs.SearchLiteralValueType;
47
+
48
+ type SQLAST = SQLASTLib.Program;
49
+ type SqlAstNode = SQLASTLib.Node;
50
+
51
+ const testQuery = `-- Select specific columns from the Employee table
52
+ SELECT
53
+ e.identifier AS EmployeeID,
54
+ e.department,
55
+ e.startDate,
56
+ m.identifier AS ManagerID,
57
+ m.department AS ManagerDepartment,
58
+ m.startDate AS ManagerStartDate
59
+ FROM
60
+ Employee e
61
+ LEFT JOIN
62
+ Employee m ON e.manager = m.identifier
63
+ WHERE
64
+ -- Filter: Search for a specific employee by their UUID
65
+ e.identifier = 'your-employee-uuid'
66
+ -- Additional Filter: Employees that belong to a specific department
67
+ AND e.department = 'Sales'
68
+ -- Additional Filter: Employees who started after a certain date
69
+ AND e.startDate > '2022-01-01'
70
+ ORDER BY
71
+ -- Sorting: Sort employees by their start date, descending
72
+ e.startDate DESC,
73
+ -- Sorting: Sort by department alphabetically after start date
74
+ e.department ASC
75
+ LIMIT
76
+ -- Limit the results to 10 employees
77
+ 10
78
+ OFFSET
79
+ -- Skip the first 2 employees
80
+ 2;
81
+ `;
82
+
83
+ const testQuery2 = `select * from Employee;`;
84
+
85
+ const testQuery3 = `-- Select specific columns from the Employee table
86
+ SELECT
87
+ Employee.identifier AS EmployeeID,
88
+ Employee.department,
89
+ Employee.startDate,
90
+ m.identifier AS ManagerID,
91
+ m.department AS ManagerDepartment,
92
+ m.startDate AS ManagerStartDate
93
+ FROM
94
+ Employee
95
+ LEFT JOIN
96
+ Employee m ON Employee.manager = m.identifier
97
+ WHERE
98
+ -- Filter: Search for a specific employee by their UUID
99
+ Employee.identifier = 'your-employee-uuid'
100
+ -- Additional Filter: Employees that belong to a specific department
101
+ AND Employee.department = 'Sales'
102
+ -- Additional Filter: Employees who started after a certain date
103
+ AND Employee.startDate > '2022-01-01'
104
+ ORDER BY
105
+ -- Sorting: Sort employees by their start date, descending
106
+ Employee.startDate DESC,
107
+ -- Sorting: Sort by department alphabetically after start date
108
+ Employee.department ASC
109
+ LIMIT
110
+ -- Limit the results to 10 employees
111
+ 10
112
+ OFFSET
113
+ -- Skip the first 2 employees
114
+ 2;
115
+ `;
116
+
117
+ const testQuery4 = `SELECT *
118
+ from Employee
119
+ ORDER BY startDate desc, department asc
120
+ limit 10 offset 2`;
121
+
122
+ const testQuery5 = `SELECT
123
+ Employee.identifier AS EmployeeID
124
+ from Employee
125
+ ORDER BY startDate desc, department asc
126
+ limit 10 offset 2`;
127
+
128
+ const testQuery6 = `SELECT
129
+ Employee.identifier AS EmployeeID,
130
+ User.identifier AS UserID
131
+ from Employee
132
+ INNER JOIN User ON
133
+ Employee.manager=User.identifier
134
+ ORDER BY Employee.startDate desc, Employee.department asc
135
+ limit 10 offset 2`;
136
+
137
+ const testQuery7 = `SELECT
138
+ Employee.identifier AS EmployeeID,
139
+ User.identifier AS userID
140
+ from Employee
141
+ INNER JOIN User ON
142
+ Employee.manager=User.identifier
143
+ limit 10 offset 0`;
144
+
145
+ const testQuery8 = `SELECT
146
+ Employee.identifier AS EmployeeID,
147
+ Employee.startDate AS startDate,
148
+ User.identifier AS userID,
149
+ Employee.department as department_a
150
+ from Employee
151
+ INNER JOIN User ON
152
+ Employee.manager=User.identifier
153
+ ORDER BY Employee.startDate desc, Employee.department asc
154
+ limit 10 offset 0`;
155
+
156
+ const testQuery9 = `SELECT *
157
+ from Employee
158
+ ORDER BY startDate desc
159
+ limit 10 offset 0`;
160
+
161
+ const testQuery10 = `SELECT
162
+ Employee.identifier AS EmployeeID,
163
+ Employee.startDate AS startDate,
164
+ User.identifier AS userID
165
+ from
166
+ (SELECT
167
+ identifier AS EmployeeID,
168
+ manager,
169
+ startDate
170
+ FROM
171
+ Employee
172
+ WHERE
173
+ startDate > '2020-01-01' -- Example condition in subquery
174
+ ) AS e
175
+ INNER JOIN User ON
176
+ Employee.manager=User.identifier
177
+ ORDER BY Employee.startDate desc
178
+ limit 10 offset 0`;
179
+
180
+ const testQuery11 = `SELECT
181
+ Employee.identifier AS EmployeeID,
182
+ Employee.startDate AS startDate,
183
+ User.identifier AS userID,
184
+ Employee.manager,
185
+ Employee.department AS department_a,
186
+ ProductSub.product_identifier AS ProductID,
187
+ RandomTable.random_value AS RandomValue
188
+ FROM Employee
189
+ INNER JOIN User ON Employee.manager = User.identifier
190
+ LEFT JOIN (
191
+ SELECT identifier AS product_identifier, name
192
+ FROM Product
193
+ WHERE name LIKE 'a%'
194
+ ) AS ProductSub ON ProductSub.product_identifier = 'a'
195
+ CROSS JOIN (SELECT 'useless_value' AS random_value) AS RandomTable
196
+ CROSS JOIN (SELECT 'another_useless_value' AS another_useless_value) AS AnotherRandomTable
197
+ ORDER BY Employee.startDate DESC, Employee.department ASC
198
+ LIMIT 10 OFFSET 0`;
199
+
200
+ const testQuery12 = `SELECT
201
+ Employee.identifier AS EmployeeID,
202
+ Employee.startDate AS startDate,
203
+ User.identifier AS userID,
204
+ Employee.department AS department_a,
205
+ ProductSub.product_identifier AS ProductID,
206
+ RandomTable.random_value AS RandomValue
207
+ FROM Employee
208
+ LEFT JOIN (
209
+ SELECT identifier AS product_identifier, name
210
+ FROM Product
211
+ WHERE name LIKE 'a%'
212
+ -- ) AS ProductSub ON Employee.identifier = ProductSub.product_identifier
213
+ ) AS ProductSub ON ProductSub.product_identifier = 'a'
214
+ ORDER BY Employee.startDate DESC, Employee.department ASC
215
+ LIMIT 10 OFFSET 0`;
216
+
217
+ const testQuery13 = `SELECT
218
+ Employee.identifier AS EmployeeID,
219
+ Employee.startDate AS startDate,
220
+ User.identifier AS userID,
221
+ Employee.department AS department_a
222
+ FROM Employee
223
+ INNER JOIN User ON Employee.manager = User.identifier
224
+ ORDER BY Employee.startDate DESC, Employee.department ASC
225
+ LIMIT 10 OFFSET 0`;
226
+
227
+ const testQuery14 = `SELECT
228
+ identifier AS product_identifier,
229
+ name
230
+ FROM Product
231
+ WHERE name LIKE 'a';`;
232
+
233
+ const testQuery15 = `SELECT
234
+ Employee.identifier AS EmployeeID,
235
+ Employee.startDate AS startDate,
236
+ User.identifier AS userID,
237
+ Employee.manager,
238
+ Employee.department AS department_a,
239
+ ProductSub.product_identifier AS ProductID,
240
+ RandomTable.random_value AS RandomValue
241
+ FROM Employee
242
+ INNER JOIN User ON Employee.manager = User.identifier
243
+ LEFT JOIN (
244
+ SELECT identifier AS product_identifier, name
245
+ FROM Product
246
+ WHERE name LIKE 'a%'
247
+ ) AS ProductSub ON ProductSub.product_identifier = 'a'
248
+ CROSS JOIN (SELECT 'useless_value' AS random_value) AS RandomTable
249
+ CROSS JOIN (SELECT 'another_useless_value' AS another_useless_value) AS AnotherRandomTable
250
+ WHERE
251
+ Employee.department = 'Sales'
252
+ AND Employee.startDate >= '2020-01-01'
253
+ AND Employee.manager IS NOT NULL
254
+
255
+ -- OR condition with grouping
256
+ AND (
257
+ Employee.identifier IN (SELECT identifier FROM Employee WHERE department = 'Engineering')
258
+ OR Employee.identifier IN (SELECT identifier FROM Employee WHERE department = 'Marketing')
259
+ )
260
+
261
+ -- Nested conditions with OR and AND mixed
262
+ AND (
263
+ (RandomTable.random_value = 'useless_value' AND AnotherRandomTable.another_useless_value = 'another_useless_value')
264
+ OR
265
+ (Employee.department = 'HR' AND Employee.startDate < '2015-01-01')
266
+ )
267
+
268
+ -- Another OR group with nested conditions
269
+ AND (
270
+ ProductSub.product_identifier IS NOT NULL
271
+ OR (Employee.manager = User.identifier AND User.identifier IS NOT NULL)
272
+ )
273
+ ORDER BY Employee.startDate DESC, Employee.department ASC
274
+ LIMIT 10 OFFSET 0;`;
275
+
276
+ const testQuery16 = `SELECT
277
+ Employee.identifier AS EmployeeID,
278
+ Employee.startDate AS startDate,
279
+ User.identifier AS userID,
280
+ Employee.manager,
281
+ Employee.department AS department_a,
282
+ ProductSub.product_identifier AS ProductID,
283
+ RandomTable.random_value AS RandomValue
284
+ FROM Employee
285
+ INNER JOIN User ON Employee.manager = User.identifier
286
+ LEFT JOIN (
287
+ SELECT identifier AS product_identifier, name
288
+ FROM Product
289
+ WHERE name LIKE 'a%'
290
+ ) AS ProductSub ON ProductSub.product_identifier = 'a'
291
+ CROSS JOIN (SELECT 'useless_value' AS random_value) AS RandomTable
292
+ CROSS JOIN (SELECT 'another_useless_value' AS another_useless_value) AS AnotherRandomTable
293
+ WHERE
294
+ Employee.department = 'Sales'
295
+ AND Employee.startDate >= '2020-01-01'
296
+ ORDER BY Employee.startDate DESC, Employee.department ASC
297
+ LIMIT 10 OFFSET 0;`;
298
+
299
+ const testQuery17 = `SELECT
300
+ Employee.identifier AS EmployeeID,
301
+ Employee.startDate AS startDate,
302
+ User.identifier AS userID,
303
+ Employee.manager,
304
+ Employee.department AS department_a,
305
+ ProductSub.product_identifier AS ProductID,
306
+ RandomTable.random_value AS RandomValue
307
+ FROM Employee
308
+ INNER JOIN User ON Employee.manager = User.identifier
309
+ LEFT JOIN (
310
+ SELECT identifier AS product_identifier, name
311
+ FROM Product
312
+ WHERE name LIKE 'a%'
313
+ ) AS ProductSub ON ProductSub.product_identifier = 'a'
314
+ CROSS JOIN (SELECT 'useless_value' AS random_value) AS RandomTable
315
+ CROSS JOIN (SELECT 'another_useless_value') AS AnotherRandomTable
316
+ WHERE
317
+ Employee.department = 'Sales'
318
+ AND Employee.startDate >= '2020-01-01'
319
+ AND Employee.manager IS NOT NULL
320
+ OR (Employee.manager = User.identifier AND User.identifier IS NOT NULL)
321
+ ORDER BY Employee.startDate DESC, Employee.department ASC
322
+ LIMIT 10 OFFSET 0;`;
323
+
324
+ const testQuery18 = `select *, Employee.* from Employee;`;
325
+
326
+ const testQuery19 = `select Something.*
327
+ from Something
328
+ LEFT JOIN Prod ON 1 = 1
329
+ where
330
+ Something.department = 'Sales';`;
331
+
332
+ // =============================================================================
333
+ // HEAVILY-NESTED FUNCTION FIXTURES — for layout stress-testing the search
334
+ // builder. Set OVERRIDE_TEST_QUERY (below) to one of these to bypass the
335
+ // entity's saved query and load a known-bad-layout case instead.
336
+ // =============================================================================
337
+
338
+ // Heavy scalar-function nesting in SELECT + WHERE.
339
+ // Exercises: nested calls in selection columns, function-of-function in WHERE.
340
+ const testQueryNestedScalars = `SELECT
341
+ UPPER(COALESCE(CONCAT(Employee.department, '-', LOWER(Employee.identifier)), 'NONE')) AS label,
342
+ CONCAT(UPPER(Employee.department), ' (', COALESCE(Employee.manager, 'no manager'), ')') AS departmentLine,
343
+ Employee.identifier AS EmployeeID
344
+ FROM Employee
345
+ WHERE LENGTH(COALESCE(Employee.manager, '')) > 0
346
+ AND UPPER(Employee.department) = UPPER('sales')
347
+ ORDER BY UPPER(Employee.department) ASC
348
+ LIMIT 10 OFFSET 0;`;
349
+
350
+ // Heavy table-valued function nesting in FROM + JOINs.
351
+ // Exercises: function as the main FROM source, multiple JOINs whose source
352
+ // is itself a function, an existing JOIN function call referenced via alias.
353
+ const testQueryNestedTableFunctions = `SELECT
354
+ Employee.identifier AS EmployeeID,
355
+ series.value AS seriesValue,
356
+ arr.value AS arrValue
357
+ FROM Employee
358
+ LEFT JOIN generate_series(1, 5, 1) AS series ON series.value > 0
359
+ LEFT JOIN unnest('[1,2,3]') AS arr ON arr.value = series.value
360
+ LEFT JOIN unnest(json_build_object('k', Employee.identifier)) AS payload ON 1 = 1
361
+ WHERE Employee.department = 'Sales'
362
+ ORDER BY Employee.identifier ASC
363
+ LIMIT 10 OFFSET 0;`;
364
+
365
+ // Mixes everything: nested scalars in SELECT, table-valued in FROM/JOIN,
366
+ // nested AND/OR in WHERE, ordering on a function expression.
367
+ const testQueryEverything = `SELECT
368
+ UPPER(COALESCE(Employee.department, 'UNKNOWN')) AS deptLabel,
369
+ CONCAT(Employee.identifier, '-', COALESCE(Employee.manager, 'root')) AS chain,
370
+ series.value AS seriesValue,
371
+ Product.name AS productName
372
+ FROM Employee
373
+ INNER JOIN User ON Employee.manager = User.identifier
374
+ LEFT JOIN Product ON Product.name LIKE 'a%'
375
+ LEFT JOIN generate_series(1, 3, 1) AS series ON series.value >= 1
376
+ LEFT JOIN unnest('[1,2]') AS arr ON arr.value = series.value
377
+ WHERE
378
+ UPPER(Employee.department) = 'SALES'
379
+ AND (
380
+ LENGTH(COALESCE(Employee.manager, '')) > 0
381
+ OR Employee.startDate >= '2020-01-01'
382
+ )
383
+ AND COALESCE(Product.name, '') != ''
384
+ ORDER BY UPPER(Employee.department) ASC, Employee.startDate DESC
385
+ LIMIT 25 OFFSET 0;`;
386
+
387
+ // Minimal: a single JOIN whose source is a table-valued function. The smallest
388
+ // fixture that exercises both the Merge-strategy alignment (function source =>
389
+ // tall data-source side) and the duplicate-`unnest` dedup in the dropdown.
390
+ const testQueryJoinFunction = `SELECT Employee.identifier AS EmployeeID
391
+ FROM Employee
392
+ LEFT JOIN unnest('[1,2,3]') AS arr ON 1 = 1;`;
393
+
394
+ // Deep scalar-function nesting on literals only — avoids any schema-dependent
395
+ // column refs that could fail hydration. The point is to render functions
396
+ // inside functions inside functions across SELECT, WHERE, and ORDER BY so we
397
+ // can see how the layout holds up at multiple nesting depths.
398
+ const testQueryDeepNestedFunctions = `SELECT
399
+ UPPER(COALESCE(LOWER('HELLO'), 'fallback')) AS msg1,
400
+ CONCAT(UPPER('a'), '-', LOWER('B'), '-', COALESCE('c', 'd')) AS msg2,
401
+ LENGTH(CONCAT(UPPER(LOWER('mixed')), '_', COALESCE('x', 'y'))) AS len1
402
+ FROM unnest('[1,2,3]') AS arr
403
+ WHERE LENGTH(COALESCE(UPPER('value'), '')) > 0
404
+ AND UPPER(LOWER('a')) = LOWER(UPPER('A'))
405
+ ORDER BY UPPER(LOWER('z')) ASC
406
+ LIMIT 5 OFFSET 0;`;
407
+
408
+ // Two unnest sources fed by JSON-array literal strings — exercises the array
409
+ // literal hydration path and gives the layout engine two parallel function
410
+ // data-sources to render side-by-side as JOINs.
411
+ const testQueryArrays = `SELECT a.value AS a_val, b.value AS b_val
412
+ FROM unnest('[1,2,3]') AS a
413
+ LEFT JOIN unnest('[4,5,6]') AS b ON a.value = b.value
414
+ WHERE a.value > 0
415
+ ORDER BY a.value ASC
416
+ LIMIT 10 OFFSET 0;`;
417
+
418
+ // Nested arrays via nested unnest calls — the inner unnest emits a row
419
+ // collection, then the outer unnest expands that. Layout-wise this is the
420
+ // most aggressive table-valued nesting we test.
421
+ const testQueryNestedArrays = `SELECT outer_arr.value AS v
422
+ FROM unnest('[[1,2],[3,4],[5,6]]') AS outer_arr
423
+ WHERE LENGTH(UPPER(COALESCE(LOWER('hello'), 'x'))) > 0
424
+ ORDER BY outer_arr.value ASC
425
+ LIMIT 5 OFFSET 0;`;
426
+
427
+ // Subquery in FROM (nested SELECT) + WHERE filter inside it. Exercises the
428
+ // nested-search-statement rendering and ensures the parent's calculateAst
429
+ // tolerates a child query that's actually populated.
430
+ const testQueryNestedSelect = `SELECT sub.identifier AS empId
431
+ FROM (
432
+ SELECT Employee.id AS identifier
433
+ FROM Employee
434
+ WHERE Employee.id IS NOT NULL
435
+ ) AS sub
436
+ ORDER BY sub.identifier ASC
437
+ LIMIT 5 OFFSET 0;`;
438
+
439
+ // "Everything bagel" — combines deep nested functions in SELECT and WHERE,
440
+ // a nested SELECT in FROM, an array-literal in a JOIN's unnest source, and
441
+ // ordering on a function expression. Useful for spotting layout regressions
442
+ // that only show up under combined load.
443
+ const testQueryEverythingBagel = `SELECT
444
+ UPPER(COALESCE(LOWER(sub.identifier), 'unknown')) AS upperId,
445
+ arr.value AS arrayValue
446
+ FROM (
447
+ SELECT Employee.id AS identifier
448
+ FROM Employee
449
+ WHERE Employee.id IS NOT NULL
450
+ ) AS sub
451
+ LEFT JOIN unnest('[1,2,3]') AS arr ON arr.value > 0
452
+ WHERE LENGTH(UPPER(COALESCE(sub.identifier, ''))) > 0
453
+ AND UPPER(LOWER('x')) != LOWER(UPPER('Y'))
454
+ ORDER BY UPPER(LOWER(sub.identifier)) ASC
455
+ LIMIT 10 OFFSET 0;`;
456
+
457
+ // External-input interpolation stress fixture. The dialog's saved Search
458
+ // entity has 7 input maps with the exact UUIDs below; each `{{::id}}`
459
+ // reference round-trips through hydrate → ValueRef → toQuery. Items below
460
+ // exercise interpolation in every position where a value can appear: SELECT
461
+ // projections (literal + function args), JOIN's array literal can't take an
462
+ // interpolation but the JOIN's ON RHS can, WHERE LHS/RHS, function args
463
+ // inside WHERE, ORDER BY (via a function expression), and LIMIT / OFFSET.
464
+ //
465
+ // Email (String) : efb7b373-bc11-4b5b-8035-720b82fdb9e6
466
+ // First number value (Number): 7a859d02-6c8a-490c-9dee-327300787808
467
+ // Second number value (Number): 4072c906-5937-4a0e-b4fb-51b4b1c74dc1
468
+ // Some boolean (Boolean) : 223f61d4-dd05-4cf7-9f21-957c41a44425
469
+ // Some external ID (UUID) : de00a2d7-7b63-4828-bce3-885aeea55dda
470
+ // External enum input (Enum): 9c3dd62b-2bcb-4341-bc3e-973db698a0f8
471
+ // Explicitly empty input (Null): ddf2890c-593a-4663-97ed-5d5efad86eb4
472
+ const testQueryInterpolationEverywhere = `SELECT
473
+ Employee.id AS empId,
474
+ '{{::efb7b373-bc11-4b5b-8035-720b82fdb9e6}}' AS emailLiteralProjection,
475
+ CONCAT('prefix-', '{{::efb7b373-bc11-4b5b-8035-720b82fdb9e6}}', '-suffix') AS labelWithEmail,
476
+ UPPER(COALESCE('{{::efb7b373-bc11-4b5b-8035-720b82fdb9e6}}', 'fallback')) AS upperEmail,
477
+ LENGTH('{{::9c3dd62b-2bcb-4341-bc3e-973db698a0f8}}') AS enumLength
478
+ FROM Employee
479
+ LEFT JOIN unnest('[1,2,3]') AS arr ON arr.value > '{{::7a859d02-6c8a-490c-9dee-327300787808}}'
480
+ WHERE Employee.id != '{{::de00a2d7-7b63-4828-bce3-885aeea55dda}}'
481
+ AND LENGTH('{{::efb7b373-bc11-4b5b-8035-720b82fdb9e6}}') > '{{::4072c906-5937-4a0e-b4fb-51b4b1c74dc1}}'
482
+ AND UPPER('{{::9c3dd62b-2bcb-4341-bc3e-973db698a0f8}}') != UPPER('placeholder')
483
+ ORDER BY UPPER(COALESCE('{{::efb7b373-bc11-4b5b-8035-720b82fdb9e6}}', '')) ASC
484
+ LIMIT '{{::7a859d02-6c8a-490c-9dee-327300787808}}'
485
+ OFFSET '{{::4072c906-5937-4a0e-b4fb-51b4b1c74dc1}}';`;
486
+
487
+ // Round-trip canary: a fixture that uses ONLY columns that exist on the real
488
+ // schema (Employee.id, not the non-existent Employee.identifier) so that
489
+ // hydrate → toQuery → re-hydrate preserves every field. Useful to spot
490
+ // regressions where the stringified SQL produces a shape the parser+hydrator
491
+ // can't reconstruct identically.
492
+ const testQueryRoundTripCanary = `SELECT
493
+ Employee.id AS empId,
494
+ UPPER(COALESCE(Employee.id, '')) AS upperId,
495
+ CONCAT(Employee.id, '-tag') AS taggedId
496
+ FROM Employee
497
+ LEFT JOIN unnest('[1,2,3]') AS arr ON 1 = 1
498
+ WHERE Employee.id IS NOT NULL
499
+ AND LENGTH(UPPER(Employee.id)) > 0
500
+ ORDER BY UPPER(Employee.id) ASC
501
+ LIMIT 10 OFFSET 0;`;
502
+
503
+ // =============================================================================
504
+ // Set this to one of the testQuery* constants above to bypass the saved
505
+ // entity query and load that fixture instead. Useful for stress-testing the
506
+ // dialog layout against intentionally-pathological queries. Leave at null to
507
+ // use the actual saved query.
508
+ // =============================================================================
509
+ const OVERRIDE_TEST_QUERY: string | null = null; // testQueryInterpolationEverywhere;
510
+
511
+ // Visits all nodes in the syntax tree and applies a callback to each node
512
+ // If the callback returns a value, the value will replace the node
513
+ // If the callback returns null, the node will be removed
514
+ // If the callback returns undefined, the node will be left as is
515
+ export function nodeVisitor(
516
+ node: SqlAstNode,
517
+ callbacks: {
518
+ beforeChildrenCallback?: (node: SqlAstNode) => SqlAstNode | null | void;
519
+ afterChildrenCallback?: (node: SqlAstNode) => SqlAstNode | null | void;
520
+ }
521
+ ): SqlAstNode | null | void {
522
+ if (!node) {
523
+ return;
524
+ }
525
+
526
+ const beforeCallbackResult = callbacks?.beforeChildrenCallback?.(node);
527
+
528
+ if (beforeCallbackResult === null) {
529
+ return null;
530
+ } else if (beforeCallbackResult) {
531
+ return beforeCallbackResult;
532
+ }
533
+
534
+ const keys: string[] = Object.keys(node);
535
+
536
+ keys.forEach((key) => {
537
+ // @ts-ignore
538
+ const value = node[key];
539
+
540
+ if (Array.isArray(value)) {
541
+ value.forEach((item, index) => {
542
+ if (item && typeof item === 'object') {
543
+ const newItem = nodeVisitor(item, callbacks);
544
+
545
+ if (newItem === null) {
546
+ value.splice(index, 1);
547
+ } else if (newItem) {
548
+ value[index] = newItem;
549
+ }
550
+ }
551
+ });
552
+ } else if (value && typeof value === 'object') {
553
+ const newValue = nodeVisitor(value, callbacks);
554
+
555
+ if (newValue === null) {
556
+ // @ts-ignore
557
+ delete node[key];
558
+ } else if (newValue) {
559
+ // @ts-ignore
560
+ node[key] = newValue;
561
+ }
562
+ }
563
+ });
564
+
565
+ return callbacks?.afterChildrenCallback?.(node);
566
+ }
567
+
568
+ // Recursively visits all nodes in the syntax tree and adds a uuid 'id' property to each node
569
+ export function addIdsToASTNodes(sqlAstNode: SqlAstNode) {
570
+ nodeVisitor(sqlAstNode, {
571
+ beforeChildrenCallback: (node) => {
572
+ const id = ProjectState.UUID.uuid();
573
+
574
+ // @ts-ignore
575
+ node.id = id;
576
+ }
577
+ });
578
+ }
579
+
580
+ // addIdsToASTNodes(cst);
581
+
582
+ // convert all keywords to uppercase
583
+ export const toUpper = cstVisitor({
584
+ keyword: (kw) => {
585
+ kw.text = kw.text.toUpperCase();
586
+ }
587
+ });
588
+
589
+ export const toLower = cstVisitor({
590
+ keyword: (kw) => {
591
+ kw.text = kw.text.toLowerCase();
592
+ }
593
+ });
594
+
595
+ export function replaceNode(
596
+ parentNode: SqlAstNode,
597
+ nodeToReplace: SqlAstNode,
598
+ newNode: SqlAstNode
599
+ ) {
600
+ nodeVisitor(parentNode, {
601
+ beforeChildrenCallback: (node) => {
602
+ if (
603
+ !!node &&
604
+ !!nodeToReplace &&
605
+ (node === nodeToReplace ||
606
+ // @ts-ignore
607
+ node?.id === nodeToReplace?.id)
608
+ ) {
609
+ return newNode;
610
+ }
611
+ }
612
+ });
613
+ }
614
+
615
+ export enum SearchStatementBuilderTabType {
616
+ MainSearchStatement = 'main-search-statement',
617
+ NewInputTab = 'new-input',
618
+ InputDeclarationTab = 'input-declaration-tab',
619
+ NestedQuery = 'nested-query'
620
+ }
621
+
622
+ export interface ISearchStatementTab {
623
+ entity: SearchStatementBuilderTabType;
624
+ // Any extra data that the tab might need
625
+ [key: string]: any;
626
+ }
627
+
628
+ export interface ITabManager {
629
+ addTab: (tab: ISearchStatementTab, navigate?: boolean) => void;
630
+ navigateToTab: (tab: ISearchStatementTab) => void;
631
+ navigateToTabIndex: (index: number) => void;
632
+ popTab: () => void;
633
+ }
634
+
635
+ export interface ISearchStatementBaseProps extends IDialogProps {
636
+ project: EditorService;
637
+ }
638
+
639
+ export interface ISearchStatementContext {
640
+ tabManager: ITabManager;
641
+ searchStatementState: SearchStatementState;
642
+ entity: SearchState;
643
+ dataSources: DataSource[];
644
+ selections: (ColumnRef | AllColumnsSelector | FunctionCall)[];
645
+ selectionsUpdateKey: number;
646
+ aggregations: AggregationStatement[];
647
+ aggregationsUpdateKey: number;
648
+ addAggregation: (value: AggregationStatement) => void;
649
+ removeAggregation: (value: AggregationStatement) => void;
650
+ editAggregation: (value: AggregationStatement) => void;
651
+ mainDataSource: DataSource | null;
652
+ setMainDataSource: (value: DataSource) => void;
653
+ setOffset: (value: SearchStatementLiteralValue | ValueRef) => void;
654
+ setLimit: (value: SearchStatementLiteralValue | ValueRef) => void;
655
+ setAsList: (value: boolean) => void;
656
+ sorting: SortStatement[];
657
+ sortingUpdateKey: number;
658
+ addSorting: (value: SortStatement) => void;
659
+ editSorting: (value: SortStatement) => void;
660
+ removeSorting: (value: SortStatement) => void;
661
+ addSelection: (
662
+ value: ColumnRef | AllColumnsSelector | FunctionCall
663
+ ) => void;
664
+ editSelection: (
665
+ value: ColumnRef | AllColumnsSelector | FunctionCall
666
+ ) => void;
667
+ removeSelection: (
668
+ value: ColumnRef | AllColumnsSelector | FunctionCall
669
+ ) => void;
670
+ resolveDatabaseClient: () => Database | null;
671
+ setWhere: (value: WhereStatement | null) => void;
672
+ where: WhereStatement | null;
673
+ whereUpdateKey: number;
674
+ offset: SearchStatementLiteralValue | ValueRef | null;
675
+ offsetUpdateKey: number;
676
+ limit: SearchStatementLiteralValue | ValueRef | null;
677
+ limitUpdateKey: number;
678
+ dataSourcesUpdateKey: number;
679
+ asList: boolean;
680
+ project: EditorService;
681
+ sqlAST: SQLAST | null;
682
+ hydrationReady: boolean;
683
+ isNested: boolean;
684
+ }
685
+
686
+ export const SearchStatementContext = createContext<ISearchStatementContext>({
687
+ tabManager: {
688
+ addTab: () => {},
689
+ navigateToTab: () => {},
690
+ navigateToTabIndex: () => {},
691
+ popTab: () => {}
692
+ },
693
+ searchStatementState: null,
694
+ entity: null,
695
+ dataSources: [],
696
+ selections: [],
697
+ selectionsUpdateKey: 0,
698
+ aggregations: [],
699
+ aggregationsUpdateKey: 0,
700
+ addAggregation: () => {},
701
+ removeAggregation: () => {},
702
+ editAggregation: () => {},
703
+ mainDataSource: null,
704
+ setMainDataSource: () => {},
705
+ setOffset: () => {},
706
+ setLimit: () => {},
707
+ setAsList: () => {},
708
+ sorting: [],
709
+ sortingUpdateKey: 0,
710
+ addSorting: () => {},
711
+ editSorting: () => {},
712
+ removeSorting: () => {},
713
+ addSelection: () => {},
714
+ editSelection: () => {},
715
+ removeSelection: () => {},
716
+ resolveDatabaseClient: () => null,
717
+ setWhere: () => {},
718
+ where: null,
719
+ whereUpdateKey: 0,
720
+ offset: null,
721
+ offsetUpdateKey: 0,
722
+ limit: null,
723
+ limitUpdateKey: 0,
724
+ dataSourcesUpdateKey: 0,
725
+ asList: true,
726
+ project: null,
727
+ sqlAST: null,
728
+ hydrationReady: false,
729
+ isNested: false
730
+ });
731
+
732
+ export const useSearchStatementContext = () => {
733
+ const context = useContext(SearchStatementContext);
734
+
735
+ if (!context) {
736
+ throw new Error(
737
+ 'useSearchStatementContext must be used within an SearchStatementProvider'
738
+ );
739
+ }
740
+
741
+ return context;
742
+ };
743
+
744
+ const SearchStatementProvider = ({
745
+ children,
746
+ project,
747
+ ready,
748
+ tabManager
749
+ }: {
750
+ children: ReactNode;
751
+ project: EditorService;
752
+ ready: boolean;
753
+ tabManager: ITabManager;
754
+ }) => {
755
+ const { entityId } = useParams<{
756
+ entityType: EntityType;
757
+ entityId: EntityId;
758
+ }>();
759
+
760
+ const entity: SearchState | null = project?.logic.get(
761
+ entityId
762
+ ) as SearchState | null;
763
+
764
+ const [sqlAST, _setSqlAST] = useState<SQLAST | null>(null);
765
+
766
+ const searchStatementState: SearchStatementState | null = useMemo(() => {
767
+ if (!entity || !project) {
768
+ return null;
769
+ }
770
+
771
+ // If an override fixture is set, use it in place of the entity's saved
772
+ // query so the builder loads with a controlled, complex test case.
773
+ const sourceQuery = OVERRIDE_TEST_QUERY ?? entity.query;
774
+
775
+ if (OVERRIDE_TEST_QUERY) {
776
+ Logger.warn(
777
+ '[SearchStatementProvider] Using OVERRIDE_TEST_QUERY instead of the saved entity query. Set it back to null to load real data.'
778
+ );
779
+ }
780
+
781
+ const sanitizedQuery =
782
+ searchStatementUtils.sanitizeQuery(sourceQuery) || '';
783
+
784
+ const initialAst = sanitizedQuery
785
+ ? parse(sanitizedQuery, {
786
+ dialect: 'sqlite'
787
+ })
788
+ : // Initializing the state with a default query
789
+ null;
790
+
791
+ const hydratedStateConfig =
792
+ searchStatementUtils.hydrateSearchStatementState(
793
+ initialAst,
794
+ project.logic,
795
+ entity
796
+ );
797
+
798
+ if (!!hydratedStateConfig.errors.length) {
799
+ popupNotification({
800
+ color: 'error',
801
+ text: `Error:\n${hydratedStateConfig.errors
802
+ .map(
803
+ (error) =>
804
+ `"${error.name}" ${
805
+ error.entity === 'table' ? 'entity' : 'property'
806
+ } not found`
807
+ )
808
+ .join('\n')}`,
809
+ delay: 4000
810
+ });
811
+ }
812
+
813
+ return hydratedStateConfig.state;
814
+ }, [project, entityId]);
815
+
816
+ const [dataSources, _setDataSources] = useState<DataSource[]>(
817
+ searchStatementState?.dataSources || []
818
+ );
819
+ const [dataSourcesUpdateKey, setDataSourcesUpdateKey] = useState(0);
820
+
821
+ const [where, _setWhere] = useState<WhereStatement | null>(
822
+ searchStatementState?.where || null
823
+ );
824
+ const [whereUpdateKey, setWhereUpdateKey] = useState(0);
825
+
826
+ const [selections, _setSelections] = useState<
827
+ (ColumnRef | AllColumnsSelector | FunctionCall)[]
828
+ >(searchStatementState?.selections || []);
829
+ const [selectionsUpdateKey, setSelectionsUpdateKey] = useState(0);
830
+
831
+ const [mainDataSource, _setMainDataSource] = useState<DataSource | null>(
832
+ searchStatementState?.from || null
833
+ );
834
+
835
+ const [aggregations, _setAggregations] = useState<AggregationStatement[]>(
836
+ searchStatementState?.aggregations || []
837
+ );
838
+ const [aggregationsUpdateKey, setAggregationsUpdateKey] = useState(0);
839
+
840
+ const [sorting, _setSorting] = useState<SortStatement[]>(
841
+ searchStatementState?.sorting || []
842
+ );
843
+ const [sortingUpdateKey, setSortingUpdateKey] = useState(0);
844
+
845
+ const [offset, _setOffset] = useState<
846
+ SearchStatementLiteralValue | ValueRef | null
847
+ >(searchStatementState?.offset || null);
848
+ const [offsetUpdateKey, setOffsetUpdateKey] = useState(0);
849
+
850
+ const [limit, _setLimit] = useState<
851
+ SearchStatementLiteralValue | ValueRef | null
852
+ >(searchStatementState?.limit || null);
853
+ const [limitUpdateKey, setLimitUpdateKey] = useState(0);
854
+
855
+ const [asList, _setAsList] = useState<boolean>(
856
+ searchStatementState?.asList || true
857
+ );
858
+
859
+ const [hydrationReady, setHydrationReady] = useState(false);
860
+
861
+ const setQueryAST = ({
862
+ ast,
863
+ query
864
+ }: {
865
+ ast: SQLAST | null;
866
+ query: string | null;
867
+ }) => {
868
+ // Don't persist broken intermediate states. `calculateAst` returns
869
+ // `ast: null` when the generated SQL string fails to re-parse — e.g.
870
+ // just after creating an empty nested-search that hasn't been
871
+ // configured yet. Writing that broken string into entity.query would
872
+ // poison it for the next hydration.
873
+ if (!ast) {
874
+ _setSqlAST(null);
875
+ return;
876
+ }
877
+
878
+ if (!!entity) {
879
+ const changeSet = project?.logic?.addChangeSet(
880
+ new ChangeSet(
881
+ project?.logic,
882
+ ProjectState.sessionAuthor,
883
+ new Date().toISOString(),
884
+ entity,
885
+ false,
886
+ StateMutationAction.ChangeSearchQuery
887
+ )
888
+ );
889
+
890
+ const sanitizedQuery =
891
+ searchStatementUtils.sanitizeQuery(query) || '';
892
+
893
+ entity?.metaSync({ query: sanitizedQuery }, changeSet);
894
+
895
+ if (
896
+ !!searchStatementState &&
897
+ searchStatementState.isValid &&
898
+ !!ast &&
899
+ !!sanitizedQuery
900
+ ) {
901
+ syncSearchEntityOutput(entity, searchStatementState, changeSet);
902
+ }
903
+
904
+ project.renderAndCloseChangeSet(changeSet);
905
+ }
906
+
907
+ _setSqlAST(ast);
908
+ };
909
+
910
+ useEffect(() => {
911
+ if (!searchStatementState) {
912
+ return;
913
+ }
914
+
915
+ if (searchStatementState.dataSources) {
916
+ _setDataSources(searchStatementState.dataSources);
917
+ }
918
+
919
+ const newAst = searchStatementState.calculateAst();
920
+
921
+ if (newAst) {
922
+ Logger.log('query before sanitization: ', entity.query);
923
+ const sanitizedQuery =
924
+ searchStatementUtils.sanitizeQuery(entity.query) || '';
925
+ Logger.log('sanitizedQuery: ', sanitizedQuery);
926
+ if (
927
+ (!!newAst.query && !sanitizedQuery) ||
928
+ (!newAst.query && !!sanitizedQuery) ||
929
+ (!!newAst.query &&
930
+ !!sanitizedQuery &&
931
+ newAst.query !== sanitizedQuery)
932
+ ) {
933
+ Logger.log('--- Setting query ---');
934
+ Logger.log('newAst.query: ', newAst.query);
935
+ Logger.log('entity query: ', sanitizedQuery);
936
+ setQueryAST(newAst);
937
+ }
938
+ }
939
+
940
+ if (!!searchStatementState.from) {
941
+ _setMainDataSource(searchStatementState.from);
942
+ }
943
+
944
+ _setWhere(searchStatementState.where);
945
+ _setOffset(searchStatementState.offset);
946
+ setOffsetUpdateKey((key) => key + 1);
947
+ _setLimit(searchStatementState.limit);
948
+ setLimitUpdateKey((key) => key + 1);
949
+ _setAsList(searchStatementState.asList);
950
+ _setAggregations(searchStatementState.aggregations);
951
+ _setSelections(searchStatementState.selections);
952
+ setSelectionsUpdateKey((key) => key + 1);
953
+ _setSorting(searchStatementState.sorting);
954
+
955
+ setHydrationReady(true);
956
+ }, [searchStatementState]);
957
+
958
+ const removeAggregation = (value: AggregationStatement) => {
959
+ searchStatementState.removeAggregation(value);
960
+ _setAggregations(searchStatementState.aggregations);
961
+ _setSelections(searchStatementState.selections);
962
+ _setSorting(searchStatementState.sorting);
963
+ _setWhere(searchStatementState.where);
964
+ setAggregationsUpdateKey((key) => key + 1);
965
+ setDataSourcesUpdateKey((key) => key + 1);
966
+ setSelectionsUpdateKey((key) => key + 1);
967
+ setSortingUpdateKey((key) => key + 1);
968
+ setWhereUpdateKey((key) => key + 1);
969
+
970
+ const newAst = searchStatementState.calculateAst();
971
+ setQueryAST(newAst);
972
+ };
973
+
974
+ const addAggregation = (value: AggregationStatement) => {
975
+ searchStatementState.addAggregation(value);
976
+ _setAggregations(searchStatementState.aggregations);
977
+ setAggregationsUpdateKey((key) => key + 1);
978
+ setDataSourcesUpdateKey((key) => key + 1);
979
+
980
+ const newAst = searchStatementState.calculateAst();
981
+ setQueryAST(newAst);
982
+ };
983
+
984
+ const editAggregation = (value: AggregationStatement) => {
985
+ searchStatementState.editAggregation(value);
986
+ _setAggregations(searchStatementState.aggregations);
987
+ setAggregationsUpdateKey((key) => key + 1);
988
+ setDataSourcesUpdateKey((key) => key + 1);
989
+
990
+ const newAst = searchStatementState.calculateAst();
991
+ setQueryAST(newAst);
992
+ };
993
+
994
+ const addSelection = (
995
+ value: ColumnRef | AllColumnsSelector | FunctionCall
996
+ ) => {
997
+ searchStatementState.addSelection(value);
998
+ _setSelections(searchStatementState.selections);
999
+ setSelectionsUpdateKey((key) => key + 1);
1000
+
1001
+ const newAst = searchStatementState.calculateAst();
1002
+ setQueryAST(newAst);
1003
+ };
1004
+
1005
+ const editSelection = (
1006
+ value: ColumnRef | AllColumnsSelector | FunctionCall
1007
+ ) => {
1008
+ searchStatementState.editSelection(value);
1009
+ _setSelections(searchStatementState.selections);
1010
+ setSelectionsUpdateKey((key) => key + 1);
1011
+
1012
+ const newAst = searchStatementState.calculateAst();
1013
+ setQueryAST(newAst);
1014
+ };
1015
+
1016
+ const removeSelection = (
1017
+ value: ColumnRef | AllColumnsSelector | FunctionCall
1018
+ ) => {
1019
+ searchStatementState.removeSelection(value);
1020
+ _setSelections(searchStatementState.selections);
1021
+ _setSorting(searchStatementState.sorting);
1022
+ setSelectionsUpdateKey((key) => key + 1);
1023
+ setSortingUpdateKey((key) => key + 1);
1024
+
1025
+ const newAst = searchStatementState.calculateAst();
1026
+ setQueryAST(newAst);
1027
+ };
1028
+
1029
+ const addSorting = (value: SortStatement) => {
1030
+ searchStatementState.addSort(value);
1031
+ _setSorting(searchStatementState.sorting);
1032
+
1033
+ const newAst = searchStatementState.calculateAst();
1034
+ setQueryAST(newAst);
1035
+ };
1036
+
1037
+ const editSorting = (value: SortStatement) => {
1038
+ searchStatementState.editSort(value);
1039
+ _setSorting(searchStatementState.sorting);
1040
+
1041
+ const newAst = searchStatementState.calculateAst();
1042
+ setQueryAST(newAst);
1043
+ };
1044
+
1045
+ const removeSorting = (value: SortStatement) => {
1046
+ searchStatementState.removeSort(value);
1047
+ _setSorting(searchStatementState.sorting);
1048
+ setSortingUpdateKey((key) => key + 1);
1049
+
1050
+ const newAst = searchStatementState.calculateAst();
1051
+ setQueryAST(newAst);
1052
+ };
1053
+
1054
+ const setMainDataSource = (value: DataSource | null) => {
1055
+ searchStatementState.setFrom(value);
1056
+ _setMainDataSource(value);
1057
+ _setSelections(searchStatementState.selections);
1058
+ _setSorting(searchStatementState.sorting);
1059
+ _setAggregations(searchStatementState.aggregations);
1060
+ setSelectionsUpdateKey((key) => key + 1);
1061
+ setSortingUpdateKey((key) => key + 1);
1062
+ setAggregationsUpdateKey((key) => key + 1);
1063
+
1064
+ const newAst = searchStatementState.calculateAst();
1065
+ setQueryAST(newAst);
1066
+ };
1067
+
1068
+ const setWhere = (value: WhereStatement | null) => {
1069
+ searchStatementState.where = value;
1070
+
1071
+ _setWhere(value);
1072
+ setWhereUpdateKey((key) => key + 1);
1073
+
1074
+ const newAst = searchStatementState.calculateAst();
1075
+ setQueryAST(newAst);
1076
+ };
1077
+
1078
+ const setOffset = (
1079
+ value: SearchStatementLiteralValue | ValueRef | null
1080
+ ) => {
1081
+ searchStatementState.offset = value;
1082
+ _setOffset(value);
1083
+ setOffsetUpdateKey((key) => key + 1);
1084
+
1085
+ const newAst = searchStatementState.calculateAst();
1086
+ setQueryAST(newAst);
1087
+ };
1088
+
1089
+ const setLimit = (value: SearchStatementLiteralValue | ValueRef | null) => {
1090
+ searchStatementState.limit = value;
1091
+ _setLimit(value);
1092
+ setLimitUpdateKey((key) => key + 1);
1093
+
1094
+ if (
1095
+ value?.type === SearchStatementNodeType.LiteralValue &&
1096
+ value.valueType === SearchLiteralValueType.Number &&
1097
+ (value.value as number) > 1
1098
+ ) {
1099
+ searchStatementState.asList = true;
1100
+
1101
+ _setAsList(true);
1102
+ }
1103
+
1104
+ const newAst = searchStatementState.calculateAst();
1105
+ setQueryAST(newAst);
1106
+ };
1107
+
1108
+ const setAsList = (value: boolean) => {
1109
+ searchStatementState.asList = value;
1110
+
1111
+ _setAsList(value);
1112
+
1113
+ if (!value) {
1114
+ const newLimitLiteral = new SearchStatementLiteralValue(
1115
+ searchStatementState
1116
+ );
1117
+ newLimitLiteral.value = 1;
1118
+ newLimitLiteral.valueType = SearchLiteralValueType.Number;
1119
+
1120
+ searchStatementState.limit = newLimitLiteral;
1121
+ _setLimit(newLimitLiteral);
1122
+ setLimitUpdateKey((key) => key + 1);
1123
+ }
1124
+
1125
+ const newAst = searchStatementState.calculateAst();
1126
+ setQueryAST(newAst);
1127
+ };
1128
+
1129
+ const addDatasource = (dataSource: DataSource) => {
1130
+ const storedDataSource = searchStatementState.addDataSource(dataSource);
1131
+
1132
+ if (dataSource !== storedDataSource) {
1133
+ // Add the data source to the list of data sources available to use throughout the search statement builder
1134
+ _setDataSources((dataSources) => [...dataSources, dataSource]);
1135
+ setDataSourcesUpdateKey((key) => key + 1);
1136
+ }
1137
+ };
1138
+
1139
+ // Based on the main data source, we resolve the database client
1140
+ const resolveDatabaseClient = (): Database | null => {
1141
+ Logger.log('resolveDatabaseClient');
1142
+ if (!!searchStatementState?.from) {
1143
+ const mainDataSourceEntity =
1144
+ searchStatementState?.mainPersistedEntity || null;
1145
+
1146
+ if (!mainDataSourceEntity) {
1147
+ Logger.log('No main data source entity');
1148
+ return null;
1149
+ }
1150
+
1151
+ const database =
1152
+ project?.localDatabaseStore?.getDatabaseForPersistedEntity(
1153
+ mainDataSourceEntity
1154
+ );
1155
+
1156
+ Logger.log('Database', database);
1157
+
1158
+ return database;
1159
+ } else {
1160
+ Logger.log('Selecting first database');
1161
+ // There is no need for any table to be present, so we just need ANY client, to query against
1162
+ return project?.localDatabaseStore?.databases[0] || null;
1163
+ }
1164
+ };
1165
+
1166
+ if (!searchStatementState || !entity || !project) {
1167
+ return null;
1168
+ }
1169
+
1170
+ return (
1171
+ <SearchStatementContext.Provider
1172
+ value={{
1173
+ tabManager,
1174
+ searchStatementState,
1175
+ dataSources,
1176
+ mainDataSource,
1177
+ setMainDataSource,
1178
+ aggregations,
1179
+ aggregationsUpdateKey,
1180
+ addAggregation,
1181
+ removeAggregation,
1182
+ editAggregation,
1183
+ selections,
1184
+ selectionsUpdateKey,
1185
+ addSelection,
1186
+ editSelection,
1187
+ removeSelection,
1188
+ sorting,
1189
+ sortingUpdateKey,
1190
+ addSorting,
1191
+ editSorting,
1192
+ removeSorting,
1193
+ setOffset,
1194
+ setLimit,
1195
+ setAsList,
1196
+ setWhere,
1197
+ resolveDatabaseClient,
1198
+ where,
1199
+ whereUpdateKey,
1200
+ offset,
1201
+ asList,
1202
+ limit,
1203
+ project,
1204
+ entity,
1205
+ sqlAST,
1206
+ offsetUpdateKey,
1207
+ limitUpdateKey,
1208
+ dataSourcesUpdateKey,
1209
+ hydrationReady,
1210
+ isNested: false
1211
+ }}
1212
+ >
1213
+ {children}
1214
+ </SearchStatementContext.Provider>
1215
+ );
1216
+ };
1217
+
1218
+ export const withSearchStatementProvider = <
1219
+ T extends {
1220
+ project: EditorService;
1221
+ ready: boolean;
1222
+ tabManager: ITabManager;
1223
+ } = {
1224
+ project: EditorService;
1225
+ ready: boolean;
1226
+ tabManager: ITabManager;
1227
+ }
1228
+ >(
1229
+ Component: React.ComponentType<T>
1230
+ ) => {
1231
+ return function WrappedComponent(props: T) {
1232
+ return (
1233
+ <SearchStatementProvider
1234
+ project={props.project}
1235
+ ready={props.ready}
1236
+ tabManager={props.tabManager}
1237
+ >
1238
+ <Component {...props} />
1239
+ </SearchStatementProvider>
1240
+ );
1241
+ };
1242
+ };
1243
+
1244
+ const NestedSearchStatementProvider = ({
1245
+ children,
1246
+ project,
1247
+ ready,
1248
+ tabManager,
1249
+ parent,
1250
+ // recalculateParent,
1251
+ query
1252
+ }: {
1253
+ children: ReactNode;
1254
+ project: EditorService;
1255
+ ready: boolean;
1256
+ tabManager: ITabManager;
1257
+ parent: SearchStatementState;
1258
+ // recalculateParent: () => void;
1259
+ query: SearchStatementState;
1260
+ }) => {
1261
+ const { entityId } = useParams<{
1262
+ entityType: EntityType;
1263
+ entityId: EntityId;
1264
+ }>();
1265
+
1266
+ const entity: SearchState | null = project?.logic.get(
1267
+ entityId
1268
+ ) as SearchState | null;
1269
+
1270
+ const [sqlAST, _setSqlAST] = useState<SQLAST | null>(null);
1271
+
1272
+ const searchStatementState: SearchStatementState | null = query;
1273
+
1274
+ const [dataSources, _setDataSources] = useState<DataSource[]>(
1275
+ searchStatementState?.dataSources || []
1276
+ );
1277
+ const [dataSourcesUpdateKey, setDataSourcesUpdateKey] = useState(0);
1278
+
1279
+ const [where, _setWhere] = useState<WhereStatement | null>(
1280
+ searchStatementState?.where || null
1281
+ );
1282
+ const [whereUpdateKey, setWhereUpdateKey] = useState(0);
1283
+
1284
+ const [selections, _setSelections] = useState<
1285
+ (ColumnRef | AllColumnsSelector | FunctionCall)[]
1286
+ >(searchStatementState?.selections || []);
1287
+ const [selectionsUpdateKey, setSelectionsUpdateKey] = useState(0);
1288
+
1289
+ const [mainDataSource, _setMainDataSource] = useState<DataSource | null>(
1290
+ searchStatementState?.from || null
1291
+ );
1292
+
1293
+ const [aggregations, _setAggregations] = useState<AggregationStatement[]>(
1294
+ searchStatementState?.aggregations || []
1295
+ );
1296
+ const [aggregationsUpdateKey, setAggregationsUpdateKey] = useState(0);
1297
+
1298
+ const [sorting, _setSorting] = useState<SortStatement[]>(
1299
+ searchStatementState?.sorting || []
1300
+ );
1301
+ const [sortingUpdateKey, setSortingUpdateKey] = useState(0);
1302
+
1303
+ const [offset, _setOffset] = useState<
1304
+ SearchStatementLiteralValue | ValueRef | null
1305
+ >(searchStatementState?.offset || null);
1306
+ const [offsetUpdateKey, setOffsetUpdateKey] = useState(0);
1307
+
1308
+ const [limit, _setLimit] = useState<
1309
+ SearchStatementLiteralValue | ValueRef | null
1310
+ >(searchStatementState?.limit || null);
1311
+ const [limitUpdateKey, setLimitUpdateKey] = useState(0);
1312
+
1313
+ const [hydrationReady, setHydrationReady] = useState(false);
1314
+
1315
+ const setQueryAST = ({
1316
+ ast,
1317
+ query
1318
+ }: {
1319
+ ast: SQLAST | null;
1320
+ query: string | null;
1321
+ }) => {
1322
+ // We don't set it in the entity becuase it's a nested search statement
1323
+ // if (!!entity) {
1324
+ // entity.query = query;
1325
+ // }
1326
+ // if (recalculateParent) {
1327
+ // recalculateParent();
1328
+ // }
1329
+
1330
+ _setSqlAST(ast);
1331
+ };
1332
+
1333
+ useEffect(() => {
1334
+ if (!searchStatementState) {
1335
+ return;
1336
+ }
1337
+
1338
+ if (searchStatementState.dataSources) {
1339
+ _setDataSources(searchStatementState.dataSources);
1340
+ }
1341
+
1342
+ const newAst = searchStatementState.calculateAst();
1343
+
1344
+ if (newAst) {
1345
+ setQueryAST(newAst);
1346
+ }
1347
+
1348
+ if (!!searchStatementState.from) {
1349
+ _setMainDataSource(searchStatementState.from);
1350
+ }
1351
+
1352
+ _setWhere(searchStatementState.where);
1353
+ _setOffset(searchStatementState.offset);
1354
+ setOffsetUpdateKey((key) => key + 1);
1355
+ _setLimit(searchStatementState.limit);
1356
+ setLimitUpdateKey((key) => key + 1);
1357
+ _setAggregations(searchStatementState.aggregations);
1358
+ _setSelections(searchStatementState.selections);
1359
+ setSelectionsUpdateKey((key) => key + 1);
1360
+ _setSorting(searchStatementState.sorting);
1361
+
1362
+ setHydrationReady(true);
1363
+ }, [searchStatementState]);
1364
+
1365
+ const removeAggregation = (value: AggregationStatement) => {
1366
+ searchStatementState.removeAggregation(value);
1367
+ _setAggregations(searchStatementState.aggregations);
1368
+ _setSelections(searchStatementState.selections);
1369
+ _setSorting(searchStatementState.sorting);
1370
+ _setWhere(searchStatementState.where);
1371
+ setAggregationsUpdateKey((key) => key + 1);
1372
+ setDataSourcesUpdateKey((key) => key + 1);
1373
+ setSelectionsUpdateKey((key) => key + 1);
1374
+ setSortingUpdateKey((key) => key + 1);
1375
+ setWhereUpdateKey((key) => key + 1);
1376
+
1377
+ const newAst = searchStatementState.calculateAst();
1378
+ setQueryAST(newAst);
1379
+ };
1380
+
1381
+ const addAggregation = (value: AggregationStatement) => {
1382
+ searchStatementState.addAggregation(value);
1383
+ _setAggregations(searchStatementState.aggregations);
1384
+ setAggregationsUpdateKey((key) => key + 1);
1385
+ setDataSourcesUpdateKey((key) => key + 1);
1386
+
1387
+ const newAst = searchStatementState.calculateAst();
1388
+ setQueryAST(newAst);
1389
+ };
1390
+
1391
+ const editAggregation = (value: AggregationStatement) => {
1392
+ searchStatementState.editAggregation(value);
1393
+ _setAggregations(searchStatementState.aggregations);
1394
+ setAggregationsUpdateKey((key) => key + 1);
1395
+ setDataSourcesUpdateKey((key) => key + 1);
1396
+
1397
+ const newAst = searchStatementState.calculateAst();
1398
+ setQueryAST(newAst);
1399
+ };
1400
+
1401
+ const addSelection = (
1402
+ value: ColumnRef | AllColumnsSelector | FunctionCall
1403
+ ) => {
1404
+ searchStatementState.addSelection(value);
1405
+ _setSelections(searchStatementState.selections);
1406
+ setSelectionsUpdateKey((key) => key + 1);
1407
+
1408
+ const newAst = searchStatementState.calculateAst();
1409
+ setQueryAST(newAst);
1410
+ };
1411
+
1412
+ const editSelection = (
1413
+ value: ColumnRef | AllColumnsSelector | FunctionCall
1414
+ ) => {
1415
+ searchStatementState.editSelection(value);
1416
+ _setSelections(searchStatementState.selections);
1417
+ setSelectionsUpdateKey((key) => key + 1);
1418
+
1419
+ const newAst = searchStatementState.calculateAst();
1420
+ setQueryAST(newAst);
1421
+ };
1422
+
1423
+ const removeSelection = (
1424
+ value: ColumnRef | AllColumnsSelector | FunctionCall
1425
+ ) => {
1426
+ searchStatementState.removeSelection(value);
1427
+ _setSelections(searchStatementState.selections);
1428
+ _setSorting(searchStatementState.sorting);
1429
+ setSelectionsUpdateKey((key) => key + 1);
1430
+ setSortingUpdateKey((key) => key + 1);
1431
+
1432
+ const newAst = searchStatementState.calculateAst();
1433
+ setQueryAST(newAst);
1434
+ };
1435
+
1436
+ const addSorting = (value: SortStatement) => {
1437
+ searchStatementState.addSort(value);
1438
+ _setSorting(searchStatementState.sorting);
1439
+ setSortingUpdateKey((key) => key + 1);
1440
+
1441
+ const newAst = searchStatementState.calculateAst();
1442
+ setQueryAST(newAst);
1443
+ };
1444
+
1445
+ const editSorting = (value: SortStatement) => {
1446
+ searchStatementState.editSort(value);
1447
+ _setSorting(searchStatementState.sorting);
1448
+
1449
+ const newAst = searchStatementState.calculateAst();
1450
+ setQueryAST(newAst);
1451
+ };
1452
+
1453
+ const removeSorting = (value: SortStatement) => {
1454
+ searchStatementState.removeSort(value);
1455
+ _setSorting(searchStatementState.sorting);
1456
+ setSortingUpdateKey((key) => key + 1);
1457
+
1458
+ const newAst = searchStatementState.calculateAst();
1459
+ setQueryAST(newAst);
1460
+ };
1461
+
1462
+ const setMainDataSource = (value: DataSource | null) => {
1463
+ searchStatementState.setFrom(value);
1464
+ _setMainDataSource(value);
1465
+ _setSelections(searchStatementState.selections);
1466
+ _setSorting(searchStatementState.sorting);
1467
+ _setAggregations(searchStatementState.aggregations);
1468
+ setSelectionsUpdateKey((key) => key + 1);
1469
+ setSortingUpdateKey((key) => key + 1);
1470
+ setAggregationsUpdateKey((key) => key + 1);
1471
+
1472
+ const newAst = searchStatementState.calculateAst();
1473
+ setQueryAST(newAst);
1474
+ };
1475
+
1476
+ const setWhere = (value: WhereStatement | null) => {
1477
+ searchStatementState.where = value;
1478
+ _setWhere(value);
1479
+ setWhereUpdateKey((key) => key + 1);
1480
+
1481
+ const newAst = searchStatementState.calculateAst();
1482
+ setQueryAST(newAst);
1483
+ };
1484
+
1485
+ const setOffset = (
1486
+ value: SearchStatementLiteralValue | ValueRef | null
1487
+ ) => {
1488
+ searchStatementState.offset = value;
1489
+ _setOffset(value);
1490
+ setOffsetUpdateKey((key) => key + 1);
1491
+
1492
+ const newAst = searchStatementState.calculateAst();
1493
+ setQueryAST(newAst);
1494
+ };
1495
+
1496
+ const setLimit = (value: SearchStatementLiteralValue | ValueRef | null) => {
1497
+ searchStatementState.limit = value;
1498
+ _setLimit(value);
1499
+ setLimitUpdateKey((key) => key + 1);
1500
+
1501
+ if (
1502
+ value?.type === SearchStatementNodeType.LiteralValue &&
1503
+ value.valueType === SearchLiteralValueType.Number &&
1504
+ (value.value as number) > 1
1505
+ ) {
1506
+ searchStatementState.asList = true;
1507
+ }
1508
+
1509
+ const newAst = searchStatementState.calculateAst();
1510
+ setQueryAST(newAst);
1511
+ };
1512
+
1513
+ const addDatasource = (dataSource: DataSource) => {
1514
+ const storedDataSource = searchStatementState.addDataSource(dataSource);
1515
+
1516
+ if (dataSource !== storedDataSource) {
1517
+ // Add the data source to the list of data sources available to use throughout the search statement builder
1518
+ _setDataSources((dataSources) => [...dataSources, dataSource]);
1519
+ setDataSourcesUpdateKey((key) => key + 1);
1520
+ }
1521
+ };
1522
+
1523
+ // Based on the main data source, we resolve the database client
1524
+ const resolveDatabaseClient = (): Database | null => {
1525
+ if (!!searchStatementState?.from) {
1526
+ const mainDataSourceEntity =
1527
+ searchStatementState?.mainPersistedEntity || null;
1528
+
1529
+ if (!mainDataSourceEntity) {
1530
+ return null;
1531
+ }
1532
+
1533
+ const database =
1534
+ project?.localDatabaseStore?.getDatabaseForPersistedEntity(
1535
+ mainDataSourceEntity
1536
+ );
1537
+
1538
+ return database;
1539
+ } else {
1540
+ // There is no need for any table to be present, so we just need ANY client, to query against
1541
+ return project?.localDatabaseStore?.databases[0] || null;
1542
+ }
1543
+ };
1544
+
1545
+ if (!searchStatementState || !entity || !project || !ready) {
1546
+ return null;
1547
+ }
1548
+
1549
+ return (
1550
+ <SearchStatementContext.Provider
1551
+ value={{
1552
+ tabManager,
1553
+ searchStatementState,
1554
+ dataSources,
1555
+ mainDataSource,
1556
+ setMainDataSource,
1557
+ aggregations,
1558
+ aggregationsUpdateKey,
1559
+ addAggregation,
1560
+ removeAggregation,
1561
+ editAggregation,
1562
+ selections,
1563
+ selectionsUpdateKey,
1564
+ addSelection,
1565
+ editSelection,
1566
+ removeSelection,
1567
+ sorting,
1568
+ sortingUpdateKey,
1569
+ addSorting,
1570
+ editSorting,
1571
+ removeSorting,
1572
+ setOffset,
1573
+ setLimit,
1574
+ setAsList: () => {},
1575
+ setWhere,
1576
+ resolveDatabaseClient,
1577
+ where,
1578
+ whereUpdateKey,
1579
+ offset,
1580
+ asList: true,
1581
+ limit,
1582
+ project,
1583
+ entity,
1584
+ sqlAST,
1585
+ offsetUpdateKey,
1586
+ limitUpdateKey,
1587
+ dataSourcesUpdateKey,
1588
+ hydrationReady,
1589
+ isNested: true
1590
+ }}
1591
+ >
1592
+ {children}
1593
+ </SearchStatementContext.Provider>
1594
+ );
1595
+ };
1596
+
1597
+ export const withNestedSearchStatementProvider = <
1598
+ T extends {
1599
+ project: EditorService;
1600
+ ready: boolean;
1601
+ parent: SearchStatementState;
1602
+ query: SearchStatementState;
1603
+ tabManager: ITabManager;
1604
+ // recalculateParent: () => void;
1605
+ } = {
1606
+ project: EditorService;
1607
+ ready: boolean;
1608
+ parent: SearchStatementState;
1609
+ query: SearchStatementState;
1610
+ tabManager: ITabManager;
1611
+ // recalculateParent: () => void;
1612
+ }
1613
+ >(
1614
+ Component: React.ComponentType<T>
1615
+ ) => {
1616
+ return function WrappedComponent(props: T) {
1617
+ return (
1618
+ <NestedSearchStatementProvider
1619
+ project={props.project}
1620
+ ready={props.ready}
1621
+ tabManager={props.tabManager}
1622
+ parent={props.parent}
1623
+ query={props.query}
1624
+ // recalculateParent={props.recalculateParent}
1625
+ >
1626
+ <Component {...props} />
1627
+ </NestedSearchStatementProvider>
1628
+ );
1629
+ };
1630
+ };