@budibase/server 1.0.35 → 1.0.39

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 (375) hide show
  1. package/__mocks__/node-fetch.ts +21 -0
  2. package/builder/assets/bb-spaceship.8f6e81e1.svg +227 -0
  3. package/builder/assets/index.3079d0f9.js +1348 -0
  4. package/builder/assets/{index.4fb3f887.css → index.39e01193.css} +1 -1
  5. package/builder/assets/{vendor.470042a4.js → vendor.f9faf6ab.js} +88 -88
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +1589 -1344
  8. package/coverage/coverage-final.json +75 -74
  9. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/apikeys.js.html +3 -3
  11. package/coverage/lcov-report/api/controllers/application.js.html +73 -64
  12. package/coverage/lcov-report/api/controllers/auth.js.html +2 -2
  13. package/coverage/lcov-report/api/controllers/automation.js.html +22 -10
  14. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/cloud.js.html +13 -4
  16. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  17. package/coverage/lcov-report/api/controllers/datasource.js.html +170 -68
  18. package/coverage/lcov-report/api/controllers/dev.js.html +3 -3
  19. package/coverage/lcov-report/api/controllers/hosting.js.html +3 -3
  20. package/coverage/lcov-report/api/controllers/index.html +39 -54
  21. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  25. package/coverage/lcov-report/api/controllers/query/index.html +126 -0
  26. package/coverage/lcov-report/api/controllers/{query.js.html → query/index.js.html} +225 -120
  27. package/coverage/lcov-report/api/controllers/query/validation.js.html +206 -0
  28. package/coverage/lcov-report/api/controllers/role.js.html +2 -2
  29. package/coverage/lcov-report/api/controllers/routing.js.html +2 -2
  30. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/index.html +22 -22
  32. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/row/internal.js.html +38 -11
  34. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +8 -5
  35. package/coverage/lcov-report/api/controllers/row/utils.js.html +29 -20
  36. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  37. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +120 -12
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +19 -7
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +6 -6
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +2 -2
  55. package/coverage/lcov-report/api/routes/application.js.html +2 -2
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +2 -2
  58. package/coverage/lcov-report/api/routes/backup.js.html +2 -2
  59. package/coverage/lcov-report/api/routes/cloud.js.html +2 -2
  60. package/coverage/lcov-report/api/routes/component.js.html +2 -2
  61. package/coverage/lcov-report/api/routes/datasource.js.html +2 -2
  62. package/coverage/lcov-report/api/routes/deploy.js.html +2 -2
  63. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  64. package/coverage/lcov-report/api/routes/hosting.js.html +2 -2
  65. package/coverage/lcov-report/api/routes/index.html +9 -9
  66. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/integration.js.html +2 -2
  68. package/coverage/lcov-report/api/routes/layout.js.html +2 -2
  69. package/coverage/lcov-report/api/routes/metadata.js.html +2 -2
  70. package/coverage/lcov-report/api/routes/permission.js.html +12 -3
  71. package/coverage/lcov-report/api/routes/query.js.html +20 -86
  72. package/coverage/lcov-report/api/routes/role.js.html +2 -2
  73. package/coverage/lcov-report/api/routes/routing.js.html +2 -2
  74. package/coverage/lcov-report/api/routes/row.js.html +2 -2
  75. package/coverage/lcov-report/api/routes/screen.js.html +2 -2
  76. package/coverage/lcov-report/api/routes/script.js.html +2 -2
  77. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  78. package/coverage/lcov-report/api/routes/table.js.html +2 -2
  79. package/coverage/lcov-report/api/routes/templates.js.html +2 -2
  80. package/coverage/lcov-report/api/routes/user.js.html +33 -3
  81. package/coverage/lcov-report/api/routes/view.js.html +2 -2
  82. package/coverage/lcov-report/api/routes/webhook.js.html +2 -2
  83. package/coverage/lcov-report/automations/actions.js.html +1 -1
  84. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  85. package/coverage/lcov-report/automations/bullboard.js.html +2 -2
  86. package/coverage/lcov-report/automations/index.html +20 -20
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +32 -8
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/index.html +11 -11
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +5 -8
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  114. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  115. package/coverage/lcov-report/automations/utils.js.html +49 -16
  116. package/coverage/lcov-report/constants/index.html +1 -1
  117. package/coverage/lcov-report/constants/index.js.html +25 -25
  118. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  119. package/coverage/lcov-report/constants/screens.js.html +2 -2
  120. package/coverage/lcov-report/db/client.js.html +19 -19
  121. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  122. package/coverage/lcov-report/db/index.html +15 -15
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  125. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +108 -81
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +1 -1
  133. package/coverage/lcov-report/events/utils.js.html +1 -1
  134. package/coverage/lcov-report/index.html +99 -84
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +12 -12
  139. package/coverage/lcov-report/middleware/builder.js.html +10 -10
  140. package/coverage/lcov-report/middleware/currentapp.js.html +48 -36
  141. package/coverage/lcov-report/middleware/index.html +1 -1
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +11 -11
  143. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +2 -2
  146. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  147. package/coverage/lcov-report/threads/automation.js.html +3 -3
  148. package/coverage/lcov-report/threads/index.html +32 -32
  149. package/coverage/lcov-report/threads/index.js.html +12 -12
  150. package/coverage/lcov-report/threads/query.js.html +560 -65
  151. package/coverage/lcov-report/threads/utils.js.html +210 -15
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +2 -2
  154. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  155. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  156. package/coverage/lcov-report/utilities/global.js.html +28 -19
  157. package/coverage/lcov-report/utilities/index.html +19 -19
  158. package/coverage/lcov-report/utilities/index.js.html +70 -37
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  160. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +19 -19
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +247 -10
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  167. package/coverage/lcov-report/utilities/security.js.html +14 -5
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/users.js.html +1 -1
  170. package/coverage/lcov-report/utilities/workerRequests.js.html +22 -22
  171. package/coverage/lcov.info +2735 -2313
  172. package/dist/api/controllers/apikeys.js +2 -2
  173. package/dist/api/controllers/application.js +4 -4
  174. package/dist/api/controllers/auth.js +1 -1
  175. package/dist/api/controllers/automation.js +7 -5
  176. package/dist/api/controllers/cloud.js +2 -2
  177. package/dist/api/controllers/datasource.js +29 -0
  178. package/dist/api/controllers/deploy/index.js +2 -2
  179. package/dist/api/controllers/dev.js +2 -2
  180. package/dist/api/controllers/hosting.js +2 -2
  181. package/dist/api/controllers/permission.js +2 -2
  182. package/dist/api/controllers/query/import/index.js +79 -0
  183. package/dist/api/controllers/query/import/sources/base/index.js +64 -0
  184. package/dist/api/controllers/query/import/sources/base/openapi.js +42 -0
  185. package/dist/api/controllers/query/import/sources/curl.js +96 -0
  186. package/dist/api/controllers/query/import/sources/openapi2.js +142 -0
  187. package/dist/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  188. package/dist/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  189. package/dist/api/controllers/{query.js → query/index.js} +88 -56
  190. package/dist/api/controllers/query/validation.js +38 -0
  191. package/dist/api/controllers/role.js +1 -1
  192. package/dist/api/controllers/routing.js +1 -1
  193. package/dist/api/controllers/row/internal.js +14 -6
  194. package/dist/api/controllers/row/internalSearch.js +3 -2
  195. package/dist/api/controllers/row/utils.js +13 -6
  196. package/dist/api/controllers/screen.js +1 -1
  197. package/dist/api/controllers/user.js +40 -4
  198. package/dist/api/controllers/webhook.js +5 -1
  199. package/dist/api/index.js +1 -1
  200. package/dist/api/routes/apikeys.js +1 -1
  201. package/dist/api/routes/application.js +1 -1
  202. package/dist/api/routes/automation.js +1 -1
  203. package/dist/api/routes/backup.js +1 -1
  204. package/dist/api/routes/cloud.js +1 -1
  205. package/dist/api/routes/component.js +1 -1
  206. package/dist/api/routes/datasource.js +1 -1
  207. package/dist/api/routes/deploy.js +1 -1
  208. package/dist/api/routes/dev.js +1 -1
  209. package/dist/api/routes/hosting.js +1 -1
  210. package/dist/api/routes/integration.js +1 -1
  211. package/dist/api/routes/layout.js +1 -1
  212. package/dist/api/routes/metadata.js +1 -1
  213. package/dist/api/routes/permission.js +1 -1
  214. package/dist/api/routes/query.js +6 -34
  215. package/dist/api/routes/role.js +1 -1
  216. package/dist/api/routes/routing.js +1 -1
  217. package/dist/api/routes/row.js +1 -1
  218. package/dist/api/routes/screen.js +1 -1
  219. package/dist/api/routes/script.js +1 -1
  220. package/dist/api/routes/static.js +1 -1
  221. package/dist/api/routes/table.js +1 -1
  222. package/dist/api/routes/templates.js +1 -1
  223. package/dist/api/routes/tests/utilities/TestFunctions.js +1 -1
  224. package/dist/api/routes/user.js +4 -2
  225. package/dist/api/routes/view.js +1 -1
  226. package/dist/api/routes/webhook.js +1 -1
  227. package/dist/app.js +1 -1
  228. package/dist/automations/bullboard.js +1 -1
  229. package/dist/automations/steps/executeQuery.js +9 -2
  230. package/dist/automations/steps/outgoingWebhook.js +2 -3
  231. package/dist/automations/utils.js +11 -1
  232. package/dist/constants/index.js +3 -3
  233. package/dist/constants/screens.js +1 -1
  234. package/dist/db/client.js +1 -1
  235. package/dist/db/utils.js +9 -1
  236. package/dist/definitions/datasource.js +6 -1
  237. package/dist/integrations/base/sqlTable.js +1 -1
  238. package/dist/integrations/rest.js +259 -120
  239. package/dist/integrations/utils.js +40 -37
  240. package/dist/middleware/authorized.js +2 -2
  241. package/dist/middleware/builder.js +2 -2
  242. package/dist/middleware/currentapp.js +6 -6
  243. package/dist/middleware/usageQuota.js +1 -1
  244. package/dist/package.json +11 -4
  245. package/dist/tests/utilities/TestConfiguration.js +55 -8
  246. package/dist/tests/utilities/structures.js +2 -2
  247. package/dist/threads/automation.js +2 -2
  248. package/dist/threads/query.js +195 -38
  249. package/dist/threads/utils.js +62 -1
  250. package/dist/tsconfig.tsbuildinfo +1 -1
  251. package/dist/utilities/budibaseDir.js +1 -1
  252. package/dist/utilities/fileSystem/utilities.js +2 -1
  253. package/dist/utilities/global.js +5 -5
  254. package/dist/utilities/index.js +11 -1
  255. package/dist/utilities/redis.js +1 -1
  256. package/dist/utilities/rowProcessor/index.js +76 -0
  257. package/dist/utilities/security.js +2 -2
  258. package/dist/utilities/usageQuota.js +2 -2
  259. package/dist/utilities/workerRequests.js +3 -3
  260. package/package.json +12 -5
  261. package/scripts/replicateApp.js +1 -1
  262. package/src/api/controllers/apikeys.js +2 -2
  263. package/src/api/controllers/application.js +7 -4
  264. package/src/api/controllers/auth.js +1 -1
  265. package/src/api/controllers/automation.js +8 -4
  266. package/src/api/controllers/cloud.js +5 -2
  267. package/src/api/controllers/datasource.js +34 -0
  268. package/src/api/controllers/deploy/index.js +2 -2
  269. package/src/api/controllers/dev.js +2 -2
  270. package/src/api/controllers/hosting.js +2 -2
  271. package/src/api/controllers/permission.js +2 -2
  272. package/src/api/controllers/query/import/index.ts +85 -0
  273. package/src/api/controllers/query/import/sources/base/index.ts +87 -0
  274. package/src/api/controllers/query/import/sources/base/openapi.ts +24 -0
  275. package/src/api/controllers/query/import/sources/curl.ts +102 -0
  276. package/src/api/controllers/query/import/sources/openapi2.ts +163 -0
  277. package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +103 -0
  278. package/src/api/controllers/query/import/sources/tests/curl/data/delete.txt +1 -0
  279. package/src/api/controllers/query/import/sources/tests/curl/data/empty-body.txt +2 -0
  280. package/src/api/controllers/query/import/sources/tests/curl/data/get.txt +1 -0
  281. package/src/api/controllers/query/import/sources/tests/curl/data/headers.txt +3 -0
  282. package/src/api/controllers/query/import/sources/tests/curl/data/patch.txt +2 -0
  283. package/src/api/controllers/query/import/sources/tests/curl/data/path.txt +1 -0
  284. package/src/api/controllers/query/import/sources/tests/curl/data/post.txt +2 -0
  285. package/src/api/controllers/query/import/sources/tests/curl/data/put.txt +2 -0
  286. package/src/api/controllers/query/import/sources/tests/curl/data/query.txt +1 -0
  287. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  288. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.yaml +160 -0
  289. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  290. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.yaml +711 -0
  291. package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +238 -0
  292. package/src/api/controllers/query/import/tests/index.spec.js +109 -0
  293. package/src/api/controllers/query/index.js +196 -0
  294. package/src/api/controllers/query/validation.js +42 -0
  295. package/src/api/controllers/role.js +1 -1
  296. package/src/api/controllers/routing.js +1 -1
  297. package/src/api/controllers/row/internal.js +14 -5
  298. package/src/api/controllers/row/internalSearch.js +3 -2
  299. package/src/api/controllers/row/utils.js +11 -8
  300. package/src/api/controllers/screen.js +1 -1
  301. package/src/api/controllers/user.js +39 -3
  302. package/src/api/controllers/webhook.js +5 -1
  303. package/src/api/index.js +1 -1
  304. package/src/api/routes/apikeys.js +1 -1
  305. package/src/api/routes/application.js +1 -1
  306. package/src/api/routes/automation.js +1 -1
  307. package/src/api/routes/backup.js +1 -1
  308. package/src/api/routes/cloud.js +1 -1
  309. package/src/api/routes/component.js +1 -1
  310. package/src/api/routes/datasource.js +1 -1
  311. package/src/api/routes/deploy.js +1 -1
  312. package/src/api/routes/dev.js +1 -1
  313. package/src/api/routes/hosting.js +1 -1
  314. package/src/api/routes/integration.js +1 -1
  315. package/src/api/routes/layout.js +1 -1
  316. package/src/api/routes/metadata.js +1 -1
  317. package/src/api/routes/permission.js +4 -1
  318. package/src/api/routes/query.js +14 -36
  319. package/src/api/routes/role.js +1 -1
  320. package/src/api/routes/routing.js +1 -1
  321. package/src/api/routes/row.js +1 -1
  322. package/src/api/routes/screen.js +1 -1
  323. package/src/api/routes/script.js +1 -1
  324. package/src/api/routes/static.js +1 -1
  325. package/src/api/routes/table.js +1 -1
  326. package/src/api/routes/templates.js +1 -1
  327. package/src/api/routes/tests/datasource.spec.js +45 -0
  328. package/src/api/routes/tests/permissions.spec.js +1 -1
  329. package/src/api/routes/tests/query.spec.js +70 -1
  330. package/src/api/routes/tests/role.spec.js +2 -2
  331. package/src/api/routes/tests/routing.spec.js +1 -1
  332. package/src/api/routes/tests/user.spec.js +1 -1
  333. package/src/api/routes/tests/utilities/TestFunctions.js +1 -1
  334. package/src/api/routes/user.js +11 -1
  335. package/src/api/routes/view.js +1 -1
  336. package/src/api/routes/webhook.js +1 -1
  337. package/src/app.ts +1 -1
  338. package/src/automations/bullboard.js +1 -1
  339. package/src/automations/steps/executeQuery.js +10 -2
  340. package/src/automations/steps/outgoingWebhook.js +2 -3
  341. package/src/automations/utils.js +12 -1
  342. package/src/constants/index.js +3 -3
  343. package/src/constants/screens.js +1 -1
  344. package/src/db/client.js +1 -1
  345. package/src/db/utils.js +10 -1
  346. package/src/definitions/common.ts +2 -16
  347. package/src/definitions/datasource.ts +98 -1
  348. package/src/integrations/base/IntegrationBase.ts +4 -4
  349. package/src/integrations/base/sqlTable.ts +1 -1
  350. package/src/integrations/rest.ts +311 -138
  351. package/src/integrations/tests/rest.spec.js +432 -21
  352. package/src/integrations/utils.ts +8 -7
  353. package/src/middleware/authorized.js +2 -2
  354. package/src/middleware/builder.js +2 -2
  355. package/src/middleware/currentapp.js +11 -7
  356. package/src/middleware/tests/authorized.spec.js +2 -2
  357. package/src/middleware/tests/currentapp.spec.js +35 -41
  358. package/src/middleware/tests/usageQuota.spec.js +1 -1
  359. package/src/middleware/usageQuota.js +1 -1
  360. package/src/tests/utilities/TestConfiguration.js +65 -8
  361. package/src/tests/utilities/structures.js +2 -2
  362. package/src/threads/automation.js +2 -2
  363. package/src/threads/query.js +204 -39
  364. package/src/threads/utils.js +66 -1
  365. package/src/utilities/budibaseDir.js +1 -1
  366. package/src/utilities/fileSystem/utilities.js +3 -1
  367. package/src/utilities/global.js +8 -5
  368. package/src/utilities/index.js +12 -1
  369. package/src/utilities/redis.js +1 -1
  370. package/src/utilities/rowProcessor/index.js +79 -0
  371. package/src/utilities/security.js +5 -2
  372. package/src/utilities/usageQuota.js +2 -2
  373. package/src/utilities/workerRequests.js +3 -3
  374. package/builder/assets/index.9ac33cf1.js +0 -1316
  375. package/src/api/controllers/query.js +0 -161
