@budibase/server 0.9.188 → 0.9.190-alpha.10

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 (314) hide show
  1. package/Dockerfile +7 -1
  2. package/__mocks__/mssql.ts +1 -1
  3. package/__mocks__/oracledb.ts +31 -0
  4. package/__mocks__/pg.ts +3 -0
  5. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  6. package/builder/assets/index.2bd3b345.js +1316 -0
  7. package/builder/assets/index.4fb3f887.css +1 -0
  8. package/builder/assets/oracle.66592424.png +0 -0
  9. package/builder/assets/vendor.470042a4.js +152 -0
  10. package/builder/assets/vendor.5e1fe644.css +1 -0
  11. package/builder/index.html +4 -4
  12. package/coverage/clover.xml +1608 -1191
  13. package/coverage/coverage-final.json +97 -93
  14. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  15. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  16. package/coverage/lcov-report/api/controllers/application.js.html +113 -80
  17. package/coverage/lcov-report/api/controllers/auth.js.html +19 -10
  18. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  19. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  22. package/coverage/lcov-report/api/controllers/datasource.js.html +245 -41
  23. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  24. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  25. package/coverage/lcov-report/api/controllers/index.html +98 -98
  26. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/layout.js.html +9 -9
  28. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  29. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  30. package/coverage/lcov-report/api/controllers/query.js.html +79 -229
  31. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  32. package/coverage/lcov-report/api/controllers/routing.js.html +29 -29
  33. package/coverage/lcov-report/api/controllers/row/external.js.html +17 -8
  34. package/coverage/lcov-report/api/controllers/row/index.html +26 -26
  35. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  36. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  37. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  38. package/coverage/lcov-report/api/controllers/row/utils.js.html +21 -30
  39. package/coverage/lcov-report/api/controllers/screen.js.html +3 -3
  40. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  41. package/coverage/lcov-report/api/controllers/table/external.js.html +1001 -0
  42. package/coverage/lcov-report/api/controllers/table/index.html +56 -26
  43. package/coverage/lcov-report/api/controllers/table/index.js.html +80 -350
  44. package/coverage/lcov-report/api/controllers/table/internal.js.html +533 -0
  45. package/coverage/lcov-report/api/controllers/table/utils.js.html +175 -52
  46. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  47. package/coverage/lcov-report/api/controllers/user.js.html +390 -33
  48. package/coverage/lcov-report/api/controllers/view/exporters.js.html +19 -4
  49. package/coverage/lcov-report/api/controllers/view/index.html +22 -22
  50. package/coverage/lcov-report/api/controllers/view/index.js.html +52 -13
  51. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  52. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  53. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  54. package/coverage/lcov-report/api/index.html +1 -1
  55. package/coverage/lcov-report/api/index.js.html +5 -5
  56. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  67. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/index.html +4 -4
  69. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  75. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/row.js.html +536 -2
  78. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  81. package/coverage/lcov-report/api/routes/table.js.html +464 -2
  82. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  83. package/coverage/lcov-report/api/routes/user.js.html +17 -2
  84. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  85. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  86. package/coverage/lcov-report/automations/actions.js.html +2 -2
  87. package/coverage/lcov-report/automations/automationUtils.js.html +4 -4
  88. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  89. package/coverage/lcov-report/automations/index.html +35 -50
  90. package/coverage/lcov-report/automations/index.js.html +2 -2
  91. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  96. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  98. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/index.html +14 -14
  100. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  102. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  103. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  106. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  107. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  108. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  110. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  113. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  115. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  116. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  117. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  118. package/coverage/lcov-report/automations/utils.js.html +46 -16
  119. package/coverage/lcov-report/constants/index.html +5 -5
  120. package/coverage/lcov-report/constants/index.js.html +87 -21
  121. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  122. package/coverage/lcov-report/constants/screens.js.html +2 -2
  123. package/coverage/lcov-report/db/client.js.html +2 -2
  124. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  125. package/coverage/lcov-report/db/index.html +2 -2
  126. package/coverage/lcov-report/db/index.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  128. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  129. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  130. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  131. package/coverage/lcov-report/db/newid.js.html +4 -4
  132. package/coverage/lcov-report/db/utils.js.html +75 -75
  133. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  134. package/coverage/lcov-report/events/index.html +6 -6
  135. package/coverage/lcov-report/events/index.js.html +1 -1
  136. package/coverage/lcov-report/events/utils.js.html +5 -5
  137. package/coverage/lcov-report/index.html +106 -91
  138. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  139. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  140. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  141. package/coverage/lcov-report/middleware/authorized.js.html +19 -16
  142. package/coverage/lcov-report/middleware/builder.js.html +22 -13
  143. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  144. package/coverage/lcov-report/middleware/index.html +23 -23
  145. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  146. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  147. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  148. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  149. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  150. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +90 -33
  151. package/coverage/lcov-report/threads/index.html +141 -0
  152. package/coverage/lcov-report/threads/index.js.html +278 -0
  153. package/coverage/lcov-report/threads/query.js.html +278 -0
  154. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  155. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  156. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  157. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  158. package/coverage/lcov-report/utilities/global.js.html +38 -23
  159. package/coverage/lcov-report/utilities/index.html +48 -48
  160. package/coverage/lcov-report/utilities/index.js.html +49 -16
  161. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +31 -10
  162. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  163. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  164. package/coverage/lcov-report/utilities/routing/index.js.html +2 -2
  165. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  166. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  167. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  168. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  169. package/coverage/lcov-report/utilities/security.js.html +3 -3
  170. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  171. package/coverage/lcov-report/utilities/users.js.html +1 -1
  172. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  173. package/coverage/lcov.info +2687 -1942
  174. package/dist/api/controllers/application.js +16 -6
  175. package/dist/api/controllers/auth.js +3 -3
  176. package/dist/api/controllers/datasource.js +67 -16
  177. package/dist/api/controllers/deploy/index.js +2 -0
  178. package/dist/api/controllers/dev.js +4 -1
  179. package/dist/api/controllers/query.js +32 -62
  180. package/dist/api/controllers/row/ExternalRequest.js +83 -36
  181. package/dist/api/controllers/row/external.js +3 -1
  182. package/dist/api/controllers/row/utils.js +6 -12
  183. package/dist/api/controllers/table/external.js +249 -0
  184. package/dist/api/controllers/table/index.js +49 -123
  185. package/dist/api/controllers/table/internal.js +146 -0
  186. package/dist/api/controllers/table/utils.js +62 -28
  187. package/dist/api/controllers/user.js +123 -11
  188. package/dist/api/controllers/view/exporters.js +4 -0
  189. package/dist/api/controllers/view/index.js +14 -2
  190. package/dist/api/routes/query.js +1 -1
  191. package/dist/api/routes/row.js +178 -0
  192. package/dist/api/routes/table.js +150 -1
  193. package/dist/api/routes/user.js +2 -1
  194. package/dist/app.js +2 -11
  195. package/dist/automations/bullboard.js +37 -10
  196. package/dist/automations/triggers.js +7 -3
  197. package/dist/automations/utils.js +11 -2
  198. package/dist/constants/index.js +19 -0
  199. package/dist/definitions/datasource.js +17 -1
  200. package/dist/environment.js +13 -0
  201. package/dist/integrations/base/IntegrationBase.js +2 -0
  202. package/dist/integrations/base/datasourcePlus.js +2 -0
  203. package/dist/integrations/base/sql.js +350 -177
  204. package/dist/integrations/base/sqlTable.js +143 -0
  205. package/dist/integrations/base/utils.js +30 -0
  206. package/dist/integrations/index.js +6 -0
  207. package/dist/integrations/microsoftSqlServer.js +117 -9
  208. package/dist/integrations/mysql.js +16 -85
  209. package/dist/integrations/oracle.js +367 -0
  210. package/dist/integrations/postgres.js +35 -28
  211. package/dist/integrations/utils.js +71 -9
  212. package/dist/middleware/authorized.js +2 -1
  213. package/dist/middleware/builder.js +4 -1
  214. package/dist/package.json +18 -9
  215. package/dist/tests/utilities/TestConfiguration.js +2 -1
  216. package/dist/{automations/thread.js → threads/automation.js} +26 -8
  217. package/dist/threads/index.js +64 -0
  218. package/dist/threads/query.js +64 -0
  219. package/dist/tsconfig.tsbuildinfo +1 -1
  220. package/dist/utilities/csvParser.js +46 -5
  221. package/dist/utilities/global.js +6 -2
  222. package/dist/utilities/index.js +11 -0
  223. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  224. package/dist/utilities/scriptRunner.js +4 -1
  225. package/package.json +19 -10
  226. package/scripts/dev/manage.js +1 -0
  227. package/scripts/docs/README.md +31 -0
  228. package/scripts/docs/generate.js +74 -0
  229. package/scripts/docs/toSwagger.js +320 -0
  230. package/scripts/integrations/mssql/data/Dockerfile +9 -0
  231. package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
  232. package/scripts/integrations/mssql/data/setup.sql +54 -0
  233. package/scripts/integrations/mssql/docker-compose.yaml +12 -0
  234. package/scripts/integrations/mssql/reset.sh +3 -0
  235. package/scripts/integrations/oracle/docker-compose.yml +19 -0
  236. package/scripts/integrations/oracle/instantclient/linux/x86-64/basiclite-21.4.zip +0 -0
  237. package/scripts/integrations/oracle/instantclient/linux/x86-64/install.sh +23 -0
  238. package/scripts/integrations/oracle/oracle.md +90 -0
  239. package/scripts/integrations/postgres/docker-compose.yml +3 -3
  240. package/scripts/likeCypress.ts +33 -0
  241. package/src/api/controllers/application.js +18 -7
  242. package/src/api/controllers/auth.js +3 -0
  243. package/src/api/controllers/datasource.js +84 -16
  244. package/src/api/controllers/deploy/index.js +2 -0
  245. package/src/api/controllers/dev.js +4 -1
  246. package/src/api/controllers/query.js +35 -85
  247. package/src/api/controllers/row/ExternalRequest.ts +99 -38
  248. package/src/api/controllers/row/external.js +4 -1
  249. package/src/api/controllers/row/utils.js +8 -11
  250. package/src/api/controllers/table/external.js +307 -0
  251. package/src/api/controllers/table/index.js +47 -137
  252. package/src/api/controllers/table/internal.js +151 -0
  253. package/src/api/controllers/table/utils.js +74 -33
  254. package/src/api/controllers/user.js +132 -13
  255. package/src/api/controllers/view/exporters.js +5 -0
  256. package/src/api/controllers/view/index.js +15 -2
  257. package/src/api/routes/query.js +1 -0
  258. package/src/api/routes/row.js +178 -0
  259. package/src/api/routes/table.js +154 -0
  260. package/src/api/routes/tests/application.spec.js +0 -2
  261. package/src/api/routes/tests/datasource.spec.js +2 -2
  262. package/src/api/routes/tests/misc.spec.js +5 -1
  263. package/src/api/routes/tests/query.spec.js +38 -9
  264. package/src/api/routes/tests/screen.spec.js +1 -1
  265. package/src/api/routes/user.js +5 -0
  266. package/src/app.ts +2 -10
  267. package/src/automations/bullboard.js +28 -11
  268. package/src/automations/tests/automation.spec.js +3 -4
  269. package/src/automations/triggers.js +7 -3
  270. package/src/automations/utils.js +12 -2
  271. package/src/constants/index.js +22 -0
  272. package/src/definitions/common.ts +7 -1
  273. package/src/definitions/datasource.ts +21 -3
  274. package/src/environment.js +15 -0
  275. package/src/integrations/airtable.ts +2 -1
  276. package/src/integrations/arangodb.ts +2 -1
  277. package/src/integrations/base/IntegrationBase.ts +6 -0
  278. package/src/integrations/base/datasourcePlus.ts +9 -0
  279. package/src/integrations/base/sql.ts +375 -218
  280. package/src/integrations/base/sqlTable.ts +180 -0
  281. package/src/integrations/base/utils.ts +22 -0
  282. package/src/integrations/couchdb.ts +2 -1
  283. package/src/integrations/dynamodb.ts +2 -1
  284. package/src/integrations/elasticsearch.ts +2 -1
  285. package/src/integrations/index.ts +7 -0
  286. package/src/integrations/microsoftSqlServer.ts +145 -13
  287. package/src/integrations/mongodb.ts +2 -1
  288. package/src/integrations/mysql.ts +23 -95
  289. package/src/integrations/oracle.ts +464 -0
  290. package/src/integrations/postgres.ts +45 -35
  291. package/src/integrations/rest.ts +2 -1
  292. package/src/integrations/s3.ts +2 -1
  293. package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
  294. package/src/integrations/tests/oracle.spec.js +94 -0
  295. package/src/integrations/tests/postgres.spec.js +4 -0
  296. package/src/integrations/utils.ts +78 -8
  297. package/src/middleware/authorized.js +2 -1
  298. package/src/middleware/builder.js +4 -1
  299. package/src/tests/utilities/TestConfiguration.js +2 -1
  300. package/src/{automations/thread.js → threads/automation.js} +27 -8
  301. package/src/threads/index.js +66 -0
  302. package/src/threads/query.js +66 -0
  303. package/src/utilities/csvParser.js +48 -5
  304. package/src/utilities/global.js +7 -2
  305. package/src/utilities/index.js +11 -0
  306. package/src/utilities/queue/inMemoryQueue.js +7 -0
  307. package/src/utilities/scriptRunner.js +4 -1
  308. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  309. package/src/utilities/tests/csvParser.spec.js +3 -0
  310. package/tsconfig.json +1 -1
  311. package/builder/assets/index.550fdba7.js +0 -201
  312. package/builder/assets/index.7469e1e4.css +0 -29
  313. package/builder/assets/vendor.278a305c.js +0 -9
  314. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -1,10 +1,14 @@
