@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,458 @@
1
+ import {
2
+ Integration,
3
+ DatasourceFieldTypes,
4
+ QueryTypes,
5
+ SqlQuery,
6
+ QueryJson,
7
+ Operation,
8
+ } from "../definitions/datasource"
9
+ import {
10
+ finaliseExternalTables,
11
+ getSqlQuery,
12
+ buildExternalTableId,
13
+ convertSqlType,
14
+ SqlClients,
15
+ } from "./utils"
16
+ import oracledb, {
17
+ ExecuteOptions,
18
+ Result,
19
+ Connection,
20
+ ConnectionAttributes,
21
+ BindParameters,
22
+ } from "oracledb"
23
+ import Sql from "./base/sql"
24
+ import { Table } from "../definitions/common"
25
+ import { DatasourcePlus } from "./base/datasourcePlus"
26
+ import { FieldTypes } from "../constants"
27
+
28
+ module OracleModule {
29
+ oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT
30
+
31
+ interface OracleConfig {
32
+ host: string
33
+ port: number
34
+ database: string
35
+ user: string
36
+ password: string
37
+ }
38
+
39
+ const SCHEMA: Integration = {
40
+ docs: "https://github.com/oracle/node-oracledb",
41
+ plus: true,
42
+ friendlyName: "Oracle",
43
+ description:
44
+ "Oracle Database is an object-relational database management system developed by Oracle Corporation",
45
+ datasource: {
46
+ host: {
47
+ type: DatasourceFieldTypes.STRING,
48
+ default: "localhost",
49
+ required: true,
50
+ },
51
+ port: {
52
+ type: DatasourceFieldTypes.NUMBER,
53
+ required: true,
54
+ default: 1521,
55
+ },
56
+ database: {
57
+ type: DatasourceFieldTypes.STRING,
58
+ required: true,
59
+ },
60
+ user: {
61
+ type: DatasourceFieldTypes.STRING,
62
+ required: true,
63
+ },
64
+ password: {
65
+ type: DatasourceFieldTypes.PASSWORD,
66
+ required: true,
67
+ },
68
+ },
69
+ query: {
70
+ create: {
71
+ type: QueryTypes.SQL,
72
+ },
73
+ read: {
74
+ type: QueryTypes.SQL,
75
+ },
76
+ update: {
77
+ type: QueryTypes.SQL,
78
+ },
79
+ delete: {
80
+ type: QueryTypes.SQL,
81
+ },
82
+ },
83
+ }
84
+
85
+ const UNSUPPORTED_TYPES = ["BLOB", "CLOB", "NCLOB"]
86
+
87
+ /**
88
+ * Raw query response
89
+ */
90
+ interface ColumnsResponse {
91
+ TABLE_NAME: string
92
+ COLUMN_NAME: string
93
+ DATA_TYPE: string
94
+ DATA_DEFAULT: string | null
95
+ COLUMN_ID: number
96
+ CONSTRAINT_NAME: string | null
97
+ CONSTRAINT_TYPE: string | null
98
+ R_CONSTRAINT_NAME: string | null
99
+ SEARCH_CONDITION: string | null
100
+ }
101
+
102
+ /**
103
+ * An oracle constraint
104
+ */
105
+ interface OracleConstraint {
106
+ name: string
107
+ type: string
108
+ relatedConstraintName: string | null
109
+ searchCondition: string | null
110
+ }
111
+
112
+ /**
113
+ * An oracle column and it's related constraints
114
+ */
115
+ interface OracleColumn {
116
+ name: string
117
+ type: string
118
+ default: string | null
119
+ id: number
120
+ constraints: { [key: string]: OracleConstraint }
121
+ }
122
+
123
+ /**
124
+ * An oracle table and it's related columns
125
+ */
126
+ interface OracleTable {
127
+ name: string
128
+ columns: { [key: string]: OracleColumn }
129
+ }
130
+
131
+ const OracleContraintTypes = {
132
+ PRIMARY: "P",
133
+ NOT_NULL_OR_CHECK: "C",
134
+ FOREIGN_KEY: "R",
135
+ UNIQUE: "U",
136
+ }
137
+
138
+ class OracleIntegration extends Sql implements DatasourcePlus {
139
+ private readonly config: OracleConfig
140
+
141
+ public tables: Record<string, Table> = {}
142
+ public schemaErrors: Record<string, string> = {}
143
+
144
+ private readonly COLUMNS_SQL = `
145
+ SELECT
146
+ tabs.table_name,
147
+ cols.column_name,
148
+ cols.data_type,
149
+ cols.data_default,
150
+ cols.column_id,
151
+ cons.constraint_name,
152
+ cons.constraint_type,
153
+ cons.r_constraint_name,
154
+ cons.search_condition
155
+ FROM
156
+ user_tables tabs
157
+ JOIN
158
+ user_tab_columns cols
159
+ ON tabs.table_name = cols.table_name
160
+ LEFT JOIN
161
+ user_cons_columns col_cons
162
+ ON cols.column_name = col_cons.column_name
163
+ AND cols.table_name = col_cons.table_name
164
+ LEFT JOIN
165
+ user_constraints cons
166
+ ON col_cons.constraint_name = cons.constraint_name
167
+ AND cons.table_name = cols.table_name
168
+ WHERE
169
+ (cons.status = 'ENABLED'
170
+ OR cons.status IS NULL)
171
+ `
172
+ constructor(config: OracleConfig) {
173
+ super(SqlClients.ORACLE)
174
+ this.config = config
175
+ }
176
+
177
+ /**
178
+ * Map the flat tabular columns and constraints data into a nested object
179
+ */
180
+ private mapColumns(result: Result<ColumnsResponse>): {
181
+ [key: string]: OracleTable
182
+ } {
183
+ const oracleTables: { [key: string]: OracleTable } = {}
184
+
185
+ if (result.rows) {
186
+ result.rows.forEach(row => {
187
+ const tableName = row.TABLE_NAME
188
+ const columnName = row.COLUMN_NAME
189
+ const dataType = row.DATA_TYPE
190
+ const dataDefault = row.DATA_DEFAULT
191
+ const columnId = row.COLUMN_ID
192
+ const constraintName = row.CONSTRAINT_NAME
193
+ const constraintType = row.CONSTRAINT_TYPE
194
+ const relatedConstraintName = row.R_CONSTRAINT_NAME
195
+ const searchCondition = row.SEARCH_CONDITION
196
+
197
+ let table = oracleTables[tableName]
198
+ if (!table) {
199
+ table = {
200
+ name: tableName,
201
+ columns: {},
202
+ }
203
+ oracleTables[tableName] = table
204
+ }
205
+
206
+ let column = table.columns[columnName]
207
+ if (!column) {
208
+ column = {
209
+ name: columnName,
210
+ type: dataType,
211
+ default: dataDefault,
212
+ id: columnId,
213
+ constraints: {},
214
+ }
215
+ table.columns[columnName] = column
216
+ }
217
+
218
+ if (constraintName && constraintType) {
219
+ let constraint = column.constraints[constraintName]
220
+ if (!constraint) {
221
+ constraint = {
222
+ name: constraintName,
223
+ type: constraintType,
224
+ relatedConstraintName: relatedConstraintName,
225
+ searchCondition: searchCondition,
226
+ }
227
+ }
228
+ column.constraints[constraintName] = constraint
229
+ }
230
+ })
231
+ }
232
+
233
+ return oracleTables
234
+ }
235
+
236
+ private isSupportedColumn(column: OracleColumn) {
237
+ if (UNSUPPORTED_TYPES.includes(column.type)) {
238
+ return false
239
+ }
240
+
241
+ return true
242
+ }
243
+
244
+ private isAutoColumn(column: OracleColumn) {
245
+ if (column.default && column.default.toLowerCase().includes("nextval")) {
246
+ return true
247
+ }
248
+
249
+ return false
250
+ }
251
+
252
+ /**
253
+ * No native boolean in oracle. Best we can do is to check if a manual 1 or 0 number constraint has been set up
254
+ * This matches the default behaviour for generating DDL used in knex.
255
+ */
256
+ private isBooleanType(column: OracleColumn): boolean {
257
+ if (
258
+ column.type.toLowerCase() === "number" &&
259
+ Object.values(column.constraints).filter(c => {
260
+ if (
261
+ c.type === OracleContraintTypes.NOT_NULL_OR_CHECK &&
262
+ c.searchCondition
263
+ ) {
264
+ const condition = c.searchCondition
265
+ .replace(/\s/g, "") // remove spaces
266
+ .replace(/[']+/g, "") // remove quotes
267
+ if (
268
+ condition.includes("in(0,1)") ||
269
+ condition.includes("in(1,0)")
270
+ ) {
271
+ return true
272
+ }
273
+ }
274
+ return false
275
+ }).length > 0
276
+ ) {
277
+ return true
278
+ }
279
+
280
+ return false
281
+ }
282
+
283
+ private internalConvertType(column: OracleColumn): string {
284
+ if (this.isBooleanType(column)) {
285
+ return FieldTypes.BOOLEAN
286
+ }
287
+
288
+ return convertSqlType(column.type)
289
+ }
290
+
291
+ /**
292
+ * Fetches the tables from the oracle table and assigns them to the datasource.
293
+ * @param {*} datasourceId - datasourceId to fetch
294
+ * @param entities - the tables that are to be built
295
+ */
296
+ async buildSchema(datasourceId: string, entities: Record<string, Table>) {
297
+ const columnsResponse = await this.internalQuery<ColumnsResponse>({
298
+ sql: this.COLUMNS_SQL,
299
+ })
300
+ const oracleTables = this.mapColumns(columnsResponse)
301
+
302
+ const tables: { [key: string]: Table } = {}
303
+
304
+ // iterate each table
305
+ Object.values(oracleTables).forEach(oracleTable => {
306
+ let table = tables[oracleTable.name]
307
+ if (!table) {
308
+ table = {
309
+ _id: buildExternalTableId(datasourceId, oracleTable.name),
310
+ primary: [],
311
+ name: oracleTable.name,
312
+ schema: {},
313
+ }
314
+ tables[oracleTable.name] = table
315
+ }
316
+
317
+ // iterate each column on the table
318
+ Object.values(oracleTable.columns)
319
+ // remove columns that we can't read / save
320
+ .filter(oracleColumn => this.isSupportedColumn(oracleColumn))
321
+ // match the order of the columns in the db
322
+ .sort((c1, c2) => c1.id - c2.id)
323
+ .forEach(oracleColumn => {
324
+ const columnName = oracleColumn.name
325
+ let fieldSchema = table.schema[columnName]
326
+ if (!fieldSchema) {
327
+ fieldSchema = {
328
+ autocolumn: this.isAutoColumn(oracleColumn),
329
+ name: columnName,
330
+ type: this.internalConvertType(oracleColumn),
331
+ }
332
+ table.schema[columnName] = fieldSchema
333
+ }
334
+
335
+ // iterate each constraint on the column
336
+ Object.values(oracleColumn.constraints).forEach(
337
+ oracleConstraint => {
338
+ if (oracleConstraint.type === OracleContraintTypes.PRIMARY) {
339
+ table.primary!.push(columnName)
340
+ }
341
+ }
342
+ )
343
+ })
344
+ })
345
+
346
+ const final = finaliseExternalTables(tables, entities)
347
+ this.tables = final.tables
348
+ this.schemaErrors = final.errors
349
+ }
350
+
351
+ /**
352
+ * Knex default returning behaviour does not work with oracle
353
+ * Manually add the behaviour for the return column
354
+ */
355
+ private addReturning(
356
+ query: SqlQuery,
357
+ bindings: BindParameters,
358
+ returnColumn: string
359
+ ) {
360
+ if (bindings instanceof Array) {
361
+ bindings.push({ dir: oracledb.BIND_OUT })
362
+ query.sql =
363
+ query.sql + ` returning \"${returnColumn}\" into :${bindings.length}`
364
+ }
365
+ }
366
+
367
+ private async internalQuery<T>(
368
+ query: SqlQuery,
369
+ returnColum?: string,
370
+ operation?: string
371
+ ): Promise<Result<T>> {
372
+ let connection
373
+ try {
374
+ connection = await this.getConnection()
375
+
376
+ const options: ExecuteOptions = { autoCommit: true }
377
+ const bindings: BindParameters = query.bindings || []
378
+
379
+ if (
380
+ returnColum &&
381
+ (operation === Operation.CREATE || operation === Operation.UPDATE)
382
+ ) {
383
+ this.addReturning(query, bindings, returnColum)
384
+ }
385
+
386
+ const result: Result<T> = await connection.execute<T>(
387
+ query.sql,
388
+ bindings,
389
+ options
390
+ )
391
+
392
+ return result
393
+ } finally {
394
+ if (connection) {
395
+ try {
396
+ await connection.close()
397
+ } catch (err) {
398
+ console.error(err)
399
+ }
400
+ }
401
+ }
402
+ }
403
+
404
+ private getConnection = async (): Promise<Connection> => {
405
+ //connectString : "(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SID= ORCL)))"
406
+ const connectString = `${this.config.host}:${this.config.port || 1521}/${
407
+ this.config.database
408
+ }`
409
+ const attributes: ConnectionAttributes = {
410
+ user: this.config.user,
411
+ password: this.config.user,
412
+ connectString,
413
+ }
414
+ return oracledb.getConnection(attributes)
415
+ }
416
+
417
+ async create(query: SqlQuery | string): Promise<any[]> {
418
+ const response = await this.internalQuery<any>(getSqlQuery(query))
419
+ return response.rows && response.rows.length
420
+ ? response.rows
421
+ : [{ created: true }]
422
+ }
423
+
424
+ async read(query: SqlQuery | string): Promise<any[]> {
425
+ const response = await this.internalQuery<any>(getSqlQuery(query))
426
+ return response.rows ? response.rows : []
427
+ }
428
+
429
+ async update(query: SqlQuery | string): Promise<any[]> {
430
+ const response = await this.internalQuery(getSqlQuery(query))
431
+ return response.rows && response.rows.length
432
+ ? response.rows
433
+ : [{ updated: true }]
434
+ }
435
+
436
+ async delete(query: SqlQuery | string): Promise<any[]> {
437
+ const response = await this.internalQuery(getSqlQuery(query))
438
+ return response.rows && response.rows.length
439
+ ? response.rows
440
+ : [{ deleted: true }]
441
+ }
442
+
443
+ async query(json: QueryJson) {
444
+ const primaryKeys = json.meta!.table!.primary
445
+ const primaryKey = primaryKeys ? primaryKeys[0] : undefined
446
+ const queryFn = (query: any, operation: string) =>
447
+ this.internalQuery(query, primaryKey, operation)
448
+ const processFn = (response: any) => (response.rows ? response.rows : [])
449
+ const output = await this.queryWithReturning(json, queryFn, processFn)
450
+ return output
451
+ }
452
+ }
453
+
454
+ module.exports = {
455
+ schema: SCHEMA,
456
+ integration: OracleIntegration,
457
+ }
458
+ }
@@ -6,17 +6,18 @@ import {
6
6
  SqlQuery,
7
7
  } from "../definitions/datasource"
8
8
  import { Table } from "../definitions/common"
9
- 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"
10
17
 
11
18
  module PostgresModule {
12
19
  const { Pool } = require("pg")
13
20
  const Sql = require("./base/sql")
14
- const { FieldTypes } = require("../constants")
15
- const {
16
- buildExternalTableId,
17
- convertType,
18
- copyExistingPropsOver,
19
- } = require("./utils")
20
21
  const { escapeDangerousCharacters } = require("../utilities")
21
22
 
22
23
  const JSON_REGEX = /'{.*}'::json/s
@@ -27,6 +28,7 @@ module PostgresModule {
27
28
  database: string
28
29
  user: string
29
30
  password: string
31
+ schema: string
30
32
  ssl?: boolean
31
33
  ca?: string
32
34
  rejectUnauthorized?: boolean
@@ -64,6 +66,11 @@ module PostgresModule {
64
66
  default: "root",
65
67
  required: true,
66
68
  },
69
+ schema: {
70
+ type: DatasourceFieldTypes.STRING,
71
+ default: "public",
72
+ required: true,
73
+ },
67
74
  ssl: {
68
75
  type: DatasourceFieldTypes.BOOLEAN,
69
76
  default: false,
@@ -96,22 +103,6 @@ module PostgresModule {
96
103
  },
97
104
  }
98
105
 
99
- const TYPE_MAP = {
100
- text: FieldTypes.LONGFORM,
101
- varchar: FieldTypes.STRING,
102
- integer: FieldTypes.NUMBER,
103
- bigint: FieldTypes.NUMBER,
104
- decimal: FieldTypes.NUMBER,
105
- smallint: FieldTypes.NUMBER,
106
- real: FieldTypes.NUMBER,
107
- "double precision": FieldTypes.NUMBER,
108
- timestamp: FieldTypes.DATETIME,
109
- time: FieldTypes.DATETIME,
110
- boolean: FieldTypes.BOOLEAN,
111
- json: FieldTypes.JSON,
112
- date: FieldTypes.DATETIME,
113
- }
114
-
115
106
  async function internalQuery(client: any, query: SqlQuery) {
116
107
  // need to handle a specific issue with json data types in postgres,
117
108
  // new lines inside the JSON data will break it
@@ -132,13 +123,14 @@ module PostgresModule {
132
123
  }
133
124
  }
134
125
 
135
- class PostgresIntegration extends Sql {
126
+ class PostgresIntegration extends Sql implements DatasourcePlus {
136
127
  static pool: any
137
128
  private readonly client: any
138
129
  private readonly config: PostgresConfig
130
+ public tables: Record<string, Table> = {}
131
+ public schemaErrors: Record<string, string> = {}
139
132
 
140
- COLUMNS_SQL =
141
- "select * from information_schema.columns where not table_schema = 'information_schema' and not table_schema = 'pg_catalog'"
133
+ COLUMNS_SQL!: string
142
134
 
143
135
  PRIMARY_KEYS_SQL = `
144
136
  select tc.table_schema, tc.table_name, kc.column_name as primary_key
@@ -151,7 +143,7 @@ module PostgresModule {
151
143
  `
152
144
 
153
145
  constructor(config: PostgresConfig) {
154
- super("pg")
146
+ super(SqlClients.POSTGRES)
155
147
  this.config = config
156
148
 
157
149
  let newConfig = {
@@ -168,6 +160,17 @@ module PostgresModule {
168
160
  }
169
161
 
170
162
  this.client = this.pool
163
+ this.setSchema()
164
+ }
165
+
166
+ setSchema() {
167
+ if (!this.config.schema) {
168
+ this.config.schema = "public"
169
+ }
170
+ this.client.on("connect", (client: any) => {
171
+ client.query(`SET search_path TO ${this.config.schema}`)
172
+ })
173
+ this.COLUMNS_SQL = `select * from information_schema.columns where table_schema = '${this.config.schema}'`
171
174
  }
172
175
 
173
176
  /**
@@ -207,13 +210,13 @@ module PostgresModule {
207
210
  if (!tables[tableName] || !tables[tableName].schema) {
208
211
  tables[tableName] = {
209
212
  _id: buildExternalTableId(datasourceId, tableName),
210
- primary: tableKeys[tableName] || ["id"],
213
+ primary: tableKeys[tableName] || [],
211
214
  name: tableName,
212
215
  schema: {},
213
216
  }
214
217
  }
215
218
 
216
- const type: string = convertType(column.data_type, TYPE_MAP)
219
+ const type: string = convertSqlType(column.data_type)
217
220
  const identity = !!(
218
221
  column.identity_generation ||
219
222
  column.identity_start ||
@@ -232,10 +235,9 @@ module PostgresModule {
232
235
  }
233
236
  }
234
237
 
235
- for (let tableName of Object.keys(tables)) {
236
- copyExistingPropsOver(tableName, tables, entities)
237
- }
238
- this.tables = tables
238
+ const final = finaliseExternalTables(tables, entities)
239
+ this.tables = final.tables
240
+ this.schemaErrors = final.errors
239
241
  }
240
242
 
241
243
  async create(query: SqlQuery | string) {
@@ -261,8 +263,16 @@ module PostgresModule {
261
263
  async query(json: QueryJson) {
262
264
  const operation = this._operation(json).toLowerCase()
263
265
  const input = this._query(json)
264
- const response = await internalQuery(this.client, input)
265
- return response.rows.length ? response.rows : [{ [operation]: true }]
266
+ if (Array.isArray(input)) {
267
+ const responses = []
268
+ for (let query of input) {
269
+ responses.push(await internalQuery(this.client, query))
270
+ }
271
+ return responses
272
+ } else {
273
+ const response = await internalQuery(this.client, input)
274
+ return response.rows.length ? response.rows : [{ [operation]: true }]
275
+ }
266
276
  }
267
277
  }
268
278
 
@@ -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 RestModule {
8
9
  const fetch = require("node-fetch")
@@ -131,7 +132,7 @@ module RestModule {
131
132
  },
132
133
  }
133
134
 
134
- class RestIntegration {
135
+ class RestIntegration implements IntegrationBase {
135
136
  private config: RestConfig
136
137
  private headers: {
137
138
  [key: string]: string
@@ -1,4 +1,5 @@
1
1
  import { Integration, QueryTypes } from "../definitions/datasource"
2
+ import { IntegrationBase } from "./base/IntegrationBase"
2
3
 
3
4
  module S3Module {
4
5
  const AWS = require("aws-sdk")
@@ -42,7 +43,7 @@ module S3Module {
42
43
  },
43
44
  }
44
45
 
45
- class S3Integration {
46
+ class S3Integration implements IntegrationBase {
46
47
  private readonly config: S3Config
47
48
  private client: any
48
49
  private connectionPromise: Promise<any>
@@ -9,32 +9,39 @@ class TestConfiguration {
9
9
  }
10
10
 
11
11
  describe("MS SQL Server Integration", () => {
12
- let config
12
+ let config
13
13
 
14
- beforeEach(() => {
14
+ beforeEach(async () => {
15
15
  config = new TestConfiguration()
16
16
  })
17
17
 
18
- it("calls the create method with the correct params", async () => {
19
- const sql = "insert into users (name, age) values ('Joe', 123);"
20
- const response = await config.integration.create({
21
- sql
18
+ describe("check sql used", () => {
19
+ beforeEach(async () => {
20
+ await config.integration.connect()
21
+ })
22
+
23
+ it("calls the create method with the correct params", async () => {
24
+ const sql = "insert into users (name, age) values ('Joe', 123);"
25
+ const response = await config.integration.create({
26
+ sql
27
+ })
28
+ expect(config.integration.client.request).toHaveBeenCalledWith()
29
+ expect(response[0]).toEqual(sql)
22
30
  })
23
- expect(config.integration.client.query).toHaveBeenCalledWith(sql, {})
24
- })
25
31
 
26
- it("calls the read method with the correct params", async () => {
27
- const sql = "select * from users;"
28
- const response = await config.integration.read({
29
- sql
32
+ it("calls the read method with the correct params", async () => {
33
+ const sql = "select * from users;"
34
+ const response = await config.integration.read({
35
+ sql
36
+ })
37
+ expect(config.integration.client.request).toHaveBeenCalledWith()
38
+ expect(response[0]).toEqual(sql)
30
39
  })
31
- expect(config.integration.client.query).toHaveBeenCalledWith(sql, {})
32
40
  })
33
41
 
34
42
  describe("no rows returned", () => {
35
43
  beforeEach(async () => {
36
44
  await config.integration.connect()
37
- config.integration.client.query.mockImplementation(() => ({ rows: [] }))
38
45
  })
39
46
 
40
47
  it("returns the correct response when the create response has no rows", async () => {
@@ -42,7 +49,7 @@ describe("MS SQL Server Integration", () => {
42
49
  const response = await config.integration.create({
43
50
  sql
44
51
  })
45
- expect(response).toEqual([{ created: true }])
52
+ expect(response[0]).toEqual(sql)
46
53
  })
47
54
  })
48
55
  })