@@ -0,0 +1,238 @@
1
+ const { OpenAPI2 } = require("../../openapi2")
2
+ const fs = require("fs")
3
+ const path = require('path')
4
+
5
+ const getData = (file, extension) => {
6
+ return fs.readFileSync(path.join(__dirname, `./data/${file}/${file}.${extension}`), "utf8")
7
+ }
8
+
9
+ describe("OpenAPI2 Import", () => {
10
+ let openapi2
11
+
12
+ beforeEach(() => {
13
+ openapi2 = new OpenAPI2()
14
+ })
15
+
16
+ it("validates unsupported data", async () => {
17
+ let data
18
+ let supported
19
+
20
+ // non json / yaml
21
+ data = "curl http://example.com"
22
+ supported = await openapi2.isSupported(data)
23
+ expect(supported).toBe(false)
24
+
25
+ // Empty
26
+ data = ""
27
+ supported = await openapi2.isSupported(data)
28
+ expect(supported).toBe(false)
29
+ })
30
+
31
+ const init = async (file, extension) => {
32
+ await openapi2.isSupported(getData(file, extension))
33
+ }
34
+
35
+ const runTests = async (filename, test, assertions) => {
36
+ for (let extension of ["json", "yaml"]) {
37
+ await test(filename, extension, assertions)
38
+ }
39
+ }
40
+
41
+ const testImportInfo = async (file, extension) => {
42
+ await init(file, extension)
43
+ const info = await openapi2.getInfo()
44
+ expect(info.name).toBe("Swagger Petstore")
45
+ }
46
+
47
+ it("returns import info", async () => {
48
+ await runTests("petstore", testImportInfo)
49
+ })
50
+
51
+ describe("Returns queries", () => {
52
+ const indexQueries = (queries) => {
53
+ return queries.reduce((acc, query) => {
54
+ acc[query.name] = query
55
+ return acc
56
+ }, {})
57
+ }
58
+
59
+ const getQueries = async (file, extension) => {
60
+ await init(file, extension)
61
+ const queries = await openapi2.getQueries()
62
+ expect(queries.length).toBe(6)
63
+ return indexQueries(queries)
64
+ }
65
+
66
+ const testVerb = async (file, extension, assertions) => {
67
+ const queries = await getQueries(file, extension)
68
+ for (let [operationId, method] of Object.entries(assertions)) {
69
+ expect(queries[operationId].queryVerb).toBe(method)
70
+ }
71
+ }
72
+
73
+ it("populates verb", async () => {
74
+ const assertions = {
75
+ "createEntity" : "create",
76
+ "getEntities" : "read",
77
+ "getEntity" : "read",
78
+ "updateEntity" : "update",
79
+ "patchEntity" : "patch",
80
+ "deleteEntity" : "delete"
81
+ }
82
+ await runTests("crud", testVerb, assertions)
83
+ })
84
+
85
+ const testPath = async (file, extension, assertions) => {
86
+ const queries = await getQueries(file, extension)
87
+ for (let [operationId, urlPath] of Object.entries(assertions)) {
88
+ expect(queries[operationId].fields.path).toBe(urlPath)
89
+ }
90
+ }
91
+
92
+ it("populates path", async () => {
93
+ const assertions = {
94
+ "createEntity" : "http://example.com/entities",
95
+ "getEntities" : "http://example.com/entities",
96
+ "getEntity" : "http://example.com/entities/{{entityId}}",
97
+ "updateEntity" : "http://example.com/entities/{{entityId}}",
98
+ "patchEntity" : "http://example.com/entities/{{entityId}}",
99
+ "deleteEntity" : "http://example.com/entities/{{entityId}}"
100
+ }
101
+ await runTests("crud", testPath, assertions)
102
+ })
103
+
104
+ const testHeaders = async (file, extension, assertions) => {
105
+ const queries = await getQueries(file, extension)
106
+ for (let [operationId, headers] of Object.entries(assertions)) {
107
+ expect(queries[operationId].fields.headers).toStrictEqual(headers)
108
+ }
109
+ }
110
+
111
+ const contentTypeHeader = {
112
+ "Content-Type" : "application/json",
113
+ }
114
+
115
+ it("populates headers", async () => {
116
+ const assertions = {
117
+ "createEntity" : {
118
+ ...contentTypeHeader
119
+ },
120
+ "getEntities" : {
121
+ },
122
+ "getEntity" : {
123
+ },
124
+ "updateEntity" : {
125
+ ...contentTypeHeader
126
+ },
127
+ "patchEntity" : {
128
+ ...contentTypeHeader
129
+ },
130
+ "deleteEntity" : {
131
+ "x-api-key" : "{{x-api-key}}",
132
+ }
133
+ }
134
+
135
+ await runTests("crud", testHeaders, assertions)
136
+ })
137
+
138
+ const testQuery = async (file, extension, assertions) => {
139
+ const queries = await getQueries(file, extension)
140
+ for (let [operationId, queryString] of Object.entries(assertions)) {
141
+ expect(queries[operationId].fields.queryString).toStrictEqual(queryString)
142
+ }
143
+ }
144
+
145
+ it("populates query", async () => {
146
+ const assertions = {
147
+ "createEntity" : "",
148
+ "getEntities" : "page={{page}}&size={{size}}",
149
+ "getEntity" : "",
150
+ "updateEntity" : "",
151
+ "patchEntity" : "",
152
+ "deleteEntity" : ""
153
+ }
154
+ await runTests("crud", testQuery, assertions)
155
+ })
156
+
157
+ const testParameters = async (file, extension, assertions) => {
158
+ const queries = await getQueries(file, extension)
159
+ for (let [operationId, parameters] of Object.entries(assertions)) {
160
+ expect(queries[operationId].parameters).toStrictEqual(parameters)
161
+ }
162
+ }
163
+
164
+ it("populates parameters", async () => {
165
+ const assertions = {
166
+ "createEntity" : [],
167
+ "getEntities" : [
168
+ {
169
+ "name" : "page",
170
+ "default" : "",
171
+ },
172
+ {
173
+ "name" : "size",
174
+ "default" : "",
175
+ }
176
+ ],
177
+ "getEntity" : [
178
+ {
179
+ "name" : "entityId",
180
+ "default" : "",
181
+ }
182
+ ],
183
+ "updateEntity" : [
184
+ {
185
+ "name" : "entityId",
186
+ "default" : "",
187
+ }
188
+ ],
189
+ "patchEntity" : [
190
+ {
191
+ "name" : "entityId",
192
+ "default" : "",
193
+ }
194
+ ],
195
+ "deleteEntity" : [
196
+ {
197
+ "name" : "entityId",
198
+ "default" : "",
199
+ },
200
+ {
201
+ "name" : "x-api-key",
202
+ "default" : "",
203
+ }
204
+ ]
205
+ }
206
+ await runTests("crud", testParameters, assertions)
207
+ })
208
+
209
+ const testBody = async (file, extension, assertions) => {
210
+ const queries = await getQueries(file, extension)
211
+ for (let [operationId, body] of Object.entries(assertions)) {
212
+ expect(queries[operationId].fields.requestBody).toStrictEqual(JSON.stringify(body, null, 2))
213
+ }
214
+ }
215
+ it("populates body", async () => {
216
+ const assertions = {
217
+ "createEntity" : {
218
+ "name" : "name",
219
+ "type" : "type",
220
+ },
221
+ "getEntities" : undefined,
222
+ "getEntity" : undefined,
223
+ "updateEntity" : {
224
+ "id": 1,
225
+ "name" : "name",
226
+ "type" : "type",
227
+ },
228
+ "patchEntity" : {
229
+ "id": 1,
230
+ "name" : "name",
231
+ "type" : "type",
232
+ },
233
+ "deleteEntity" : undefined
234
+ }
235
+ await runTests("crud", testBody, assertions)
236
+ })
237
+ })
238
+ })
@@ -0,0 +1,109 @@
1
+
2
+ const bulkDocs = jest.fn()
3
+ const db = jest.fn(() => {
4
+ return {
5
+ bulkDocs
6
+ }
7
+ })
8
+ jest.mock("../../../../../db", () => db)
9
+
10
+ const { RestImporter } = require("../index")
11
+
12
+ const fs = require("fs")
13
+ const path = require('path')
14
+
15
+ const getData = (file) => {
16
+ return fs.readFileSync(path.join(__dirname, `../sources/tests/${file}`), "utf8")
17
+ }
18
+
19
+ // openapi2 (swagger)
20
+ const oapi2CrudJson = getData("openapi2/data/crud/crud.json")
21
+ const oapi2CrudYaml = getData("openapi2/data/crud/crud.json")
22
+ const oapi2PetstoreJson = getData("openapi2/data/petstore/petstore.json")
23
+ const oapi2PetstoreYaml = getData("openapi2/data/petstore/petstore.json")
24
+
25
+ // curl
26
+ const curl = getData("curl/data/post.txt")
27
+
28
+ const datasets = {
29
+ oapi2CrudJson,
30
+ oapi2CrudYaml,
31
+ oapi2PetstoreJson,
32
+ oapi2PetstoreYaml,
33
+ curl
34
+ }
35
+
36
+ describe("Rest Importer", () => {
37
+ let restImporter
38
+
39
+ const init = async (data) => {
40
+ restImporter = new RestImporter(data)
41
+ await restImporter.init()
42
+ }
43
+
44
+ const runTest = async (test, assertions) => {
45
+ for (let [key, data] of Object.entries(datasets)) {
46
+ await test(key, data, assertions)
47
+ }
48
+ }
49
+
50
+ const testGetInfo = async (key, data, assertions) => {
51
+ await init(data)
52
+ const info = await restImporter.getInfo()
53
+ expect(info.name).toBe(assertions[key].name)
54
+ }
55
+
56
+ it("gets info", async () => {
57
+ const assertions = {
58
+ "oapi2CrudJson" : {
59
+ name: "CRUD",
60
+ },
61
+ "oapi2CrudYaml" : {
62
+ name: "CRUD",
63
+ },
64
+ "oapi2PetstoreJson" : {
65
+ name: "Swagger Petstore",
66
+ },
67
+ "oapi2PetstoreYaml" :{
68
+ name: "Swagger Petstore",
69
+ },
70
+ "curl": {
71
+ name: "example.com",
72
+ }
73
+ }
74
+ await runTest(testGetInfo, assertions)
75
+ })
76
+
77
+ const testImportQueries = async (key, data, assertions) => {
78
+ await init(data)
79
+ bulkDocs.mockReturnValue([])
80
+ const importResult = await restImporter.importQueries("appId", "datasourceId")
81
+ expect(importResult.errorQueries.length).toBe(0)
82
+ expect(importResult.queries.length).toBe(assertions[key].count)
83
+ expect(bulkDocs).toHaveBeenCalledTimes(1)
84
+ jest.clearAllMocks()
85
+ }
86
+
87
+ it("imports queries", async () => {
88
+ // simple sanity assertions that the whole dataset
89
+ // makes it through the importer
90
+ const assertions = {
91
+ "oapi2CrudJson" : {
92
+ count: 6,
93
+ },
94
+ "oapi2CrudYaml" :{
95
+ count: 6,
96
+ },
97
+ "oapi2PetstoreJson" : {
98
+ count: 20,
99
+ },
100
+ "oapi2PetstoreYaml" :{
101
+ count: 20,
102
+ },
103
+ "curl": {
104
+ count: 1
105
+ }
106
+ }
107
+ await runTest(testImportQueries, assertions)
108
+ })
109
+ })
@@ -0,0 +1,196 @@
1
+ const CouchDB = require("../../../db")
2
+ const {
3
+ generateQueryID,
4
+ getQueryParams,
5
+ isProdAppID,
6
+ } = require("../../../db/utils")
7
+ const { BaseQueryVerbs } = require("../../../constants")
8
+ const { Thread, ThreadType } = require("../../../threads")
9
+ const { save: saveDatasource } = require("../datasource")
10
+ const { RestImporter } = require("./import")
11
+ const { invalidateDynamicVariables } = require("../../../threads/utils")
12
+
13
+ const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 })
14
+
15
+ // simple function to append "readable" to all read queries
16
+ function enrichQueries(input) {
17
+ const wasArray = Array.isArray(input)
18
+ const queries = wasArray ? input : [input]
19
+ for (let query of queries) {
20
+ if (query.queryVerb === BaseQueryVerbs.READ) {
21
+ query.readable = true
22
+ }
23
+ }
24
+ return wasArray ? queries : queries[0]
25
+ }
26
+
27
+ exports.fetch = async function (ctx) {
28
+ const db = new CouchDB(ctx.appId)
29
+
30
+ const body = await db.allDocs(
31
+ getQueryParams(null, {
32
+ include_docs: true,
33
+ })
34
+ )
35
+
36
+ ctx.body = enrichQueries(body.rows.map(row => row.doc))
37
+ }
38
+
39
+ exports.import = async ctx => {
40
+ const body = ctx.request.body
41
+ const data = body.data
42
+
43
+ const importer = new RestImporter(data)
44
+ await importer.init()
45
+
46
+ let datasourceId
47
+ if (!body.datasourceId) {
48
+ // construct new datasource
49
+ const info = await importer.getInfo()
50
+ let datasource = {
51
+ type: "datasource",
52
+ source: "REST",
53
+ config: {
54
+ url: info.url,
55
+ defaultHeaders: [],
56
+ },
57
+ name: info.name,
58
+ }
59
+ // save the datasource
60
+ const datasourceCtx = { ...ctx }
61
+ datasourceCtx.request.body.datasource = datasource
62
+ await saveDatasource(datasourceCtx)
63
+ datasourceId = datasourceCtx.body.datasource._id
64
+ } else {
65
+ // use existing datasource
66
+ datasourceId = body.datasourceId
67
+ }
68
+
69
+ const importResult = await importer.importQueries(ctx.appId, datasourceId)
70
+
71
+ ctx.body = {
72
+ ...importResult,
73
+ datasourceId,
74
+ }
75
+ ctx.status = 200
76
+ }
77
+
78
+ exports.save = async function (ctx) {
79
+ const db = new CouchDB(ctx.appId)
80
+ const query = ctx.request.body
81
+
82
+ if (!query._id) {
83
+ query._id = generateQueryID(query.datasourceId)
84
+ }
85
+
86
+ const response = await db.put(query)
87
+ query._rev = response.rev
88
+
89
+ ctx.body = query
90
+ ctx.message = `Query ${query.name} saved successfully.`
91
+ }
92
+
93
+ exports.find = async function (ctx) {
94
+ const db = new CouchDB(ctx.appId)
95
+ const query = enrichQueries(await db.get(ctx.params.queryId))
96
+ // remove properties that could be dangerous in real app
97
+ if (isProdAppID(ctx.appId)) {
98
+ delete query.fields
99
+ delete query.parameters
100
+ }
101
+ ctx.body = query
102
+ }
103
+
104
+ exports.preview = async function (ctx) {
105
+ const db = new CouchDB(ctx.appId)
106
+
107
+ const datasource = await db.get(ctx.request.body.datasourceId)
108
+ // preview may not have a queryId as it hasn't been saved, but if it does
109
+ // this stops dynamic variables from calling the same query
110
+ const { fields, parameters, queryVerb, transformer, queryId } =
111
+ ctx.request.body
112
+
113
+ try {
114
+ const { rows, keys, info, extra } = await Runner.run({
115
+ appId: ctx.appId,
116
+ datasource,
117
+ queryVerb,
118
+ fields,
119
+ parameters,
120
+ transformer,
121
+ queryId,
122
+ })
123
+
124
+ ctx.body = {
125
+ rows,
126
+ schemaFields: [...new Set(keys)],
127
+ info,
128
+ extra,
129
+ }
130
+ } catch (err) {
131
+ ctx.throw(400, err)
132
+ }
133
+ }
134
+
135
+ async function execute(ctx, opts = { rowsOnly: false }) {
136
+ const db = new CouchDB(ctx.appId)
137
+
138
+ const query = await db.get(ctx.params.queryId)
139
+ const datasource = await db.get(query.datasourceId)
140
+
141
+ // call the relevant CRUD method on the integration class
142
+ try {
143
+ const { rows, pagination, extra } = await Runner.run({
144
+ appId: ctx.appId,
145
+ datasource,
146
+ queryVerb: query.queryVerb,
147
+ fields: query.fields,
148
+ pagination: ctx.request.body.pagination,
149
+ parameters: ctx.request.body.parameters,
150
+ transformer: query.transformer,
151
+ queryId: ctx.params.queryId,
152
+ })
153
+ if (opts && opts.rowsOnly) {
154
+ ctx.body = rows
155
+ } else {
156
+ ctx.body = { data: rows, pagination, ...extra }
157
+ }
158
+ } catch (err) {
159
+ ctx.throw(400, err)
160
+ }
161
+ }
162
+
163
+ exports.executeV1 = async function (ctx) {
164
+ return execute(ctx, { rowsOnly: true })
165
+ }
166
+
167
+ exports.executeV2 = async function (ctx) {
168
+ return execute(ctx, { rowsOnly: false })
169
+ }
170
+
171
+ const removeDynamicVariables = async (db, queryId) => {
172
+ const query = await db.get(queryId)
173
+ const datasource = await db.get(query.datasourceId)
174
+ const dynamicVariables = datasource.config.dynamicVariables
175
+
176
+ if (dynamicVariables) {
177
+ // delete dynamic variables from the datasource
178
+ const newVariables = dynamicVariables.filter(dv => dv.queryId !== queryId)
179
+ datasource.config.dynamicVariables = newVariables
180
+ await db.put(datasource)
181
+
182
+ // invalidate the deleted variables
183
+ const variablesToDelete = dynamicVariables.filter(
184
+ dv => dv.queryId === queryId
185
+ )
186
+ await invalidateDynamicVariables(variablesToDelete)
187
+ }
188
+ }
189
+
190
+ exports.destroy = async function (ctx) {
191
+ const db = new CouchDB(ctx.appId)
192
+ await removeDynamicVariables(db, ctx.params.queryId)
193
+ await db.remove(ctx.params.queryId, ctx.params.revId)
194
+ ctx.message = `Query deleted.`
195
+ ctx.status = 200
196
+ }
@@ -0,0 +1,42 @@
1
+ const joiValidator = require("../../../middleware/joi-validator")
2
+ const Joi = require("joi")
3
+
4
+ exports.queryValidation = () => {
5
+ return Joi.object({
6
+ _id: Joi.string(),
7
+ _rev: Joi.string(),
8
+ name: Joi.string().required(),
9
+ fields: Joi.object().required(),
10
+ datasourceId: Joi.string().required(),
11
+ readable: Joi.boolean(),
12
+ parameters: Joi.array().items(
13
+ Joi.object({
14
+ name: Joi.string(),
15
+ default: Joi.string().allow(""),
16
+ })
17
+ ),
18
+ queryVerb: Joi.string().allow().required(),
19
+ extra: Joi.object().optional(),
20
+ schema: Joi.object({}).required().unknown(true),
21
+ transformer: Joi.string().optional(),
22
+ flags: Joi.object().optional(),
23
+ })
24
+ }
25
+
26
+ exports.generateQueryValidation = () => {
27
+ // prettier-ignore
28
+ return joiValidator.body(exports.queryValidation())
29
+ }
30
+
31
+ exports.generateQueryPreviewValidation = () => {
32
+ // prettier-ignore
33
+ return joiValidator.body(Joi.object({
34
+ fields: Joi.object().required(),
35
+ queryVerb: Joi.string().allow().required(),
36
+ extra: Joi.object().optional(),
37
+ datasourceId: Joi.string().required(),
38
+ transformer: Joi.string().optional(),
39
+ parameters: Joi.object({}).required().unknown(true),
40
+ queryId: Joi.string().optional(),
41
+ }))
42
+ }
@@ -4,7 +4,7 @@ const {
4
4
  getRole,
5
5
  isBuiltin,
6
6
  getAllRoles,
7
- } = require("@budibase/auth/roles")
7
+ } = require("@budibase/backend-core/roles")
8
8
  const {
9
9
  generateRoleID,
10
10
  getUserMetadataParams,
@@ -2,7 +2,7 @@ const { getRoutingInfo } = require("../../utilities/routing")
2
2
  const {
3
3
  getUserRoleHierarchy,
4
4
  BUILTIN_ROLE_IDS,
5
- } = require("@budibase/auth/roles")
5
+ } = require("@budibase/backend-core/roles")
6
6
 