1
1
  const { processString } = require("@budibase/string-templates")
2
2
  const CouchDB = require("../../db")
3
- const { generateQueryID, getQueryParams } = require("../../db/utils")
4
- const { integrations } = require("../../integrations")
3
+ const {
4
+ generateQueryID,
5
+ getQueryParams,
6
+ isProdAppID,
7
+ } = require("../../db/utils")
5
8
  const { BaseQueryVerbs } = require("../../constants")
6
- const env = require("../../environment")
7
- const ScriptRunner = require("../../utilities/scriptRunner")
9
+ const { Thread, ThreadType } = require("../../threads")
10
+
11
+ const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 })
8
12
 
9
13
  // simple function to append "readable" to all read queries
10
14
  function enrichQueries(input) {
@@ -18,47 +22,6 @@ function enrichQueries(input) {
18
22
  return wasArray ? queries : queries[0]
19
23
  }
20
24
 
21
- function formatResponse(resp) {
22
- if (typeof resp === "string") {
23
- try {
24
- resp = JSON.parse(resp)
25
- } catch (err) {
26
- resp = { response: resp }
27
- }
28
- }
29
- return resp
30
- }
31
-
32
- async function runAndTransform(
33
- integration,
34
- queryVerb,
35
- enrichedQuery,
36
- transformer
37
- ) {
38
- let rows = formatResponse(await integration[queryVerb](enrichedQuery))
39
-
40
- // transform as required
41
- if (transformer) {
42
- const runner = new ScriptRunner(transformer, { data: rows })
43
- rows = runner.execute()
44
- }
45
-
46
- // needs to an array for next step
47
- if (!Array.isArray(rows)) {
48
- rows = [rows]
49
- }
50
-
51
- // map into JSON if just raw primitive here
52
- if (rows.find(row => typeof row !== "object")) {
53
- rows = rows.map(value => ({ value }))
54
- }
55
-
56
- // get all the potential fields in the schema
57
- let keys = rows.flatMap(Object.keys)
58
-
59
- return { rows, keys }
60
- }
61
-
62
25
  exports.fetch = async function (ctx) {
63
26
  const db = new CouchDB(ctx.appId)
64
27
 
@@ -98,7 +61,9 @@ async function enrichQueryFields(fields, parameters = {}) {
98
61
  enrichedQuery[key] = await enrichQueryFields(fields[key], parameters)
99
62
  } else if (typeof fields[key] === "string") {
100
63
  // enrich string value as normal
101
- enrichedQuery[key] = await processString(fields[key], parameters)
64
+ enrichedQuery[key] = await processString(fields[key], parameters, {
65
+ noHelpers: true,
66
+ })
102
67
  } else {
103
68
  enrichedQuery[key] = fields[key]
104
69
  }
@@ -128,10 +93,9 @@ exports.find = async function (ctx) {
128
93
  const db = new CouchDB(ctx.appId)
129
94
  const query = enrichQueries(await db.get(ctx.params.queryId))
130
95
  // remove properties that could be dangerous in real app
131
- if (env.isProd()) {
96
+ if (isProdAppID(ctx.appId)) {
132
97
  delete query.fields
133
98
  delete query.parameters
134
- delete query.schema
135
99
  }
136
100
  ctx.body = query
137
101
  }
@@ -141,30 +105,23 @@ exports.preview = async function (ctx) {
141
105
 
142
106
  const datasource = await db.get(ctx.request.body.datasourceId)
143
107
 
144
- const Integration = integrations[datasource.source]
145
-
146
- if (!Integration) {
147
- ctx.throw(400, "Integration type does not exist.")
148
- }
149
-
150
108
  const { fields, parameters, queryVerb, transformer } = ctx.request.body
151
109
  const enrichedQuery = await enrichQueryFields(fields, parameters)
152
- const integration = new Integration(datasource.config)
153
110
 
154
- const { rows, keys } = await runAndTransform(
155
- integration,
156
- queryVerb,
157
- enrichedQuery,
158
- transformer
159
- )
111
+ try {
112
+ const { rows, keys } = await Runner.run({
113
+ datasource,
114
+ queryVerb,
115
+ query: enrichedQuery,
116
+ transformer,
117
+ })
160
118
 
161
- ctx.body = {
162
- rows,
163
- schemaFields: [...new Set(keys)],
164
- }
165
- // cleanup
166
- if (integration.end) {
167
- integration.end()
119
+ ctx.body = {
120
+ rows,
121
+ schemaFields: [...new Set(keys)],
122
+ }
123
+ } catch (err) {
124
+ ctx.throw(400, err)
168
125
  }
169
126
  }
170
127
 
@@ -174,29 +131,22 @@ exports.execute = async function (ctx) {
174
131
  const query = await db.get(ctx.params.queryId)
175
132
  const datasource = await db.get(query.datasourceId)
176
133
 
177
- const Integration = integrations[datasource.source]
178
-
179
- if (!Integration) {
180
- ctx.throw(400, "Integration type does not exist.")
181
- }
182
-
183
134
  const enrichedQuery = await enrichQueryFields(
184
135
  query.fields,
185
136
  ctx.request.body.parameters
186
137
  )
187
- const integration = new Integration(datasource.config)
188
138
 
189
139
  // call the relevant CRUD method on the integration class
190
- const { rows } = await runAndTransform(
191
- integration,
192
- query.queryVerb,
193
- enrichedQuery,
194
- query.transformer
195
- )
196
- ctx.body = rows
197
- // cleanup
198
- if (integration.end) {
199
- integration.end()
140
+ try {
141
+ const { rows } = await Runner.run({
142
+ datasource,
143
+ queryVerb: query.queryVerb,
144
+ query: enrichedQuery,
145
+ transformer: query.transformer,
146
+ })
147
+ ctx.body = rows
148
+ } catch (err) {
149
+ ctx.throw(400, err)
200
150
  }
201
151
  }
202
152
 
@@ -1,4 +1,5 @@
1
1
  import {
2
+ FilterTypes,
2
3
  IncludeRelationships,
3
4
  Operation,
4
5
  PaginationJson,
@@ -33,10 +34,11 @@ interface RunConfig {
33
34
  sort?: SortJson
34
35
  paginate?: PaginationJson
35
36
  row?: Row
37
+ rows?: Row[]
36
38
  }
37
39
 
38
40
  module External {
39
- const { makeExternalQuery } = require("./utils")
41
+ const { getDatasourceAndQuery } = require("./utils")
40
42
  const {
41
43
  DataSourceOperation,
42
44
  FieldTypes,
@@ -46,6 +48,7 @@ module External {
46
48
  const { processObjectSync } = require("@budibase/string-templates")
47
49
  const { cloneDeep } = require("lodash/fp")
48
50
  const CouchDB = require("../../../db")
51
+ const { processFormulas } = require("../../../utilities/rowProcessor/utils")
49
52
 
50
53
  function buildFilters(
51
54
  id: string | undefined,
@@ -116,8 +119,13 @@ module External {
116
119
  }
117
120
  // check the row and filters to make sure they aren't a key of some sort
118
121
  if (config.filters) {
119
- for (let filter of Object.values(config.filters)) {
120
- if (typeof filter !== "object" || Object.keys(filter).length === 0) {
122
+ for (let [key, filter] of Object.entries(config.filters)) {
123
+ // oneOf is an array, don't iterate it
124
+ if (
125
+ typeof filter !== "object" ||
126
+ Object.keys(filter).length === 0 ||
127
+ key === FilterTypes.ONE_OF
128
+ ) {
121
129
  continue
122
130
  }
123
131
  iterateObject(filter)
@@ -162,8 +170,8 @@ module External {
162
170
  }
163
171
  }
164
172
 
165
- function basicProcessing(row: Row, table: Table) {
166
- const thisRow: { [key: string]: any } = {}
173
+ function basicProcessing(row: Row, table: Table): Row {
174
+ const thisRow: Row = {}
167
175
  // filter the row down to what is actually the row (not joined)
168
176
  for (let fieldName of Object.keys(table.schema)) {
169
177
  const value = row[`${table.name}.${fieldName}`] || row[fieldName]
@@ -178,9 +186,26 @@ module External {
178
186
  return thisRow
179
187
  }
180
188
 
181
- function isMany(field: FieldSchema) {
189
+ function fixArrayTypes(row: Row, table: Table) {
190
+ for (let [fieldName, schema] of Object.entries(table.schema)) {
191
+ if (
192
+ schema.type === FieldTypes.ARRAY &&
193
+ typeof row[fieldName] === "string"
194
+ ) {
195
+ try {
196
+ row[fieldName] = JSON.parse(row[fieldName])
197
+ } catch (err) {
198
+ // couldn't convert back to array, ignore
199
+ delete row[fieldName]
200
+ }
201
+ }
202
+ }
203
+ return row
204
+ }
205
+
206
+ function isOneSide(field: FieldSchema) {
182
207
  return (
183
- field.relationshipType && field.relationshipType.split("-")[0] === "many"
208
+ field.relationshipType && field.relationshipType.split("-")[0] === "one"
184
209
  )
185
210
  }
186
211
 
@@ -225,7 +250,12 @@ module External {
225
250
  manyRelationships: ManyRelationship[] = []
226
251
  for (let [key, field] of Object.entries(table.schema)) {
227
252
  // if set already, or not set just skip it
228
- if ((!row[key] && row[key] !== "") || newRow[key] || field.autocolumn) {
253
+ if (
254
+ row[key] == null ||
255
+ newRow[key] ||
256
+ field.autocolumn ||
257
+ field.type === FieldTypes.FORMULA
258
+ ) {
229
259
  continue
230
260
  }
231
261
  // if its an empty string then it means return the column to null (if possible)
@@ -250,25 +280,37 @@ module External {
250
280
  const linkTable = this.tables[linkTableName]
251
281
  // @ts-ignore
252
282
  const linkTablePrimary = linkTable.primary[0]
253
- if (!isMany(field)) {
283
+ // one to many
284
+ if (isOneSide(field)) {
254
285
  newRow[field.foreignKey || linkTablePrimary] = breakRowIdField(
255
286
  row[key][0]
256
287
  )[0]
257
- } else {
288
+ }
289
+ // many to many
290
+ else if (field.through) {
258
291
  // we're not inserting a doc, will be a bunch of update calls
259
- const isUpdate = !field.through
260
- const thisKey: string = isUpdate
261
- ? "id"
262
- : field.throughTo || linkTablePrimary
263
- // @ts-ignore
264
- const otherKey: string = isUpdate
265
- ? field.fieldName
266
- : field.throughFrom || tablePrimary
292
+ const otherKey: string = field.throughFrom || linkTablePrimary
293
+ const thisKey: string = field.throughTo || tablePrimary
267
294
  row[key].map((relationship: any) => {
268
- // we don't really support composite keys for relationships, this is why [0] is used
269
295
  manyRelationships.push({
270
296
  tableId: field.through || field.tableId,
271
- isUpdate,
297
+ isUpdate: false,
298
+ key: otherKey,
299
+ [otherKey]: breakRowIdField(relationship)[0],
300
+ // leave the ID for enrichment later
301
+ [thisKey]: `{{ literal ${tablePrimary} }}`,
302
+ })
303
+ })
304
+ }
305
+ // many to one
306
+ else {
307
+ const thisKey: string = "id"
308
+ // @ts-ignore
309
+ const otherKey: string = field.fieldName
310
+ row[key].map((relationship: any) => {
311
+ manyRelationships.push({
312
+ tableId: field.tableId,
313
+ isUpdate: true,
272
314
  key: otherKey,
273
315
  [thisKey]: breakRowIdField(relationship)[0],
274
316
  // leave the ID for enrichment later
@@ -336,7 +378,7 @@ module External {
336
378
  table: Table,
337
379
  relationships: RelationshipsJson[]
338
380
  ) {
339
- if (rows[0].read === true) {
381
+ if (!rows || rows.length === 0 || rows[0].read === true) {
340
382
  return []
341
383
  }
342
384
  let finalRows: { [key: string]: Row } = {}
@@ -352,7 +394,10 @@ module External {
352
394
  )
353
395
  continue
354
396
  }
355
- const thisRow = basicProcessing(row, table)
397
+ const thisRow = fixArrayTypes(basicProcessing(row, table), table)
398
+ if (thisRow._id == null) {
399
+ throw "Unable to generate row ID for SQL rows"
400
+ }
356
401
  finalRows[thisRow._id] = thisRow
357
402
  // do this at end once its been added to the final rows
358
403
  finalRows = this.updateRelationshipColumns(
@@ -361,7 +406,7 @@ module External {
361
406
  relationships
362
407
  )
363
408
  }
364
- return Object.values(finalRows)
409
+ return processFormulas(table, Object.values(finalRows))
365
410
  }
366
411
 
367
412
  /**
@@ -398,8 +443,8 @@ module External {
398
443
  )
399
444
  definition.through = throughTableName
400
445
  // don't support composite keys for relationships
401
- definition.from = field.throughFrom || table.primary[0]
402
- definition.to = field.throughTo || linkTable.primary[0]
446
+ definition.from = field.throughTo || table.primary[0]
447
+ definition.to = field.throughFrom || linkTable.primary[0]
403
448
  definition.fromPrimary = table.primary[0]
404
449
  definition.toPrimary = linkTable.primary[0]
405
450
  }
@@ -421,24 +466,36 @@ module External {
421
466
  // make a new request to get the row with all its relationships
422
467
  // we need this to work out if any relationships need removed
423
468
  for (let field of Object.values(table.schema)) {
424
- if (field.type !== FieldTypes.LINK || !field.fieldName) {
469
+ if (
470
+ field.type !== FieldTypes.LINK ||
471
+ !field.fieldName ||
472
+ isOneSide(field)
473
+ ) {
425
474
  continue
426
475
  }
427
476
  const isMany = field.relationshipType === RelationshipTypes.MANY_TO_MANY
428
477
  const tableId = isMany ? field.through : field.tableId
429
- const manyKey = field.throughFrom || primaryKey
478
+ const { tableName: relatedTableName } = breakExternalTableId(tableId)
479
+ // @ts-ignore
480
+ const linkPrimaryKey = this.tables[relatedTableName].primary[0]
481
+ const manyKey = field.throughTo || primaryKey
482
+ const lookupField = isMany ? primaryKey : field.foreignKey
430
483
  const fieldName = isMany ? manyKey : field.fieldName
431
- const response = await makeExternalQuery(this.appId, {
484
+ if (!lookupField || !row[lookupField]) {
485
+ continue
486
+ }
487
+ const response = await getDatasourceAndQuery(this.appId, {
432
488
  endpoint: getEndpoint(tableId, DataSourceOperation.READ),
433
489
  filters: {
434
490
  equal: {
435
- [fieldName]: row[primaryKey],
491
+ [fieldName]: row[lookupField],
436
492
  },
437
493
  },
438
494
  })
439
495
  // this is the response from knex if no rows found
440
496
  const rows = !response[0].read ? response : []
441
- related[fieldName] = { rows, isMany, tableId }
497
+ const storeTo = isMany ? field.throughFrom || linkPrimaryKey : manyKey
498
+ related[storeTo] = { rows, isMany, tableId }
442
499
  }
443
500
  return related
444
501
  }
@@ -479,7 +536,7 @@ module External {
479
536
  : DataSourceOperation.CREATE
480
537
  if (!found) {
481
538
  promises.push(
482
- makeExternalQuery(appId, {
539
+ getDatasourceAndQuery(appId, {
483
540
  endpoint: getEndpoint(tableId, operation),
484
541
  // if we're doing many relationships then we're writing, only one response
485
542
  body,
@@ -509,7 +566,7 @@ module External {
509
566
  : DataSourceOperation.UPDATE
510
567
  const body = isMany ? null : { [colName]: null }
511
568
  promises.push(
512
- makeExternalQuery(this.appId, {
569
+ getDatasourceAndQuery(this.appId, {
513
570
  endpoint: getEndpoint(tableId, op),
514
571
  body,
515
572
  filters,
@@ -532,16 +589,17 @@ module External {
532
589
  table: Table,
533
590
  includeRelations: IncludeRelationships = IncludeRelationships.INCLUDE
534
591
  ) {
535
- function extractNonLinkFieldNames(table: Table, existing: string[] = []) {
592
+ function extractRealFields(table: Table, existing: string[] = []) {
536
593
  return Object.entries(table.schema)
537
594
  .filter(
538
595
  column =>
539
596
  column[1].type !== FieldTypes.LINK &&
597
+ column[1].type !== FieldTypes.FORMULA &&
540
598
  !existing.find((field: string) => field === column[0])
541
599
  )
542
600
  .map(column => `${table.name}.${column[0]}`)
543
601
  }
544
- let fields = extractNonLinkFieldNames(table)
602
+ let fields = extractRealFields(table)
545
603
  for (let field of Object.values(table.schema)) {
546
604
  if (field.type !== FieldTypes.LINK || !includeRelations) {
547
605
  continue
@@ -549,7 +607,7 @@ module External {
549
607
  const { tableName: linkTableName } = breakExternalTableId(field.tableId)
550
608
  const linkTable = this.tables[linkTableName]
551
609
  if (linkTable) {
552
- const linkedFields = extractNonLinkFieldNames(linkTable, fields)
610
+ const linkedFields = extractRealFields(linkTable, fields)
553
611
  fields = fields.concat(linkedFields)
554
612
  }
555
613
  }
@@ -573,7 +631,10 @@ module External {
573
631
  throw `Unable to process query, table "${tableName}" not defined.`
574
632
  }
575
633
  // look for specific components of config which may not be considered acceptable
576
- let { id, row, filters, sort, paginate } = cleanupConfig(config, table)
634
+ let { id, row, filters, sort, paginate, rows } = cleanupConfig(
635
+ config,
636
+ table
637
+ )
577
638
  filters = buildFilters(id, filters || {}, table)
578
639
  const relationships = this.buildRelationships(table)
579
640
  // clean up row on ingress using schema
@@ -599,7 +660,7 @@ module External {
599
660
  sort,
600
661
  paginate,
601
662
  relationships,
602
- body: row,
663
+ body: row || rows,
603
664
  // pass an id filter into extra, purely for mysql/returning
604
665
  extra: {
605
666
  idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
@@ -609,7 +670,7 @@ module External {
609
670
  },
610
671
  }
611
672
  // can't really use response right now
612
- const response = await makeExternalQuery(appId, json)
673
+ const response = await getDatasourceAndQuery(appId, json)
613
674
  // handle many to many relationships now if we know the ID (could be auto increment)
614
675
  if (
615
676
  operation !== DataSourceOperation.READ &&
@@ -30,6 +30,8 @@ async function handleRequest(appId, operation, tableId, opts = {}) {
30
30
  )
31
31
  }
32
32
 
33
+ exports.handleRequest = handleRequest
34
+
33
35
  exports.patch = async ctx => {
34
36
  const appId = ctx.appId
35
37
  const inputs = ctx.request.body
@@ -55,7 +57,8 @@ exports.save = async ctx => {
55
57
  exports.fetchView = async ctx => {
56
58
  // there are no views in external data sources, shouldn't ever be called
57
59
  // for now just fetch
58
- ctx.params.tableId = ctx.params.viewName.split("all_")[1]
60
+ const split = ctx.params.viewName.split("all_")
61
+ ctx.params.tableId = split[1] ? split[1] : split[0]
59
62
  return exports.fetch(ctx)
60
63
  }
61
64
 
@@ -4,8 +4,8 @@ const CouchDB = require("../../../db")
4
4
  const { InternalTables } = require("../../../db/utils")
5
5
  const userController = require("../user")
6
6
  const { FieldTypes } = require("../../../constants")
7
- const { integrations } = require("../../../integrations")
8
7
  const { processStringSync } = require("@budibase/string-templates")
8
+ const { makeExternalQuery } = require("../../../integrations/base/utils")
9
9
 
10
10
  validateJs.extend(validateJs.validators.datetime, {
11
11
  parse: function (value) {
@@ -17,18 +17,11 @@ validateJs.extend(validateJs.validators.datetime, {
17
17
  },
18
18
  })
19
19
 
20
- exports.makeExternalQuery = async (appId, json) => {
20
+ exports.getDatasourceAndQuery = async (appId, json) => {
21
21
  const datasourceId = json.endpoint.datasourceId
22
22
  const db = new CouchDB(appId)
23
23
  const datasource = await db.get(datasourceId)
24
- const Integration = integrations[datasource.source]
25
- // query is the opinionated function
26
- if (Integration.prototype.query) {
27
- const integration = new Integration(datasource.config)
28
- return integration.query(json)
29
- } else {
30
- throw "Datasource does not support query."
31
- }
24
+ return makeExternalQuery(datasource, json)
32
25
  }
33
26
 
34
27
  exports.findRow = async (ctx, db, tableId, rowId) => {
@@ -68,7 +61,11 @@ exports.validate = async ({ appId, tableId, row, table }) => {
68
61
  let res
69
62
 
70
63
  // Validate.js doesn't seem to handle array
71
- if (table.schema[fieldName].type === FieldTypes.ARRAY) {
64
+ if (
65
+ table.schema[fieldName].type === FieldTypes.ARRAY &&
66
+ row[fieldName] &&
67
+ row[fieldName].length
68
+ ) {
72
69
  row[fieldName].map(val => {
73
70
  if (!constraints.inclusion.includes(val)) {
74
71
  errors[fieldName] = "Field not in list"