@budibase/server 0.9.188 → 0.9.190-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) 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.7d405e74.css +1 -0
  7. package/builder/assets/index.edea4fa5.js +1316 -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 +1507 -1081
  13. package/coverage/coverage-final.json +93 -89
  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 +64 -13
  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 +232 -28
  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 +91 -91
  26. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  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 +53 -209
  31. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  32. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  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 +2 -2
  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 +545 -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 +1 -1
  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 +1 -1
  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 +35 -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 +42 -12
  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 +1 -1
  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 +3 -3
  132. package/coverage/lcov-report/db/utils.js.html +57 -57
  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 +11 -8
  142. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  143. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  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 +1 -1
  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 +26 -11
  159. package/coverage/lcov-report/utilities/index.html +48 -48
  160. package/coverage/lcov-report/utilities/index.js.html +47 -14
  161. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  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 +1 -1
  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 +2495 -1737
  174. package/dist/api/controllers/application.js +15 -1
  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 +30 -58
  180. package/dist/api/controllers/row/ExternalRequest.js +78 -34
  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 +150 -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/table.js +7 -1
  192. package/dist/api/routes/user.js +2 -1
  193. package/dist/app.js +2 -11
  194. package/dist/automations/bullboard.js +37 -10
  195. package/dist/automations/triggers.js +7 -3
  196. package/dist/automations/utils.js +11 -2
  197. package/dist/constants/index.js +19 -0
  198. package/dist/definitions/datasource.js +5 -0
  199. package/dist/environment.js +13 -0
  200. package/dist/integrations/base/IntegrationBase.js +2 -0
  201. package/dist/integrations/base/datasourcePlus.js +2 -0
  202. package/dist/integrations/base/sql.js +353 -177
  203. package/dist/integrations/base/sqlTable.js +143 -0
  204. package/dist/integrations/base/utils.js +30 -0
  205. package/dist/integrations/index.js +6 -0
  206. package/dist/integrations/microsoftSqlServer.js +117 -9
  207. package/dist/integrations/mysql.js +16 -85
  208. package/dist/integrations/oracle.js +347 -0
  209. package/dist/integrations/postgres.js +35 -28
  210. package/dist/integrations/utils.js +71 -9
  211. package/dist/middleware/authorized.js +2 -1
  212. package/dist/middleware/builder.js +4 -1
  213. package/dist/package.json +12 -7
  214. package/dist/tests/utilities/TestConfiguration.js +2 -1
  215. package/dist/{automations/thread.js → threads/automation.js} +26 -8
  216. package/dist/threads/index.js +64 -0
  217. package/dist/threads/query.js +64 -0
  218. package/dist/tsconfig.tsbuildinfo +1 -1
  219. package/dist/utilities/csvParser.js +46 -5
  220. package/dist/utilities/global.js +6 -2
  221. package/dist/utilities/index.js +11 -0
  222. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  223. package/dist/utilities/scriptRunner.js +4 -1
  224. package/package.json +13 -8
  225. package/scripts/dev/manage.js +1 -0
  226. package/scripts/integrations/mssql/data/Dockerfile +9 -0
  227. package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
  228. package/scripts/integrations/mssql/data/setup.sql +54 -0
  229. package/scripts/integrations/mssql/docker-compose.yaml +12 -0
  230. package/scripts/integrations/mssql/reset.sh +3 -0
  231. package/scripts/integrations/oracle/docker-compose.yml +19 -0
  232. package/scripts/integrations/oracle/instantclient/linux/x86-64/basiclite-21.4.zip +0 -0
  233. package/scripts/integrations/oracle/instantclient/linux/x86-64/install.sh +23 -0
  234. package/scripts/integrations/oracle/oracle.md +90 -0
  235. package/scripts/integrations/postgres/docker-compose.yml +3 -3
  236. package/scripts/likeCypress.ts +33 -0
  237. package/src/api/controllers/application.js +18 -1
  238. package/src/api/controllers/auth.js +3 -0
  239. package/src/api/controllers/datasource.js +84 -16
  240. package/src/api/controllers/deploy/index.js +2 -0
  241. package/src/api/controllers/dev.js +4 -1
  242. package/src/api/controllers/query.js +29 -81
  243. package/src/api/controllers/row/ExternalRequest.ts +91 -36
  244. package/src/api/controllers/row/external.js +4 -1
  245. package/src/api/controllers/row/utils.js +8 -11
  246. package/src/api/controllers/table/external.js +307 -0
  247. package/src/api/controllers/table/index.js +47 -137
  248. package/src/api/controllers/table/internal.js +155 -0
  249. package/src/api/controllers/table/utils.js +74 -33
  250. package/src/api/controllers/user.js +132 -13
  251. package/src/api/controllers/view/exporters.js +5 -0
  252. package/src/api/controllers/view/index.js +15 -2
  253. package/src/api/routes/query.js +1 -0
  254. package/src/api/routes/table.js +11 -0
  255. package/src/api/routes/tests/datasource.spec.js +2 -2
  256. package/src/api/routes/tests/misc.spec.js +5 -1
  257. package/src/api/routes/tests/query.spec.js +0 -1
  258. package/src/api/routes/user.js +5 -0
  259. package/src/app.ts +2 -10
  260. package/src/automations/bullboard.js +28 -11
  261. package/src/automations/tests/automation.spec.js +3 -4
  262. package/src/automations/triggers.js +7 -3
  263. package/src/automations/utils.js +12 -2
  264. package/src/constants/index.js +22 -0
  265. package/src/definitions/common.ts +7 -1
  266. package/src/definitions/datasource.ts +10 -3
  267. package/src/environment.js +15 -0
  268. package/src/integrations/airtable.ts +2 -1
  269. package/src/integrations/arangodb.ts +2 -1
  270. package/src/integrations/base/IntegrationBase.ts +6 -0
  271. package/src/integrations/base/datasourcePlus.ts +9 -0
  272. package/src/integrations/base/sql.ts +377 -218
  273. package/src/integrations/base/sqlTable.ts +180 -0
  274. package/src/integrations/base/utils.ts +22 -0
  275. package/src/integrations/couchdb.ts +2 -1
  276. package/src/integrations/dynamodb.ts +2 -1
  277. package/src/integrations/elasticsearch.ts +2 -1
  278. package/src/integrations/index.ts +7 -0
  279. package/src/integrations/microsoftSqlServer.ts +145 -13
  280. package/src/integrations/mongodb.ts +2 -1
  281. package/src/integrations/mysql.ts +23 -95
  282. package/src/integrations/oracle.ts +458 -0
  283. package/src/integrations/postgres.ts +45 -35
  284. package/src/integrations/rest.ts +2 -1
  285. package/src/integrations/s3.ts +2 -1
  286. package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
  287. package/src/integrations/tests/oracle.spec.js +94 -0
  288. package/src/integrations/tests/postgres.spec.js +4 -0
  289. package/src/integrations/utils.ts +78 -8
  290. package/src/middleware/authorized.js +2 -1
  291. package/src/middleware/builder.js +4 -1
  292. package/src/tests/utilities/TestConfiguration.js +2 -1
  293. package/src/{automations/thread.js → threads/automation.js} +27 -8
  294. package/src/threads/index.js +66 -0
  295. package/src/threads/query.js +66 -0
  296. package/src/utilities/csvParser.js +48 -5
  297. package/src/utilities/global.js +7 -2
  298. package/src/utilities/index.js +11 -0
  299. package/src/utilities/queue/inMemoryQueue.js +7 -0
  300. package/src/utilities/scriptRunner.js +4 -1
  301. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  302. package/src/utilities/tests/csvParser.spec.js +3 -0
  303. package/tsconfig.json +1 -1
  304. package/builder/assets/index.550fdba7.js +0 -201
  305. package/builder/assets/index.7469e1e4.css +0 -29
  306. package/builder/assets/vendor.278a305c.js +0 -9
  307. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -0,0 +1,180 @@
