@budibase/server 1.0.218 → 1.0.219-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/__mocks__/node-fetch.ts +9 -0
  2. package/builder/assets/index.2ccbb3ad.js +977 -0
  3. package/builder/assets/index.7786f497.css +6 -0
  4. package/builder/assets/{vendor.9bf2fcb4.js → vendor.001dcf8c.js} +163 -163
  5. package/builder/index.html +3 -3
  6. package/coverage/clover.xml +866 -792
  7. package/coverage/coverage-final.json +26 -26
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/automation.js.html +111 -12
  11. package/coverage/lcov-report/api/controllers/backup.js.html +9 -6
  12. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/datasource.js.html +16 -16
  15. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/index.html +21 -21
  17. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  23. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/external.js.html +47 -17
  27. package/coverage/lcov-report/api/controllers/row/index.html +34 -34
  28. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +95 -11
  30. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/utils.js.html +17 -8
  32. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  37. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  46. package/coverage/lcov-report/api/index.html +15 -15
  47. package/coverage/lcov-report/api/index.js.html +22 -13
  48. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/automation.js.html +32 -2
  52. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/index.html +1 -1
  59. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  73. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  76. package/coverage/lcov-report/automations/actions.js.html +1 -1
  77. package/coverage/lcov-report/automations/automationUtils.js.html +57 -12
  78. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  79. package/coverage/lcov-report/automations/index.html +17 -17
  80. package/coverage/lcov-report/automations/index.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/filter.js.html +58 -34
  87. package/coverage/lcov-report/automations/steps/index.html +11 -11
  88. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggers.js.html +4 -4
  107. package/coverage/lcov-report/constants/index.html +1 -1
  108. package/coverage/lcov-report/constants/index.js.html +1 -1
  109. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  110. package/coverage/lcov-report/constants/screens.js.html +1 -1
  111. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  112. package/coverage/lcov-report/db/index.html +14 -14
  113. package/coverage/lcov-report/db/index.js.html +1 -1
  114. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/index.html +13 -13
  116. package/coverage/lcov-report/db/linkedRows/index.js.html +10 -7
  117. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  118. package/coverage/lcov-report/db/newid.js.html +2 -2
  119. package/coverage/lcov-report/db/utils.js.html +27 -51
  120. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  121. package/coverage/lcov-report/events/index.html +1 -1
  122. package/coverage/lcov-report/events/index.js.html +1 -1
  123. package/coverage/lcov-report/events/utils.js.html +1 -1
  124. package/coverage/lcov-report/index.html +74 -74
  125. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  126. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  127. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  128. package/coverage/lcov-report/middleware/builder.js.html +12 -12
  129. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  130. package/coverage/lcov-report/middleware/index.html +1 -1
  131. package/coverage/lcov-report/middleware/joi-validator.js.html +10 -10
  132. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  133. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  134. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  135. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  136. package/coverage/lcov-report/threads/automation.js.html +18 -9
  137. package/coverage/lcov-report/threads/index.html +25 -25
  138. package/coverage/lcov-report/threads/query.js.html +280 -76
  139. package/coverage/lcov-report/threads/utils.js.html +4 -4
  140. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  141. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  142. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  143. package/coverage/lcov-report/utilities/global.js.html +14 -14
  144. package/coverage/lcov-report/utilities/index.html +1 -1
  145. package/coverage/lcov-report/utilities/index.js.html +9 -9
  146. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  147. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  148. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  149. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  150. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  151. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  152. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  153. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  154. package/coverage/lcov-report/utilities/security.js.html +2 -2
  155. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  156. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  157. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  158. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  159. package/coverage/lcov-report/utilities/users.js.html +1 -1
  160. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  161. package/coverage/lcov.info +1554 -1422
  162. package/dist/api/controllers/application.js +18 -15
  163. package/dist/api/controllers/automation.js +28 -2
  164. package/dist/api/controllers/backup.js +3 -2
  165. package/dist/api/controllers/query/index.js +25 -0
  166. package/dist/api/controllers/row/external.js +19 -7
  167. package/dist/api/controllers/row/internalSearch.js +22 -1
  168. package/dist/api/controllers/row/utils.js +3 -0
  169. package/dist/api/index.js +4 -1
  170. package/dist/api/routes/automation.js +2 -0
  171. package/dist/automations/automationUtils.js +16 -4
  172. package/dist/automations/logging/index.js +70 -0
  173. package/dist/automations/steps/filter.js +38 -29
  174. package/dist/automations/triggers.js +1 -1
  175. package/dist/db/linkedRows/index.js +1 -0
  176. package/dist/db/utils.js +4 -31
  177. package/dist/definitions/datasource.js +1 -0
  178. package/dist/environment.js +1 -0
  179. package/dist/integrations/airtable.js +1 -0
  180. package/dist/integrations/arangodb.js +1 -0
  181. package/dist/integrations/base/sql.js +20 -3
  182. package/dist/integrations/couchdb.js +1 -0
  183. package/dist/integrations/dynamodb.js +1 -0
  184. package/dist/integrations/elasticsearch.js +1 -0
  185. package/dist/integrations/firebase.js +1 -0
  186. package/dist/integrations/googlesheets.js +1 -0
  187. package/dist/integrations/index.js +4 -0
  188. package/dist/integrations/microsoftSqlServer.js +2 -1
  189. package/dist/integrations/mongodb.js +1 -0
  190. package/dist/integrations/mysql.js +2 -1
  191. package/dist/integrations/oracle.js +1 -0
  192. package/dist/integrations/postgres.js +2 -1
  193. package/dist/integrations/queries/sql.js +3 -0
  194. package/dist/integrations/redis.js +1 -0
  195. package/dist/integrations/rest.js +2 -1
  196. package/dist/integrations/s3.js +1 -0
  197. package/dist/integrations/snowflake.js +102 -0
  198. package/dist/package.json +7 -6
  199. package/dist/tests/utilities/TestConfiguration.js +19 -6
  200. package/dist/threads/automation.js +6 -3
  201. package/dist/threads/index.js +15 -1
  202. package/dist/threads/query.js +53 -8
  203. package/dist/tsconfig.build.tsbuildinfo +1 -1
  204. package/dist/utilities/fileSystem/index.js +16 -6
  205. package/package.json +8 -7
  206. package/scripts/integrations/oracle/instantclient/linux/arm64/basiclite-19.10.zip +0 -0
  207. package/scripts/integrations/oracle/instantclient/linux/arm64/install.sh +23 -0
  208. package/scripts/integrations/oracle/instantclient/linux/install.sh +10 -0
  209. package/src/api/controllers/application.ts +18 -14
  210. package/src/api/controllers/automation.js +35 -2
  211. package/src/api/controllers/backup.js +3 -2
  212. package/src/api/controllers/query/index.ts +29 -1
  213. package/src/api/controllers/row/external.js +19 -9
  214. package/src/api/controllers/row/internalSearch.js +28 -0
  215. package/src/api/controllers/row/utils.js +3 -0
  216. package/src/api/index.js +4 -1
  217. package/src/api/routes/automation.js +10 -0
  218. package/src/api/routes/tests/query.spec.js +166 -0
  219. package/src/automations/automationUtils.js +19 -4
  220. package/src/automations/logging/index.ts +35 -0
  221. package/src/automations/steps/filter.js +36 -28
  222. package/src/automations/tests/filter.spec.js +2 -1
  223. package/src/automations/triggers.js +1 -1
  224. package/src/db/linkedRows/index.js +1 -0
  225. package/src/db/utils.js +5 -13
  226. package/src/definitions/common.ts +1 -0
  227. package/src/definitions/datasource.ts +2 -0
  228. package/src/environment.js +1 -0
  229. package/src/integrations/airtable.ts +1 -0
  230. package/src/integrations/arangodb.ts +1 -0
  231. package/src/integrations/base/sql.ts +25 -11
  232. package/src/integrations/couchdb.ts +1 -0
  233. package/src/integrations/dynamodb.ts +1 -0
  234. package/src/integrations/elasticsearch.ts +1 -0
  235. package/src/integrations/firebase.ts +1 -0
  236. package/src/integrations/googlesheets.ts +1 -0
  237. package/src/integrations/index.ts +4 -0
  238. package/src/integrations/microsoftSqlServer.ts +2 -0
  239. package/src/integrations/mongodb.ts +1 -0
  240. package/src/integrations/mysql.ts +2 -0
  241. package/src/integrations/oracle.ts +1 -0
  242. package/src/integrations/postgres.ts +2 -0
  243. package/src/integrations/queries/sql.ts +3 -1
  244. package/src/integrations/redis.ts +1 -0
  245. package/src/integrations/rest.ts +2 -1
  246. package/src/integrations/s3.ts +1 -0
  247. package/src/integrations/snowflake.ts +99 -0
  248. package/src/integrations/tests/rest.spec.js +16 -1
  249. package/src/migrations/tests/index.spec.ts +18 -2
  250. package/src/module.d.ts +2 -0
  251. package/src/tests/utilities/TestConfiguration.js +22 -3
  252. package/src/threads/automation.js +6 -3
  253. package/src/threads/index.ts +5 -1
  254. package/src/threads/query.js +78 -10
  255. package/src/utilities/fileSystem/index.js +22 -8
  256. package/builder/assets/index.24307ca0.css +0 -6
  257. package/builder/assets/index.36419068.js +0 -1316