7
7
  const URL_SEPARATOR = "/"
8
8
 
@@ -11,6 +11,7 @@ const {
11
11
  inputProcessing,
12
12
  outputProcessing,
13
13
  processAutoColumn,
14
+ cleanupAttachments,
14
15
  } = require("../../../utilities/rowProcessor")
15
16
  const { FieldTypes } = require("../../../constants")
16
17
  const { isEqual } = require("lodash")
@@ -25,6 +26,7 @@ const {
25
26
  getFromDesignDoc,
26
27
  getFromMemoryDoc,
27
28
  } = require("../view/utils")
29
+ const { cloneDeep } = require("lodash/fp")
28
30
 
29
31
  const CALCULATION_TYPES = {
30
32
  SUM: "sum",
@@ -109,14 +111,14 @@ exports.patch = async ctx => {
109
111
  const inputs = ctx.request.body
110
112
  const tableId = inputs.tableId
111
113
  const isUserTable = tableId === InternalTables.USER_METADATA
112
- let dbRow
114
+ let oldRow
113
115
  try {
114
- dbRow = await db.get(inputs._id)
116
+ oldRow = await db.get(inputs._id)
115
117
  } catch (err) {
116
118
  if (isUserTable) {
117
119
  // don't include the rev, it'll be the global rev
118
120
  // this time
119
- dbRow = {
121
+ oldRow = {
120
122
  _id: inputs._id,
121
123
  }
122
124
  } else {
@@ -125,13 +127,14 @@ exports.patch = async ctx => {
125
127
  }
126
128
  let dbTable = await db.get(tableId)
127
129
  // need to build up full patch fields before coerce
130
+ let combinedRow = cloneDeep(oldRow)
128
131
  for (let key of Object.keys(inputs)) {
129
132
  if (!dbTable.schema[key]) continue
130
- dbRow[key] = inputs[key]
133
+ combinedRow[key] = inputs[key]
131
134
  }
132
135
 
133
136
  // this returns the table and row incase they have been updated
134
- let { table, row } = inputProcessing(ctx.user, dbTable, dbRow)
137
+ let { table, row } = inputProcessing(ctx.user, dbTable, combinedRow)
135
138
  const validateResult = await validate({
136
139
  row,
137
140
  table,
@@ -149,6 +152,8 @@ exports.patch = async ctx => {
149
152
  tableId: row.tableId,
150
153
  table,
151
154
  })
155
+ // check if any attachments removed
156
+ await cleanupAttachments(appId, table, { oldRow, row })
152
157
 
153
158
  if (isUserTable) {
154
159
  // the row has been updated, need to put it into the ctx
@@ -295,6 +300,8 @@ exports.destroy = async function (ctx) {
295
300
  row,
296
301
  tableId: row.tableId,
297
302
  })
303
+ // remove any attachments that were on the row from object storage
304
+ await cleanupAttachments(appId, table, { row })
298
305
 
299
306
  let response
300
307
  if (ctx.params.tableId === InternalTables.USER_METADATA) {
@@ -341,6 +348,8 @@ exports.bulkDestroy = async ctx => {
341
348
  } else {
342
349
  await db.bulkDocs(rows.map(row => ({ ...row, _deleted: true })))
343
350
  }
351
+ // remove any attachments that were on the rows from object storage
352
+ await cleanupAttachments(appId, table, { rows })
344
353
  await Promise.all(updates)
345
354
  return { response: { ok: true }, rows }
346
355
  }
@@ -1,6 +1,6 @@
1
1
  const { SearchIndexes } = require("../../../db/utils")
2
2
  const fetch = require("node-fetch")
3
- const { getCouchUrl } = require("@budibase/auth/db")
3
+ const { getCouchUrl } = require("@budibase/backend-core/db")
4
4
 
5
5
  /**
6
6
  * Class to build lucene query URLs.
@@ -191,7 +191,8 @@ class QueryBuilder {
191
191
  }
192
192
  if (this.query.equal) {
193
193
  build(this.query.equal, (key, value) => {
194
- if (!value) {
194
+ // 0 evaluates to false, which means we would return all rows if we don't check it
195
+ if (!value && value !== 0) {
195
196
  return null
196
197
  }
197
198
  return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`