1
+ import { Knex, knex } from "knex"
2
+ import { Table } from "../../definitions/common"
3
+ import { Operation, QueryJson } from "../../definitions/datasource"
4
+ import { breakExternalTableId } from "../utils"
5
+ import SchemaBuilder = Knex.SchemaBuilder
6
+ import CreateTableBuilder = Knex.CreateTableBuilder
7
+ const { FieldTypes, RelationshipTypes } = require("../../constants")
8
+
9
+ function generateSchema(
10
+ schema: CreateTableBuilder,
11
+ table: Table,
12
+ tables: Record<string, Table>,
13
+ oldTable: null | Table = null
14
+ ) {
15
+ let primaryKey = table && table.primary ? table.primary[0] : null
16
+ const columns = Object.values(table.schema)
17
+ // all columns in a junction table will be meta
18
+ let metaCols = columns.filter(col => col.meta)
19
+ let isJunction = metaCols.length === columns.length
20
+ // can't change primary once its set for now
21
+ if (primaryKey && !oldTable && !isJunction) {
22
+ schema.increments(primaryKey).primary()
23
+ } else if (!oldTable && isJunction) {
24
+ schema.primary(metaCols.map(col => col.name))
25
+ }
26
+
27
+ // check if any columns need added
28
+ const foreignKeys = Object.values(table.schema).map(col => col.foreignKey)
29
+ for (let [key, column] of Object.entries(table.schema)) {
30
+ // skip things that are already correct
31
+ const oldColumn = oldTable ? oldTable.schema[key] : null
32
+ if ((oldColumn && oldColumn.type) || (primaryKey === key && !isJunction)) {
33
+ continue
34
+ }
35
+ switch (column.type) {
36
+ case FieldTypes.STRING:
37
+ case FieldTypes.OPTIONS:
38
+ case FieldTypes.LONGFORM:
39
+ schema.string(key)
40
+ break
41
+ case FieldTypes.NUMBER:
42
+ // if meta is specified then this is a junction table entry
43
+ if (column.meta && column.meta.toKey && column.meta.toTable) {
44
+ const { toKey, toTable } = column.meta
45
+ schema.integer(key).unsigned()
46
+ schema.foreign(key).references(`${toTable}.${toKey}`)
47
+ } else if (foreignKeys.indexOf(key) === -1) {
48
+ schema.float(key)
49
+ }
50
+ break
51
+ case FieldTypes.BOOLEAN:
52
+ schema.boolean(key)
53
+ break
54
+ case FieldTypes.DATETIME:
55
+ schema.datetime(key)
56
+ break
57
+ case FieldTypes.ARRAY:
58
+ schema.json(key)
59
+ break
60
+ case FieldTypes.LINK:
61
+ // this side of the relationship doesn't need any SQL work
62
+ if (
63
+ column.relationshipType !== RelationshipTypes.MANY_TO_ONE &&
64
+ column.relationshipType !== RelationshipTypes.MANY_TO_MANY
65
+ ) {
66
+ if (!column.foreignKey || !column.tableId) {
67
+ throw "Invalid relationship schema"
68
+ }
69
+ const { tableName } = breakExternalTableId(column.tableId)
70
+ // @ts-ignore
71
+ const relatedTable = tables[tableName]
72
+ if (!relatedTable) {
73
+ throw "Referenced table doesn't exist"
74
+ }
75
+ schema.integer(column.foreignKey).unsigned()
76
+ schema
77
+ .foreign(column.foreignKey)
78
+ .references(`${tableName}.${relatedTable.primary[0]}`)
79
+ }
80
+ break
81
+ }
82
+ }
83
+
84
+ // need to check if any columns have been deleted
85
+ if (oldTable) {
86
+ const deletedColumns = Object.entries(oldTable.schema)
87
+ .filter(
88
+ ([key, schema]) =>
89
+ schema.type !== FieldTypes.LINK && table.schema[key] == null
90
+ )
91
+ .map(([key]) => key)
92
+ deletedColumns.forEach(key => {
93
+ if (oldTable.constrained && oldTable.constrained.indexOf(key) !== -1) {
94
+ schema.dropForeign(key)
95
+ }
96
+ schema.dropColumn(key)
97
+ })
98
+ }
99
+
100
+ return schema
101
+ }
102
+
103
+ function buildCreateTable(
104
+ knex: Knex,
105
+ table: Table,
106
+ tables: Record<string, Table>
107
+ ): SchemaBuilder {
108
+ return knex.schema.createTable(table.name, schema => {
109
+ generateSchema(schema, table, tables)
110
+ })
111
+ }
112
+
113
+ function buildUpdateTable(
114
+ knex: Knex,
115
+ table: Table,
116
+ tables: Record<string, Table>,
117
+ oldTable: Table
118
+ ): SchemaBuilder {
119
+ return knex.schema.alterTable(table.name, schema => {
120
+ generateSchema(schema, table, tables, oldTable)
121
+ })
122
+ }
123
+
124
+ function buildDeleteTable(knex: Knex, table: Table): SchemaBuilder {
125
+ return knex.schema.dropTable(table.name)
126
+ }
127
+
128
+ class SqlTableQueryBuilder {
129
+ private readonly sqlClient: string
130
+
131
+ // pass through client to get flavour of SQL
132
+ constructor(client: string) {
133
+ this.sqlClient = client
134
+ }
135
+
136
+ getSqlClient(): string {
137
+ return this.sqlClient
138
+ }
139
+
140
+ /**
141
+ * @param json the input JSON structure from which an SQL query will be built.
142
+ * @return {string} the operation that was found in the JSON.
143
+ */
144
+ _operation(json: QueryJson): Operation {
145
+ return json.endpoint.operation
146
+ }
147
+
148
+ _tableQuery(json: QueryJson): any {
149
+ const client = knex({ client: this.sqlClient })
150
+ let query
151
+ if (!json.table || !json.meta || !json.meta.tables) {
152
+ throw "Cannot execute without table being specified"
153
+ }
154
+ switch (this._operation(json)) {
155
+ case Operation.CREATE_TABLE:
156
+ query = buildCreateTable(client, json.table, json.meta.tables)
157
+ break
158
+ case Operation.UPDATE_TABLE:
159
+ if (!json.meta || !json.meta.table) {
160
+ throw "Must specify old table for update"
161
+ }
162
+ query = buildUpdateTable(
163
+ client,
164
+ json.table,
165
+ json.meta.tables,
166
+ json.meta.table
167
+ )
168
+ break
169
+ case Operation.DELETE_TABLE:
170
+ query = buildDeleteTable(client, json.table)
171
+ break
172
+ default:
173
+ throw "Table operation is of unknown type"
174
+ }
175
+ return query.toSQL()
176
+ }
177
+ }
178
+
179
+ export default SqlTableQueryBuilder
180
+ module.exports = SqlTableQueryBuilder
@@ -0,0 +1,22 @@
1
+ import { QueryJson } from "../../definitions/datasource"
2
+ import { Datasource } from "../../definitions/common"
3
+
4
+ module DatasourceUtils {
5
+ const { integrations } = require("../index")
6
+
7
+ export async function makeExternalQuery(
8
+ datasource: Datasource,
9
+ json: QueryJson
10
+ ) {
11
+ const Integration = integrations[datasource.source]
12
+ // query is the opinionated function
13
+ if (Integration.prototype.query) {
14
+ const integration = new Integration(datasource.config)
15
+ return integration.query(json)
16
+ } else {
17
+ throw "Datasource does not support query."
18
+ }
19
+ }
20
+
21
+ module.exports.makeExternalQuery = makeExternalQuery
22
+ }
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module CouchDBModule {
8
9
  const PouchDB = require("pouchdb")
@@ -50,7 +51,7 @@ module CouchDBModule {
50
51
  },
51
52
  }