@@ -1,5 +1,10 @@
1
1
  const { getTable } = require("../api/controllers/table/utils")
2
- const { findHBSBlocks } = require("@budibase/string-templates")
2
+ const {
3
+ findHBSBlocks,
4
+ decodeJSBinding,
5
+ isJSBinding,
6
+ encodeJSBinding,
7
+ } = require("@budibase/string-templates")
3
8
 
4
9
  /**
5
10
  * When values are input to the system generally they will be of type string as this is required for template strings.
@@ -77,11 +82,21 @@ exports.getError = err => {
77
82
  }
78
83
 
79
84
  exports.substituteLoopStep = (hbsString, substitute) => {
80
- let blocks = findHBSBlocks(hbsString)
85
+ let blocks = []
86
+ let checkForJS = isJSBinding(hbsString)
87
+ if (checkForJS) {
88
+ hbsString = decodeJSBinding(hbsString)
89
+ blocks.push(hbsString)
90
+ } else {
91
+ blocks = findHBSBlocks(hbsString)
92
+ }
81
93
  for (let block of blocks) {
82
- let oldBlock = block
83
94
  block = block.replace(/loop/, substitute)
84
- hbsString = hbsString.replace(new RegExp(oldBlock, "g"), block)
95
+ if (checkForJS) {
96
+ hbsString = encodeJSBinding(block)
97
+ } else {
98
+ hbsString = block
99
+ }
85
100
  }
86
101
 
87
102
  return hbsString
@@ -0,0 +1,35 @@
1
+ import * as env from "../../environment"
2
+ import { AutomationResults, Automation, App } from "@budibase/types"
3
+ import { automations } from "@budibase/pro"
4
+ import { db as dbUtils } from "@budibase/backend-core"
5
+
6
+ export async function storeLog(
7
+ automation: Automation,
8
+ results: AutomationResults
9
+ ) {
10
+ // can disable this if un-needed in self-host, also only do this for prod apps
11
+ if (env.DISABLE_AUTOMATION_LOGS) {
12
+ return
13
+ }
14
+ await automations.logs.storeLog(automation, results)
15
+ }
16
+
17
+ export async function checkAppMetadata(apps: App[]) {
18
+ const maxStartDate = await automations.logs.oldestLogDate()
19
+ for (let metadata of apps) {
20
+ if (!metadata.automationErrors) {
21
+ continue
22
+ }
23
+ for (let [key, errors] of Object.entries(metadata.automationErrors)) {
24
+ const updated = []
25
+ for (let error of errors) {
26
+ const startDate = error.split(dbUtils.SEPARATOR)[2]
27
+ if (startDate > maxStartDate) {
28
+ updated.push(error)
29
+ }
30
+ }
31
+ metadata.automationErrors[key] = updated
32
+ }
33
+ }
34
+ return apps
35
+ }
@@ -50,43 +50,51 @@ exports.definition = {
50
50
  outputs: {
51
51
  properties: {
52
52
  success: {
53
+ type: "boolean",
54
+ description: "Whether the action was successful",
55
+ },
56
+ result: {
53
57
  type: "boolean",
54
58
  description: "Whether the logic block passed",
55
59
  },
56
60
  },
57
- required: ["success"],
61
+ required: ["success", "result"],
58
62
  },
59
63
  },
60
64
  }
61
65
 
62
66
  exports.run = async function filter({ inputs }) {
63
- let { field, condition, value } = inputs
64
- // coerce types so that we can use them
65
- if (!isNaN(value) && !isNaN(field)) {
66
- value = parseFloat(value)
67
- field = parseFloat(field)
68
- } else if (!isNaN(Date.parse(value)) && !isNaN(Date.parse(field))) {
69
- value = Date.parse(value)
70
- field = Date.parse(field)
71
- }
72
- let success = false
73
- if (typeof field !== "object" && typeof value !== "object") {
74
- switch (condition) {
75
- case FilterConditions.EQUAL:
76
- success = field === value
77
- break
78
- case FilterConditions.NOT_EQUAL:
79
- success = field !== value
80
- break
81
- case FilterConditions.GREATER_THAN:
82
- success = field > value
83
- break
84
- case FilterConditions.LESS_THAN:
85
- success = field < value
86
- break
67
+ try {
68
+ let { field, condition, value } = inputs
69
+ // coerce types so that we can use them
70
+ if (!isNaN(value) && !isNaN(field)) {
71
+ value = parseFloat(value)
72
+ field = parseFloat(field)
73
+ } else if (!isNaN(Date.parse(value)) && !isNaN(Date.parse(field))) {
74
+ value = Date.parse(value)
75
+ field = Date.parse(field)
76
+ }
77
+ let result = false
78
+ if (typeof field !== "object" && typeof value !== "object") {
79
+ switch (condition) {
80
+ case FilterConditions.EQUAL:
81
+ result = field === value
82
+ break
83
+ case FilterConditions.NOT_EQUAL:
84
+ result = field !== value
85
+ break
86
+ case FilterConditions.GREATER_THAN:
87
+ result = field > value
88
+ break
89
+ case FilterConditions.LESS_THAN:
90
+ result = field < value
91
+ break
92
+ }
93
+ } else {
94
+ result = false
87
95
  }
88
- } else {
89
- success = false
96
+ return { success: true, result }
97
+ } catch (err) {
98
+ return { success: false, result: false }
90
99
  }
91
- return { success }
92
100
  }
@@ -6,7 +6,8 @@ describe("test the filter logic", () => {
6
6
  let res = await setup.runStep(setup.actions.FILTER.stepId,
7
7
  { field, condition, value }
8
8
  )
9
- expect(res.success).toEqual(pass)
9
+ expect(res.result).toEqual(pass)
10
+ expect(res.success).toEqual(true)
10
11
  }
11
12
 
12
13
  it("should be able test equality", async () => {
@@ -97,7 +97,7 @@ exports.externalTrigger = async function (
97
97
  // values are likely to be submitted as strings, so we shall convert to correct type
98
98
  const coercedFields = {}
99
99
  const fields = automation.definition.trigger.inputs.fields
100
- for (let key of Object.keys(fields)) {
100
+ for (let key of Object.keys(fields || {})) {
101
101
  coercedFields[key] = coerce(params.fields[key], fields[key])
102
102
  }
103
103
  params.fields = coercedFields
@@ -65,6 +65,7 @@ async function getLinksForRows(rows) {
65
65
  // return duplicates, could be querying for both tables in a relation
66
66
  return getUniqueByProp(
67
67
  responses
68
+ .filter(el => el != null)
68
69
  // create a unique ID which we can use for getting only unique ones
69
70
  .map(el => ({ ...el, unique: el.id + el.thisId + el.fieldName })),
70
71
  "unique"
package/src/db/utils.js CHANGED
@@ -11,6 +11,8 @@ const {
11
11
  isProdAppID,
12
12
  getDevelopmentAppID,
13
13
  generateAppID,
14
+ getQueryIndex,
15
+ ViewNames,
14
16
  } = require("@budibase/backend-core/db")
15
17
 
16
18
  const UNICODE_MAX = "\ufff0"
@@ -22,11 +24,7 @@ const AppStatus = {
22
24
  }
23
25
 
24
26
  const DocumentTypes = {
25
- APP: CoreDocTypes.APP,
26
- DEV: CoreDocTypes.DEV,
27
- APP_DEV: CoreDocTypes.APP_DEV,
28
- APP_METADATA: CoreDocTypes.APP_METADATA,
29
- ROLE: CoreDocTypes.ROLE,
27
+ ...CoreDocTypes,
30
28
  TABLE: "ta",
31
29
  ROW: "ro",
32
30
  USER: "us",
@@ -45,11 +43,6 @@ const DocumentTypes = {
45
43
  USER_FLAG: "flag",
46
44
  }
47
45
 
48
- const ViewNames = {
49
- LINK: "by_link",
50
- ROUTING: "screen_routes",
51
- }
52
-
53
46
  const InternalTables = {
54
47
  USER_METADATA: "ta_users",
55
48
  }
@@ -74,6 +67,7 @@ exports.isDevAppID = isDevAppID
74
67
  exports.isProdAppID = isProdAppID
75
68
  exports.USER_METDATA_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
76
69
  exports.LINK_USER_METADATA_PREFIX = `${DocumentTypes.LINK}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
70
+ exports.TABLE_ROW_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${DocumentTypes.TABLE}`
77
71
  exports.ViewNames = ViewNames
78
72
  exports.InternalTables = InternalTables
79
73
  exports.DocumentTypes = DocumentTypes
@@ -88,9 +82,7 @@ exports.generateDevAppID = getDevelopmentAppID
88
82
  exports.generateRoleID = generateRoleID
89
83
  exports.getRoleParams = getRoleParams
90
84
 
91
- exports.getQueryIndex = viewName => {
92
- return `database/${viewName}`
93
- }
85
+ exports.getQueryIndex = getQueryIndex
94
86
 
95
87
  /**
96
88
  * If creating DB allDocs/query params with only a single top level ID this can be used, this
@@ -12,6 +12,7 @@ export interface Application extends Base {
12
12
  export interface FieldSchema {
13
13
  // TODO: replace with field types enum when done
14
14
  type: string
15
+ externalType?: string
15
16
  fieldName?: string
16
17
  name: string
17
18
  tableId?: string
@@ -50,6 +50,7 @@ export enum SourceNames {
50
50
  GOOGLE_SHEETS = "GOOGLE_SHEETS",
51
51
  FIRESTORE = "FIRESTORE",
52
52
  REDIS = "REDIS",
53
+ SNOWFLAKE = "SNOWFLAKE",
53
54
  }
54
55
 
55
56
  export enum IncludeRelationships {
@@ -93,6 +94,7 @@ export interface Integration {
93
94
  relationships?: boolean
94
95
  description: string
95
96
  friendlyName: string
97
+ type?: string
96
98
  datasource: {}
97
99
  query: {
98
100
  [key: string]: QueryDefinition
@@ -78,6 +78,7 @@ module.exports = {
78
78
  ALLOW_DEV_AUTOMATIONS: process.env.ALLOW_DEV_AUTOMATIONS,
79
79
  DISABLE_THREADING: process.env.DISABLE_THREADING,
80
80
  DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE,
81
+ DISABLE_AUTOMATION_LOGS: process.env.DISABLE_AUTOMATION_LOGS,
81
82
  MULTI_TENANCY: process.env.MULTI_TENANCY,
82
83
  ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
83
84
  SELF_HOSTED: process.env.SELF_HOSTED,
@@ -18,6 +18,7 @@ module AirtableModule {
18
18
  description:
19
19
  "Airtable is a spreadsheet-database hybrid, with the features of a database but applied to a spreadsheet.",
20
20
  friendlyName: "Airtable",
21
+ type: "Spreadsheet",
21
22
  datasource: {
22
23
  apiKey: {
23
24
  type: DatasourceFieldTypes.PASSWORD,
@@ -19,6 +19,7 @@ module ArangoModule {
19
19
  const SCHEMA: Integration = {
20
20
  docs: "https://github.com/arangodb/arangojs",
21
21
  friendlyName: "ArangoDB",
22
+ type: "Non-relational",
22
23
  description:
23
24
  "ArangoDB is a scalable open-source multi-model database natively supporting graph, document and search. All supported data models & access patterns can be combined in queries allowing for maximal flexibility. ",
24
25
  datasource: {
@@ -89,6 +89,28 @@ function parseFilters(filters: SearchFilters | undefined): SearchFilters {
89
89
  return filters
90
90
  }
91
91
 
92
+ function generateSelectStatement(
93
+ json: QueryJson,
94
+ knex: Knex
95
+ ): (string | Knex.Raw)[] {
96
+ const { resource, meta } = json
97
+ const schema = meta?.table?.schema
98
+ return resource.fields.map(field => {
99
+ const fieldNames = field.split(/\./g)
100
+ const tableName = fieldNames[0]
101
+ const columnName = fieldNames[1]
102
+ if (columnName && knex.client.config.client === SqlClients.POSTGRES) {
103
+ const externalType = schema?.[columnName].externalType
104
+ if (externalType?.includes("money")) {
105
+ return knex.raw(
106
+ `"${tableName}"."${columnName}"::money::numeric as "${field}"`
107
+ )
108
+ }
109
+ }
110
+ return `${field} as ${field}`
111
+ })
112
+ }
113
+
92
114
  class InternalBuilder {
93
115
  private readonly client: string
94
116
 
@@ -216,9 +238,7 @@ class InternalBuilder {
216
238
  }
217
239
 
218
240
  addRelationships(
219
- knex: Knex,
220
241
  query: KnexQuery,
221
- fields: string | string[],
222
242
  fromTable: string,
223
243
  relationships: RelationshipsJson[] | undefined
224
244
  ): KnexQuery {
@@ -323,12 +343,12 @@ class InternalBuilder {
323
343
  if (!resource) {
324
344
  resource = { fields: [] }
325
345
  }
326
- let selectStatement: string | string[] = "*"
346
+ let selectStatement: string | (string | Knex.Raw)[] = "*"
327
347
  // handle select
328
348
  if (resource.fields && resource.fields.length > 0) {
329
349
  // select the resources as the format "table.columnName" - this is what is provided
330
350
  // by the resource builder further up
331
- selectStatement = resource.fields.map(field => `${field} as ${field}`)
351
+ selectStatement = generateSelectStatement(json, knex)
332
352
  }
333
353
  let foundLimit = limit || BASE_LIMIT
334
354
  // handle pagination
@@ -363,13 +383,7 @@ class InternalBuilder {
363
383
  preQuery = this.addSorting(preQuery, json)
364
384
  }
365
385
  // handle joins
366
- query = this.addRelationships(
367
- knex,
368
- preQuery,
369
- selectStatement,
370
- tableName,
371
- relationships
372
- )
386
+ query = this.addRelationships(preQuery, tableName, relationships)
373
387
  return this.addFilters(query, filters, { relationship: true })
374
388
  }
375
389
 
@@ -16,6 +16,7 @@ module CouchDBModule {
16
16
  const SCHEMA: Integration = {
17
17
  docs: "https://docs.couchdb.org/en/stable/",
18
18
  friendlyName: "CouchDB",
19
+ type: "Non-relational",
19
20
  description:
20
21
  "Apache CouchDB is an open-source document-oriented NoSQL database, implemented in Erlang.",
21
22
  datasource: {
@@ -21,6 +21,7 @@ module DynamoModule {
21
21
  description:
22
22
  "Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale.",
23
23
  friendlyName: "DynamoDB",
24
+ type: "Non-relational",
24
25
  datasource: {
25
26
  region: {
26
27
  type: DatasourceFieldTypes.STRING,
@@ -17,6 +17,7 @@ module ElasticsearchModule {
17
17
  description:
18
18
  "Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents.",
19
19
  friendlyName: "ElasticSearch",
20
+ type: "Non-relational",
20
21
  datasource: {
21
22
  url: {
22
23
  type: DatasourceFieldTypes.STRING,
@@ -16,6 +16,7 @@ module Firebase {
16
16
  const SCHEMA: Integration = {
17
17
  docs: "https://firebase.google.com/docs/firestore/quickstart",
18
18
  friendlyName: "Firestore",
19
+ type: "Non-relational",
19
20
  description:
20
21
  "Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud.",
21
22
  datasource: {
@@ -49,6 +49,7 @@ module GoogleSheetsModule {
49
49
  description:
50
50
  "Create and collaborate on online spreadsheets in real-time and from any device. ",
51
51
  friendlyName: "Google Sheets",
52
+ type: "Spreadsheet",
52
53
  datasource: {
53
54
  spreadsheetId: {
54
55
  display: "Google Sheet URL",
@@ -12,6 +12,7 @@ const rest = require("./rest")
12
12
  const googlesheets = require("./googlesheets")
13
13
  const firebase = require("./firebase")
14
14
  const redis = require("./redis")
15
+ const snowflake = require("./snowflake")
15
16
  const { SourceNames } = require("../definitions/datasource")
16
17
  const environment = require("../environment")
17
18
 
@@ -29,6 +30,7 @@ const DEFINITIONS = {
29
30
  [SourceNames.REST]: rest.schema,
30
31
  [SourceNames.FIRESTORE]: firebase.schema,
31
32
  [SourceNames.REDIS]: redis.schema,
33
+ [SourceNames.SNOWFLAKE]: snowflake.schema,
32
34
  }
33
35
 
34
36
  const INTEGRATIONS = {
@@ -46,6 +48,8 @@ const INTEGRATIONS = {
46
48
  [SourceNames.FIRESTORE]: firebase.integration,
47
49
  [SourceNames.GOOGLE_SHEETS]: googlesheets.integration,
48
50
  [SourceNames.REDIS]: redis.integration,
51
+ [SourceNames.FIREBASE]: firebase.integration,
52
+ [SourceNames.SNOWFLAKE]: snowflake.integration,
49
53
  }
50
54
 
51
55
  // optionally add oracle integration if the oracle binary can be installed
@@ -44,6 +44,7 @@ module MSSQLModule {
44
44
  description:
45
45
  "Microsoft SQL Server is a relational database management system developed by Microsoft. ",
46
46
  friendlyName: "MS SQL Server",
47
+ type: "Relational",
47
48
  datasource: {
48
49
  user: {
49
50
  type: DatasourceFieldTypes.STRING,
@@ -246,6 +247,7 @@ module MSSQLModule {
246
247
  autocolumn: !!autoColumns.find((col: string) => col === name),
247
248
  name: name,
248
249
  ...convertSqlType(def.DATA_TYPE),
250
+ externalType: def.DATA_TYPE,
249
251
  }
250
252
  }
251
253
  tables[tableName] = {
@@ -24,6 +24,7 @@ module MongoDBModule {
24
24
  const SCHEMA: Integration = {
25
25
  docs: "https://github.com/mongodb/node-mongodb-native",
26
26
  friendlyName: "MongoDB",
27
+ type: "Non-relational",
27
28
  description:
28
29
  "MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era.",
29
30
  datasource: {
@@ -36,6 +36,7 @@ module MySQLModule {
36
36
  docs: "https://github.com/sidorares/node-mysql2",
37
37
  plus: true,
38
38
  friendlyName: "MySQL",
39
+ type: "Relational",
39
40
  description:
40
41
  "MySQL Database Service is a fully managed database service to deploy cloud-native applications. ",
41
42
  datasource: {
@@ -232,6 +233,7 @@ module MySQLModule {
232
233
  autocolumn: isAuto,
233
234
  constraints,
234
235
  ...convertSqlType(column.Type),
236
+ externalType: column.Type,
235
237
  }
236
238
  }
237
239
  if (!tables[tableName]) {
@@ -40,6 +40,7 @@ module OracleModule {
40
40
  docs: "https://github.com/oracle/node-oracledb",
41
41
  plus: true,
42
42
  friendlyName: "Oracle",
43
+ type: "Relational",
43
44
  description:
44
45
  "Oracle Database is an object-relational database management system developed by Oracle Corporation",
45
46
  datasource: {
@@ -47,6 +47,7 @@ module PostgresModule {
47
47
  docs: "https://node-postgres.com",
48
48
  plus: true,
49
49
  friendlyName: "PostgreSQL",
50
+ type: "Relational",
50
51
  description:
51
52
  "PostgreSQL, also known as Postgres, is a free and open-source relational database management system emphasizing extensibility and SQL compliance.",
52
53
  datasource: {
@@ -271,6 +272,7 @@ module PostgresModule {
271
272
  autocolumn: isAuto,
272
273
  name: columnName,
273
274
  ...convertSqlType(column.data_type),
275
+ externalType: column.data_type,
274
276
  }
275
277
  }
276
278
 
@@ -9,7 +9,9 @@ export function enrichQueryFields(
9
9
  parameters = {}
10
10
  ) {
11
11
  const enrichedQuery: { [key: string]: any } = Array.isArray(fields) ? [] : {}
12
-
12
+ if (!fields || !parameters) {
13
+ return enrichedQuery
14
+ }
13
15
  // enrich the fields with dynamic parameters
14
16
  for (let key of Object.keys(fields)) {
15
17
  if (fields[key] == null) {
@@ -17,6 +17,7 @@ module RedisModule {
17
17
  docs: "https://redis.io/docs/",
18
18
  description: "",
19
19
  friendlyName: "Redis",
20
+ type: "Non-relational",
20
21
  datasource: {
21
22
  host: {
22
23
  type: "string",
@@ -64,6 +64,7 @@ module RestModule {
64
64
  description:
65
65
  "With the REST API datasource, you can connect, query and pull data from multiple REST APIs. You can then use the retrieved data to build apps.",
66
66
  friendlyName: "REST API",
67
+ type: "API",
67
68
  datasource: {
68
69
  url: {
69
70
  type: DatasourceFieldTypes.STRING,
@@ -286,7 +287,7 @@ module RestModule {
286
287
  input.body = form
287
288
  break
288
289
  case BodyTypes.XML:
289
- if (object != null) {
290
+ if (object != null && Object.keys(object).length) {
290
291
  string = new XmlBuilder().buildObject(object)
291
292
  }
292
293
  input.body = string
@@ -17,6 +17,7 @@ module S3Module {
17
17
  description:
18
18
  "Amazon Simple Storage Service (Amazon S3) is an object storage service that offers industry-leading scalability, data availability, security, and performance.",
19
19
  friendlyName: "Amazon S3",
20
+ type: "Object store",
20
21
  datasource: {
21
22
  region: {
22
23
  type: "string",
@@ -0,0 +1,99 @@
1
+ import { Integration, QueryTypes, SqlQuery } from "../definitions/datasource"
2
+ import { Snowflake } from "snowflake-promise"
3
+
4
+ module SnowflakeModule {
5
+ interface SnowflakeConfig {
6
+ account: string
7
+ username: string
8
+ password: string
9
+ warehouse: string
10
+ database: string
11
+ schema: string
12
+ }
13
+
14
+ const SCHEMA: Integration = {
15
+ docs: "https://developers.snowflake.com/",
16
+ description:
17
+ "Snowflake is a solution for data warehousing, data lakes, data engineering, data science, data application development, and securely sharing and consuming shared data.",
18
+ friendlyName: "Snowflake",
19
+ type: "Relational",
20
+ datasource: {
21
+ account: {
22
+ type: "string",
23
+ required: true,
24
+ },
25
+ username: {
26
+ type: "string",
27
+ required: true,
28
+ },
29
+ password: {
30
+ type: "password",
31
+ required: true,
32
+ },
33
+ warehouse: {
34
+ type: "string",
35
+ required: true,
36
+ },
37
+ database: {
38
+ type: "string",
39
+ required: true,
40
+ },
41
+ schema: {
42
+ type: "string",
43
+ required: true,
44
+ },
45
+ },
46
+ query: {
47
+ create: {
48
+ type: QueryTypes.SQL,
49
+ },
50
+ read: {
51
+ type: QueryTypes.SQL,
52
+ },
53
+ update: {
54
+ type: QueryTypes.SQL,
55
+ },
56
+ delete: {
57
+ type: QueryTypes.SQL,
58
+ },
59
+ },
60
+ }
61
+
62
+ class SnowflakeIntegration {
63
+ private client: Snowflake
64
+
65
+ constructor(config: SnowflakeConfig) {
66
+ this.client = new Snowflake(config)
67
+ }
68
+
69
+ async internalQuery(query: SqlQuery) {
70
+ await this.client.connect()
71
+ try {
72
+ return await this.client.execute(query.sql)
73
+ } catch (err: any) {
74
+ throw err?.message.split(":")[1] || err?.message
75
+ }
76
+ }
77
+
78
+ async create(query: SqlQuery) {
79
+ return this.internalQuery(query)
80
+ }
81
+
82
+ async read(query: SqlQuery) {
83
+ return this.internalQuery(query)
84
+ }
85
+
86
+ async update(query: SqlQuery) {
87
+ return this.internalQuery(query)
88
+ }
89
+
90
+ async delete(query: SqlQuery) {
91
+ return this.internalQuery(query)
92
+ }
93
+ }
94
+
95
+ module.exports = {
96
+ schema: SCHEMA,
97
+ integration: SnowflakeIntegration,
98
+ }
99
+ }