52
53
 
53
- class CouchDBIntegration {
54
+ class CouchDBIntegration implements IntegrationBase {
54
55
  private config: CouchDBConfig
55
56
  private client: any
56
57
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module DynamoModule {
8
9
  const AWS = require("aws-sdk")
@@ -113,7 +114,7 @@ module DynamoModule {
113
114
  },
114
115
  }
115
116
 
116
- class DynamoDBIntegration {
117
+ class DynamoDBIntegration implements IntegrationBase {
117
118
  private config: DynamoDBConfig
118
119
  private client: any
119
120
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module ElasticsearchModule {
8
9
  const { Client } = require("@elastic/elasticsearch")
@@ -74,7 +75,7 @@ module ElasticsearchModule {
74
75
  },
75
76
  }
76
77
 
77
- class ElasticSearchIntegration {
78
+ class ElasticSearchIntegration implements IntegrationBase {
78
79
  private config: ElasticsearchConfig
79
80
  private client: any
80
81
 
@@ -39,6 +39,13 @@ const INTEGRATIONS = {
39
39
  [SourceNames.REST]: rest.integration,
40
40
  }
41
41
 
42
+ // optionally add oracle integration if the oracle binary can be installed
43
+ if (!(process.arch === "arm64" && process.platform === "darwin")) {
44
+ const oracle = require("./oracle")
45
+ DEFINITIONS[SourceNames.ORACLE] = oracle.schema
46
+ INTEGRATIONS[SourceNames.ORACLE] = oracle.integration
47
+ }
48
+
42
49
  module.exports = {
43
50
  definitions: DEFINITIONS,
44
51
  integrations: INTEGRATIONS,
@@ -1,11 +1,20 @@
1
1
  import {
2
- Integration,
3
2
  DatasourceFieldTypes,
4
- QueryTypes,
3
+ Integration,
4
+ Operation,
5
5
  QueryJson,
6
+ QueryTypes,
6
7
  SqlQuery,
7
8
  } from "../definitions/datasource"
8
- import { getSqlQuery } from "./utils"
9
+ import {
10
+ getSqlQuery,
11
+ buildExternalTableId,
12
+ convertSqlType,
13
+ finaliseExternalTables,
14
+ SqlClients,
15
+ } from "./utils"
16
+ import { DatasourcePlus } from "./base/datasourcePlus"
17
+ import { Table, TableSchema } from "../definitions/common"
9
18
 
10
19
  module MSSQLModule {
11
20
  const sqlServer = require("mssql")
@@ -22,6 +31,7 @@ module MSSQLModule {
22
31
 
23
32
  const SCHEMA: Integration = {
24
33
  docs: "https://github.com/tediousjs/node-mssql",
34
+ plus: true,
25
35
  description:
26
36
  "Microsoft SQL Server is a relational database management system developed by Microsoft. ",
27
37
  friendlyName: "MS SQL Server",
@@ -69,26 +79,84 @@ module MSSQLModule {
69
79
  },
70
80
  }
71
81
 
72
- async function internalQuery(client: any, query: SqlQuery) {
82
+ async function internalQuery(
83
+ client: any,
84
+ query: SqlQuery,
85
+ operation: string | undefined = undefined
86
+ ) {
87
+ const request = client.request()
73
88
  try {
74
- return await client.query(query.sql, query.bindings || {})
89
+ if (Array.isArray(query.bindings)) {
90
+ let count = 0
91
+ for (let binding of query.bindings) {
92
+ request.input(`p${count++}`, binding)
93
+ }
94
+ }
95
+ // this is a hack to get the inserted ID back,
96
+ // no way to do this with Knex nicely
97
+ const sql =
98
+ operation === Operation.CREATE
99
+ ? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;`
100
+ : query.sql
101
+ return await request.query(sql)
75
102
  } catch (err) {
76
103
  // @ts-ignore
77
104
  throw new Error(err)
78
105
  }
79
106
  }
80
107
 
81
- class SqlServerIntegration extends Sql {
108
+ class SqlServerIntegration extends Sql implements DatasourcePlus {
82
109
  private readonly config: MSSQLConfig
83
110
  static pool: any
111
+ public tables: Record<string, Table> = {}
112
+ public schemaErrors: Record<string, string> = {}
113
+
114
+ MASTER_TABLES = [
115
+ "spt_fallback_db",
116
+ "spt_fallback_dev",
117
+ "spt_fallback_usg",
118
+ "spt_monitor",
119
+ "MSreplication_options",
120
+ ]
121
+ TABLES_SQL =
122
+ "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'"
123
+
124
+ getDefinitionSQL(tableName: string) {
125
+ return `select *
126
+ from INFORMATION_SCHEMA.COLUMNS
127
+ where TABLE_NAME='${tableName}'`
128
+ }
129
+
130
+ getConstraintsSQL(tableName: string) {
131
+ return `SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
132
+ INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KU
133
+ ON TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
134
+ AND TC.CONSTRAINT_NAME = KU.CONSTRAINT_NAME
135
+ AND KU.table_name='${tableName}'
136
+ ORDER BY
137
+ KU.TABLE_NAME,
138
+ KU.ORDINAL_POSITION;`
139
+ }
140
+
141
+ getAutoColumnsSQL(tableName: string) {
142
+ return `SELECT
143
+ COLUMNPROPERTY(OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME),COLUMN_NAME,'IsComputed')
144
+ AS IS_COMPUTED,
145
+ COLUMNPROPERTY(object_id(TABLE_SCHEMA+'.'+TABLE_NAME), COLUMN_NAME, 'IsIdentity')
146
+ AS IS_IDENTITY,
147
+ *
148
+ FROM INFORMATION_SCHEMA.COLUMNS
149
+ WHERE TABLE_NAME='${tableName}'`
150
+ }
84
151
 
85
152
  constructor(config: MSSQLConfig) {
86
- super("mssql")
153
+ super(SqlClients.MS_SQL)
87
154
  this.config = config
88
155
  const clientCfg = {
89
156
  ...this.config,
90
157
  options: {
91
158
  encrypt: this.config.encrypt,
159
+ enableArithAbort: true,
92
160
  },
93
161
  }
94
162
  delete clientCfg.encrypt
@@ -99,14 +167,75 @@ module MSSQLModule {
99
167
 
100
168
  async connect() {
101
169
  try {
102
- const client = await this.pool.connect()
103
- this.client = client.request()
170
+ this.client = await this.pool.connect()
104
171
  } catch (err) {
105
172
  // @ts-ignore
106
173
  throw new Error(err)
107
174
  }
108
175
  }
109
176
 
177
+ async runSQL(sql: string) {
178
+ return (await internalQuery(this.client, getSqlQuery(sql))).recordset
179
+ }
180
+
181
+ /**
182
+ * Fetches the tables from the sql server database and assigns them to the datasource.
183
+ * @param {*} datasourceId - datasourceId to fetch
184
+ * @param entities - the tables that are to be built
185
+ */
186
+ async buildSchema(datasourceId: string, entities: Record<string, Table>) {
187
+ await this.connect()
188
+ let tableNames = await this.runSQL(this.TABLES_SQL)
189
+ if (tableNames == null || !Array.isArray(tableNames)) {
190
+ throw "Unable to get list of tables in database"
191
+ }
192
+ tableNames = tableNames
193
+ .map((record: any) => record.TABLE_NAME)
194
+ .filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1)
195
+
196
+ const tables: Record<string, Table> = {}
197
+ for (let tableName of tableNames) {
198
+ // get the column definition (type)
199
+ const definition = await this.runSQL(this.getDefinitionSQL(tableName))
200
+ // find primary key constraints
201
+ const constraints = await this.runSQL(this.getConstraintsSQL(tableName))
202
+ // find the computed and identity columns (auto columns)
203
+ const columns = await this.runSQL(this.getAutoColumnsSQL(tableName))
204
+ const primaryKeys = constraints
205
+ .filter(
206
+ (constraint: any) => constraint.CONSTRAINT_TYPE === "PRIMARY KEY"
207
+ )
208
+ .map((constraint: any) => constraint.COLUMN_NAME)
209
+ const autoColumns = columns
210
+ .filter((col: any) => col.IS_COMPUTED || col.IS_IDENTITY)
211
+ .map((col: any) => col.COLUMN_NAME)
212
+
213
+ let schema: TableSchema = {}
214
+ for (let def of definition) {
215
+ const name = def.COLUMN_NAME
216
+ if (typeof name !== "string") {
217
+ continue
218
+ }
219
+ const type: string = convertSqlType(def.DATA_TYPE)
220
+
221
+ schema[name] = {
222
+ autocolumn: !!autoColumns.find((col: string) => col === name),
223
+ name: name,
224
+ type,
225
+ }
226
+ }
227
+ tables[tableName] = {
228
+ _id: buildExternalTableId(datasourceId, tableName),
229
+ primary: primaryKeys,
230
+ name: tableName,
231
+ schema,
232
+ }
233
+ }
234
+ const final = finaliseExternalTables(tables, entities)
235
+ this.tables = final.tables
236
+ this.schemaErrors = final.errors
237
+ }
238
+
110
239
  async read(query: SqlQuery | string) {
111
240
  await this.connect()
112
241
  const response = await internalQuery(this.client, getSqlQuery(query))
@@ -132,10 +261,13 @@ module MSSQLModule {
132
261
  }
133
262
 
134
263
  async query(json: QueryJson) {
135
- const operation = this._operation(json).toLowerCase()
136
- const input = this._query(json)
137
- const response = await internalQuery(this.client, input)
138
- return response.recordset ? response.recordset : [{ [operation]: true }]
264
+ await this.connect()
265
+ const operation = this._operation(json)
266
+ const queryFn = (query: any, op: string) =>
267
+ internalQuery(this.client, query, op)
268
+ const processFn = (result: any) =>
269
+ result.recordset ? result.recordset : [{ [operation]: true }]
270
+ return this.queryWithReturning(json, queryFn, processFn)
139
271
  }
140
272
  }
141
273
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module MongoDBModule {
8
9
  const { MongoClient } = require("mongodb")
@@ -62,7 +63,7 @@ module MongoDBModule {
62
63
  },
63
64
  }
64
65
 
65
- class MongoIntegration {
66
+ class MongoIntegration implements IntegrationBase {
66
67
  private config: MongoDBConfig
67
68
  private client: any
68
69
 
@@ -2,22 +2,22 @@ import {
2
2
  Integration,
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
- Operation,
6
5
  QueryJson,
7
6
  SqlQuery,
8
7
  } from "../definitions/datasource"
9
8
  import { Table, TableSchema } from "../definitions/common"
10
- import { getSqlQuery } from "./utils"
9
+ import {
10
+ getSqlQuery,
11
+ SqlClients,
12
+ buildExternalTableId,
13
+ convertSqlType,
14
+ finaliseExternalTables,
15
+ } from "./utils"
16
+ import { DatasourcePlus } from "./base/datasourcePlus"
11
17
 
12
18
  module MySQLModule {
13
19
  const mysql = require("mysql2")
14
20
  const Sql = require("./base/sql")
15
- const {
16
- buildExternalTableId,
17
- convertType,
18
- copyExistingPropsOver,
19
- } = require("./utils")
20
- const { FieldTypes } = require("../constants")
21
21
 
22
22
  interface MySQLConfig {
23
23
  host: string
@@ -28,30 +28,6 @@ module MySQLModule {
28
28
  ssl?: object
29
29
  }
30
30
 
31
- const TYPE_MAP = {
32
- text: FieldTypes.LONGFORM,
33
- blob: FieldTypes.LONGFORM,
34
- enum: FieldTypes.STRING,
35
- varchar: FieldTypes.STRING,
36
- float: FieldTypes.NUMBER,
37
- int: FieldTypes.NUMBER,
38
- numeric: FieldTypes.NUMBER,
39
- bigint: FieldTypes.NUMBER,
40
- mediumint: FieldTypes.NUMBER,
41
- decimal: FieldTypes.NUMBER,
42
- dec: FieldTypes.NUMBER,
43
- double: FieldTypes.NUMBER,
44
- real: FieldTypes.NUMBER,
45
- fixed: FieldTypes.NUMBER,
46
- smallint: FieldTypes.NUMBER,
47
- timestamp: FieldTypes.DATETIME,
48
- date: FieldTypes.DATETIME,
49
- datetime: FieldTypes.DATETIME,
50
- time: FieldTypes.DATETIME,
51
- tinyint: FieldTypes.BOOLEAN,
52
- json: DatasourceFieldTypes.JSON,
53
- }
54
-
55
31
  const SCHEMA: Integration = {
56
32
  docs: "https://github.com/mysqljs/mysql",
57
33
  plus: true,
@@ -131,12 +107,14 @@ module MySQLModule {
131
107
  })
132
108
  }
133
109
 
134
- class MySQLIntegration extends Sql {
110
+ class MySQLIntegration extends Sql implements DatasourcePlus {
135
111
  private config: MySQLConfig
136
112
  private readonly client: any
113
+ public tables: Record<string, Table> = {}
114
+ public schemaErrors: Record<string, string> = {}
137
115
 
138
116
  constructor(config: MySQLConfig) {
139
- super("mysql")
117
+ super(SqlClients.MY_SQL)
140
118
  this.config = config
141
119
  if (config.ssl && Object.keys(config.ssl).length === 0) {
142
120
  delete config.ssl
@@ -156,7 +134,9 @@ module MySQLModule {
156
134
  false
157
135
  )
158
136
  const tableNames = tablesResp.map(
159
- (obj: any) => obj[`Tables_in_${database.toLowerCase()}`]
137
+ (obj: any) =>
138
+ obj[`Tables_in_${database}`] ||
139
+ obj[`Tables_in_${database.toLowerCase()}`]
160
140
  )
161
141
  for (let tableName of tableNames) {
162
142
  const primaryKeys = []
@@ -181,14 +161,10 @@ module MySQLModule {
181
161
  schema[columnName] = {
182
162
  name: columnName,
183
163
  autocolumn: isAuto,
184
- type: convertType(column.Type, TYPE_MAP),
164
+ type: convertSqlType(column.Type),
185
165
  constraints,
186
166
  }
187
167
  }
188
- // for now just default to first column
189
- if (primaryKeys.length === 0) {
190
- primaryKeys.push(descResp[0].Field)
191
- }
192
168
  if (!tables[tableName]) {
193
169
  tables[tableName] = {
194
170
  _id: buildExternalTableId(datasourceId, tableName),
@@ -197,12 +173,12 @@ module MySQLModule {
197
173
  schema,
198
174
  }
199
175
  }
200
-
201
- copyExistingPropsOver(tableName, tables, entities)
202
176
  }
203
177
 
204
178
  this.client.end()
205
- this.tables = tables
179
+ const final = finaliseExternalTables(tables, entities)
180
+ this.tables = final.tables
181
+ this.schemaErrors = final.errors
206
182
  }
207
183
 
208
184
  async create(query: SqlQuery | string) {
@@ -210,7 +186,7 @@ module MySQLModule {
210
186
  return results.length ? results : [{ created: true }]
211
187
  }
212
188
 
213
- read(query: SqlQuery | string) {
189
+ async read(query: SqlQuery | string) {
214
190
  return internalQuery(this.client, getSqlQuery(query))
215
191
  }
216
192
 
@@ -224,60 +200,12 @@ module MySQLModule {
224
200
  return results.length ? results : [{ deleted: true }]
225
201
  }
226
202
 
227
- async getReturningRow(json: QueryJson) {
228
- if (!json.extra || !json.extra.idFilter) {
229
- return {}
230
- }
231
- const input = this._query({
232
- endpoint: {
233
- ...json.endpoint,
234
- operation: Operation.READ,
235
- },
236
- fields: [],
237
- filters: json.extra.idFilter,
238
- paginate: {
239
- limit: 1,
240
- },
241
- })
242
- return internalQuery(this.client, input, false)
243
- }
244
-
245
- // when creating if an ID has been inserted need to make sure
246
- // the id filter is enriched with it before trying to retrieve the row
247
- checkLookupKeys(results: any, json: QueryJson) {
248
- if (!results?.insertId || !json.meta?.table || !json.meta.table.primary) {
249
- return json
250
- }
251
- const primaryKey = json.meta.table.primary?.[0]
252
- json.extra = {
253
- idFilter: {
254
- equal: {
255
- [primaryKey]: results.insertId,
256
- },
257
- },
258
- }
259
- return json
260
- }
261
-
262
203
  async query(json: QueryJson) {
263
- const operation = this._operation(json)
264
204
  this.client.connect()
265
- const input = this._query(json, { disableReturning: true })
266
- let row
267
- // need to manage returning, a feature mySQL can't do
268
- if (operation === operation.DELETE) {
269
- row = this.getReturningRow(json)
270
- }
271
- const results = await internalQuery(this.client, input, false)
272
- // same as delete, manage returning
273
- if (operation === Operation.CREATE || operation === Operation.UPDATE) {
274
- row = this.getReturningRow(this.checkLookupKeys(results, json))
275
- }
205
+ const queryFn = (query: any) => internalQuery(this.client, query, false)
206
+ const output = await this.queryWithReturning(json, queryFn)
276
207
  this.client.end()
277
- if (operation !== Operation.READ) {
278
- return row
279
- }
280
- return results.length ? results : [{ [operation.toLowerCase()]: true }]
208
+ return output
281
209
  }
282
210
  }
283
211