@budibase/server 0.9.190-alpha.7 → 1.0.1

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 (185) hide show
  1. package/builder/assets/{index.59c6065f.js → index.e95b024a.js} +140 -140
  2. package/builder/index.html +1 -1
  3. package/coverage/clover.xml +42 -45
  4. package/coverage/coverage-final.json +3 -3
  5. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  6. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  7. package/coverage/lcov-report/api/controllers/application.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/index.html +1 -1
  17. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/query.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  32. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/table/index.html +14 -14
  34. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/internal.js.html +8 -20
  36. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  45. package/coverage/lcov-report/api/index.html +1 -1
  46. package/coverage/lcov-report/api/index.js.html +1 -1
  47. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/index.html +1 -1
  60. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/row.js.html +536 -2
  69. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/table.js.html +436 -7
  73. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  77. package/coverage/lcov-report/automations/actions.js.html +1 -1
  78. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  79. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  80. package/coverage/lcov-report/automations/index.html +1 -1
  81. package/coverage/lcov-report/automations/index.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/index.html +1 -1
  91. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  109. package/coverage/lcov-report/automations/utils.js.html +1 -1
  110. package/coverage/lcov-report/constants/index.html +1 -1
  111. package/coverage/lcov-report/constants/index.js.html +1 -1
  112. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  113. package/coverage/lcov-report/constants/screens.js.html +1 -1
  114. package/coverage/lcov-report/db/client.js.html +1 -1
  115. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  116. package/coverage/lcov-report/db/index.html +1 -1
  117. package/coverage/lcov-report/db/index.js.html +1 -1
  118. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  119. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  120. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  121. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  122. package/coverage/lcov-report/db/newid.js.html +1 -1
  123. package/coverage/lcov-report/db/utils.js.html +1 -1
  124. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  125. package/coverage/lcov-report/events/index.html +1 -1
  126. package/coverage/lcov-report/events/index.js.html +1 -1
  127. package/coverage/lcov-report/events/utils.js.html +1 -1
  128. package/coverage/lcov-report/index.html +13 -13
  129. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  130. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  131. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  132. package/coverage/lcov-report/middleware/authorized.js.html +1 -1
  133. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  134. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  135. package/coverage/lcov-report/middleware/index.html +1 -1
  136. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  137. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  138. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  139. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  140. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  141. package/coverage/lcov-report/threads/automation.js.html +1 -1
  142. package/coverage/lcov-report/threads/index.html +1 -1
  143. package/coverage/lcov-report/threads/index.js.html +1 -1
  144. package/coverage/lcov-report/threads/query.js.html +1 -1
  145. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  146. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  147. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  148. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  149. package/coverage/lcov-report/utilities/global.js.html +1 -1
  150. package/coverage/lcov-report/utilities/index.html +1 -1
  151. package/coverage/lcov-report/utilities/index.js.html +1 -1
  152. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  153. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  154. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  155. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  156. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  157. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  158. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  159. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  160. package/coverage/lcov-report/utilities/security.js.html +1 -1
  161. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  162. package/coverage/lcov-report/utilities/users.js.html +1 -1
  163. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  164. package/coverage/lcov.info +63 -70
  165. package/dist/api/controllers/row/ExternalRequest.js +5 -2
  166. package/dist/api/controllers/table/internal.js +0 -4
  167. package/dist/api/routes/row.js +178 -0
  168. package/dist/api/routes/table.js +148 -5
  169. package/dist/definitions/datasource.js +12 -1
  170. package/dist/integrations/base/sql.js +1 -4
  171. package/dist/integrations/oracle.js +42 -22
  172. package/dist/package.json +10 -6
  173. package/dist/tsconfig.tsbuildinfo +1 -1
  174. package/package.json +11 -7
  175. package/scripts/docs/README.md +31 -0
  176. package/scripts/docs/generate.js +74 -0
  177. package/scripts/docs/toSwagger.js +320 -0
  178. package/scripts/integrations/oracle/docker-compose.yml +1 -1
  179. package/src/api/controllers/row/ExternalRequest.ts +8 -2
  180. package/src/api/controllers/table/internal.js +0 -4
  181. package/src/api/routes/row.js +178 -0
  182. package/src/api/routes/table.js +148 -5
  183. package/src/definitions/datasource.ts +11 -0
  184. package/src/integrations/base/sql.ts +1 -3
  185. package/src/integrations/oracle.ts +41 -35
@@ -14,24 +14,130 @@ const {
14
14
  const router = Router()
15
15
 
16
16
  router
17
+ /**
18
+ * @api {get} /api/:tableId/:rowId/enrich Get an enriched row
19
+ * @apiName Get an enriched row
20
+ * @apiGroup rows
21
+ * @apiPermission table read access
22
+ * @apiDescription This API is only useful when dealing with rows that have relationships.
23
+ * Normally when a row is a returned from the API relationships will only have the structure
24
+ * `{ primaryDisplay: "name", _id: ... }` but this call will return the full related rows
25
+ * for each relationship instead.
26
+ *
27
+ * @apiParam {string} rowId The ID of the row which is to be retrieved and enriched.
28
+ *
29
+ * @apiSuccess {object} row The response body will be the enriched row.
30
+ */
17
31
  .get(
18
32
  "/api/:tableId/:rowId/enrich",
19
33
  paramSubResource("tableId", "rowId"),
20
34
  authorized(PermissionTypes.TABLE, PermissionLevels.READ),
21
35
  rowController.fetchEnrichedRow
22
36
  )
37
+ /**
38
+ * @api {get} /api/:tableId/rows Get all rows in a table
39
+ * @apiName Get all rows in a table
40
+ * @apiGroup rows
41
+ * @apiPermission table read access
42
+ * @apiDescription This is a deprecated endpoint that should not be used anymore, instead use the search endpoint.
43
+ * This endpoint gets all of the rows within the specified table - it is not heavily used
44
+ * due to its lack of support for pagination. With SQL tables this will retrieve up to a limit and then
45
+ * will simply stop.
46
+ *
47
+ * @apiParam {string} tableId The ID of the table to retrieve all rows within.
48
+ *
49
+ * @apiSuccess {object[]} rows The response body will be an array of all rows found.
50
+ */
23
51
  .get(
24
52
  "/api/:tableId/rows",
25
53
  paramResource("tableId"),
26
54
  authorized(PermissionTypes.TABLE, PermissionLevels.READ),
27
55
  rowController.fetch
28
56
  )
57
+ /**
58
+ * @api {get} /api/:tableId/rows/:rowId Retrieve a single row
59
+ * @apiName Retrieve a single row
60
+ * @apiGroup rows
61
+ * @apiPermission table read access
62
+ * @apiDescription This endpoint retrieves only the specified row. If you wish to retrieve
63
+ * a row by anything other than its _id field, use the search endpoint.
64
+ *
65
+ * @apiParam {string} tableId The ID of the table to retrieve a row from.
66
+ * @apiParam {string} rowId The ID of the row to retrieve.
67
+ *
68
+ * @apiSuccess {object} body The response body will be the row that was found.
69
+ */
29
70
  .get(
30
71
  "/api/:tableId/rows/:rowId",
31
72
  paramSubResource("tableId", "rowId"),
32
73
  authorized(PermissionTypes.TABLE, PermissionLevels.READ),
33
74
  rowController.find
34
75
  )
76
+ /**
77
+ * @api {post} /api/:tableId/search Search for rows in a table
78
+ * @apiName Search for rows in a table
79
+ * @apiGroup rows
80
+ * @apiPermission table read access
81
+ * @apiDescription This is the primary method of accessing rows in Budibase, the data provider
82
+ * and data UI in the builder are built atop this. All filtering, sorting and pagination is
83
+ * handled through this, for internal and external (datasource plus, e.g. SQL) tables.
84
+ *
85
+ * @apiParam {string} tableId The ID of the table to retrieve rows from.
86
+ *
87
+ * @apiParam (Body) {boolean} [paginate] If pagination is required then this should be set to true,
88
+ * defaults to false.
89
+ * @apiParam (Body) {object} [query] This contains a set of filters which should be applied, if none
90
+ * specified then the request will be unfiltered. An example with all of the possible query
91
+ * options has been supplied below.
92
+ * @apiParam (Body) {number} [limit] This sets a limit for the number of rows that will be returned,
93
+ * this will be implemented at the database level if supported for performance reasons. This
94
+ * is useful when paginating to set exactly how many rows per page.
95
+ * @apiParam (Body) {string} [bookmark] If pagination is enabled then a bookmark will be returned
96
+ * with each successful search request, this should be supplied back to get the next page.
97
+ * @apiParam (Body) {object} [sort] If sort is desired this should contain the name of the column to
98
+ * sort on.
99
+ * @apiParam (Body) {string} [sortOrder] If sort is enabled then this can be either "descending" or
100
+ * "ascending" as required.
101
+ * @apiParam (Body) {string} [sortType] If sort is enabled then you must specify the type of search
102
+ * being used, either "string" or "number". This is only used for internal tables.
103
+ *
104
+ * @apiParamExample {json} Example:
105
+ * {
106
+ * "tableId": "ta_70260ff0b85c467ca74364aefc46f26d",
107
+ * "query": {
108
+ * "string": {},
109
+ * "fuzzy": {},
110
+ * "range": {
111
+ * "columnName": {
112
+ * "high": 20,
113
+ * "low": 10,
114
+ * }
115
+ * },
116
+ * "equal": {
117
+ * "columnName": "someValue"
118
+ * },
119
+ * "notEqual": {},
120
+ * "empty": {},
121
+ * "notEmpty": {},
122
+ * "contains": {},
123
+ * "notContains": {}
124
+ * "oneOf": {
125
+ * "columnName": ["value"]
126
+ * }
127
+ * },
128
+ * "limit": 10,
129
+ * "sort": "name",
130
+ * "sortOrder": "descending",
131
+ * "sortType": "string",
132
+ * "paginate": true
133
+ * }
134
+ *
135
+ * @apiSuccess {object[]} rows An array of rows that was found based on the supplied parameters.
136
+ * @apiSuccess {boolean} hasNextPage If pagination was enabled then this specifies whether or
137
+ * not there is another page after this request.
138
+ * @apiSuccess {string} bookmark The bookmark to be sent with the next request to get the next
139
+ * page.
140
+ */
35
141
  .post(
36
142
  "/api/:tableId/search",
37
143
  paramResource("tableId"),
@@ -46,6 +152,30 @@ router
46
152
  authorized(PermissionTypes.TABLE, PermissionLevels.READ),
47
153
  rowController.search
48
154
  )
155
+ /**
156
+ * @api {post} /api/:tableId/rows Creates a new row
157
+ * @apiName Creates a new row
158
+ * @apiGroup rows
159
+ * @apiPermission table write access
160
+ * @apiDescription This API will create a new row based on the supplied body. If the
161
+ * body includes an "_id" field then it will update an existing row if the field
162
+ * links to one. Please note that "_id", "_rev" and "tableId" are fields that are
163
+ * already used by Budibase tables and cannot be used for columns.
164
+ *
165
+ * @apiParam {string} tableId The ID of the table to save a row to.
166
+ *
167
+ * @apiParam (Body) {string} [_id] If the row exists already then an ID for the row must be provided.
168
+ * @apiParam (Body) {string} [_rev] If working with an existing row for an internal table its revision
169
+ * must also be provided.
170
+ * @apiParam (Body) {string} tableId The ID of the table should also be specified in the row body itself.
171
+ * @apiParam (Body) {any} [any] Any field supplied in the body will be assessed to see if it matches
172
+ * a column in the specified table. All other fields will be dropped and not stored.
173
+ *
174
+ * @apiSuccess {string} _id The ID of the row that was just saved, if it was just created this
175
+ * is the rows new ID.
176
+ * @apiSuccess {string} [_rev] If saving to an internal table a revision will also be returned.
177
+ * @apiSuccess {object} body The contents of the row that was saved will be returned as well.
178
+ */
49
179
  .post(
50
180
  "/api/:tableId/rows",
51
181
  paramResource("tableId"),
@@ -53,18 +183,66 @@ router
53
183
  usage,
54
184
  rowController.save
55
185
  )
186
+ /**
187
+ * @api {patch} /api/:tableId/rows Updates a row
188
+ * @apiName Update a row
189
+ * @apiGroup rows
190
+ * @apiPermission table write access
191
+ * @apiDescription This endpoint is identical to the row creation endpoint but instead it will
192
+ * error if an _id isn't provided, it will only function for existing rows.
193
+ */
56
194
  .patch(
57
195
  "/api/:tableId/rows",
58
196
  paramResource("tableId"),
59
197
  authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
60
198
  rowController.patch
61
199
  )
200
+ /**
201
+ * @api {post} /api/:tableId/rows/validate Validate inputs for a row
202
+ * @apiName Validate inputs for a row
203
+ * @apiGroup rows
204
+ * @apiPermission table write access
205
+ * @apiDescription When attempting to save a row you may want to check if the row is valid
206
+ * given the table schema, this will iterate through all the constraints on the table and
207
+ * check if the request body is valid.
208
+ *
209
+ * @apiParam {string} tableId The ID of the table the row is to be validated for.
210
+ *
211
+ * @apiParam (Body) {any} [any] Any fields provided in the request body will be tested
212
+ * against the table schema and constraints.
213
+ *
214
+ * @apiSuccess {boolean} valid If inputs provided are acceptable within the table schema this
215
+ * will be true, if it is not then then errors property will be populated.
216
+ * @apiSuccess {object} [errors] A key value map of information about fields on the input
217
+ * which do not match the table schema. The key name will be the column names that have breached
218
+ * the schema.
219
+ */
62
220
  .post(
63
221
  "/api/:tableId/rows/validate",
64
222
  paramResource("tableId"),
65
223
  authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
66
224
  rowController.validate
67
225
  )
226
+ /**
227
+ * @api {delete} /api/:tableId/rows Delete rows
228
+ * @apiName Delete rows
229
+ * @apiGroup rows
230
+ * @apiPermission table write access
231
+ * @apiDescription This endpoint can delete a single row, or delete them in a bulk
232
+ * fashion.
233
+ *
234
+ * @apiParam {string} tableId The ID of the table the row is to be deleted from.
235
+ *
236
+ * @apiParam (Body) {object[]} [rows] If bulk deletion is desired then provide the rows in this
237
+ * key of the request body that are to be deleted.
238
+ * @apiParam (Body) {string} [_id] If deleting a single row then provide its ID in this field.
239
+ * @apiParam (Body) {string} [_rev] If deleting a single row from an internal table then provide its
240
+ * revision here.
241
+ *
242
+ * @apiSuccess {object[]|object} body If deleting bulk then the response body will be an array
243
+ * of the deleted rows, if deleting a single row then the body will contain a "row" property which
244
+ * is the deleted row.
245
+ */
68
246
  .delete(
69
247
  "/api/:tableId/rows",
70
248
  paramResource("tableId"),
@@ -27,13 +27,110 @@ function generateSaveValidator() {
27
27
  }
28
28
 
29
29
  router
30
+ /**
31
+ * @api {get} /api/tables Fetch all tables
32
+ * @apiName Fetch all tables
33
+ * @apiGroup tables
34
+ * @apiPermission table read access
35
+ * @apiDescription This endpoint retrieves all of the tables which have been created in
36
+ * an app. This includes all of the external and internal tables; to tell the difference
37
+ * between these look for the "type" property on each table, either being "internal" or "external".
38
+ *
39
+ * @apiSuccess {object[]} body The response body will be the list of tables that was found - as
40
+ * this does not take any parameters the only error scenario is no access.
41
+ */
30
42
  .get("/api/tables", authorized(BUILDER), tableController.fetch)
43
+ /**
44
+ * @api {get} /api/tables/:id Fetch a single table
45
+ * @apiName Fetch a single table
46
+ * @apiGroup tables
47
+ * @apiPermission table read access
48
+ * @apiDescription Retrieves a single table this could be be internal or external based on
49
+ * the provided table ID.
50
+ *
51
+ * @apiParam {string} id The ID of the table which is to be retrieved.
52
+ *
53
+ * @apiSuccess {object[]} body The response body will be the table that was found.
54
+ */
31
55
  .get(
32
56
  "/api/tables/:id",
33
57
  paramResource("id"),
34
58
  authorized(PermissionTypes.TABLE, PermissionLevels.READ),
35
59
  tableController.find
36
60
  )
61
+ /**
62
+ * @api {post} /api/tables Save a table
63
+ * @apiName Save a table
64
+ * @apiGroup tables
65
+ * @apiPermission builder
66
+ * @apiDescription Create or update a table with this endpoint, this will function for both internal
67
+ * external tables.
68
+ *
69
+ * @apiParam (Body) {string} [_id] If updating an existing table then the ID of the table must be specified.
70
+ * @apiParam (Body) {string} [_rev] If updating an existing internal table then the revision must also be specified.
71
+ * @apiParam (Body) {string} type] This should either be "internal" or "external" depending on the table type -
72
+ * this will default to internal.
73
+ * @apiParam (Body) {string} [sourceId] If creating an external table then this should be set to the data source ID. If
74
+ * building an internal table this does not need to be set, although it will be returned as "bb_internal".
75
+ * @apiParam (Body) {string} name The name of the table, this will be used in the UI. To rename the table simply
76
+ * supply the table structure to this endpoint with the name changed.
77
+ * @apiParam (Body) {object} schema A key value object which has all of the columns in the table as the keys in this
78
+ * object. For each column a "type" and "constraints" must be specified, with some types requiring further information.
79
+ * More information about the schema structure can be found in the Typescript definitions.
80
+ * @apiParam (Body) {string} [primaryDisplay] The name of the column which should be used when displaying rows
81
+ * from this table as relationships.
82
+ * @apiParam (Body) {object[]} [indexes] Specifies the search indexes - this is deprecated behaviour with the introduction
83
+ * of lucene indexes. This functionality is only available for internal tables.
84
+ * @apiParam (Body) {object} [_rename] If a column is to be renamed then the "old" column name should be set in this
85
+ * structure, and the "updated", new column name should also be supplied. The schema should also be updated, this field
86
+ * lets the server know that a field hasn't just been deleted, that the data has moved to a new name, this will fix
87
+ * the rows in the table. This functionality is only available for internal tables.
88
+ * @apiParam (Body) {object} [dataImport] When creating an internal table it can be built from a CSV, by using the
89
+ * CSV validation endpoint. Send the CSV data to the validation endpoint, then put the results of that call
90
+ * into this property, along with the CSV and a table/rows will be built from it. This is not supported when updating
91
+ * or for external tables.
92
+ *
93
+ * @apiParamExample {json} Example:
94
+ * {
95
+ * "_id": "ta_05541307fa0f4044abee071ca2a82119",
96
+ * "_rev": "10-0fbe4e78f69b255d79f1017e2eeef807",
97
+ * "type": "internal",
98
+ * "views": {},
99
+ * "name": "tableName",
100
+ * "schema": {
101
+ * "column": {
102
+ * "type": "string",
103
+ * "constraints": {
104
+ * "type": "string",
105
+ * "length": {
106
+ * "maximum": null
107
+ * },
108
+ * "presence": false
109
+ * },
110
+ * "name": "column"
111
+ * },
112
+ * },
113
+ * "primaryDisplay": "column",
114
+ * "indexes": [],
115
+ * "sourceId": "bb_internal",
116
+ * "_rename": {
117
+ * "old": "columnName",
118
+ * "updated": "newColumnName",
119
+ * },
120
+ * "dataImport": {
121
+ * "csvString": "column\nvalue",
122
+ * "primaryDisplay": "column",
123
+ * "schema": {
124
+ * "column": {
125
+ * "type": "string"
126
+ * }
127
+ * }
128
+ * }
129
+ * }
130
+ *
131
+ * @apiSuccess {object} table The response body will contain the table structure after being cleaned up and
132
+ * saved to the database.
133
+ */
37
134
  .post(
38
135
  "/api/tables",
39
136
  // allows control over updating a table
@@ -42,22 +139,68 @@ router
42
139
  generateSaveValidator(),
43
140
  tableController.save
44
141
  )
142
+ /**
143
+ * @api {post} /api/tables/csv/validate Validate a CSV for a table
144
+ * @apiName Validate a CSV for a table
145
+ * @apiGroup tables
146
+ * @apiPermission builder
147
+ * @apiDescription When creating a new table, or importing a CSV to an existing table the CSV must be validated and
148
+ * converted into a Budibase schema; this endpoint does this.
149
+ *
150
+ * @apiParam (Body) {string} csvString The CSV which is to be validated as a string.
151
+ * @apiParam (Body) {object} [schema] When a CSV has been validated it is possible to re-validate after changing the
152
+ * type of a field, by default everything will be strings as there is no way to infer types. The returned schema can
153
+ * be updated and then returned to the endpoint to re-validate and check if the type will work for the CSV, e.g.
154
+ * using a number instead of strings.
155
+ * @apiParam (Body) {string} [tableId] If importing data to an existing table this will pull the current table and
156
+ * remove any fields from the CSV schema which do not exist on the table/don't match the type of the table. When
157
+ * importing a CSV to an existing table only fields that are present on the table can be imported.
158
+ *
159
+ * @apiSuccess {object} schema The response body will contain a "schema" object that represents the schema found for
160
+ * the CSV - this will be in the same format used for table schema.s
161
+ */
45
162
  .post(
46
163
  "/api/tables/csv/validate",
47
164
  authorized(BUILDER),
48
165
  tableController.validateCSVSchema
49
166
  )
167
+ /**
168
+ * @api {post} /api/tables/:tableId/:revId Delete a table
169
+ * @apiName Delete a table
170
+ * @apiGroup tables
171
+ * @apiPermission builder
172
+ * @apiDescription This endpoint will delete a table and all of its associated data, for this reason it is
173
+ * quite dangerous - it will work for internal and external tables.
174
+ *
175
+ * @apiParam {string} tableId The ID of the table which is to be deleted.
176
+ * @apiParam {string} [revId] If deleting an internal table then the revision must also be supplied (_rev), for
177
+ * external tables this can simply be set to anything, e.g. "external".
178
+ *
179
+ * @apiSuccess {string} message A message stating that the table was deleted successfully.
180
+ */
50
181
  .delete(
51
182
  "/api/tables/:tableId/:revId",
52
183
  paramResource("tableId"),
53
184
  authorized(BUILDER),
54
185
  tableController.destroy
55
186
  )
56
- // this is currently builder only, but in the future
57
- // it could be carried out by an end user in app,
58
- // however some thought will need to be had about
59
- // implications for automations (triggers)
60
- // new trigger type, bulk rows created
187
+ /**
188
+ * @api {post} /api/tables/:tableId/:revId Import CSV to existing table
189
+ * @apiName Import CSV to existing table
190
+ * @apiGroup tables
191
+ * @apiPermission builder
192
+ * @apiDescription This endpoint will import data to existing tables, internal or external. It is used in combination
193
+ * with the CSV validation endpoint. Take the output of the CSV validation endpoint and pass it to this endpoint to
194
+ * import the data; please note this will only import fields that already exist on the table/match the type.
195
+ *
196
+ * @apiParam {string} tableId The ID of the table which the data should be imported to.
197
+ *
198
+ * @apiParam (Body) {object} dataImport This is the same as the structure used when creating an internal table with
199
+ * a CSV, it will have the "schema" returned from the CSV validation endpoint and the "csvString" which is to be
200
+ * turned into rows.
201
+ *
202
+ * @apiSuccess {string} message A message stating that the data was imported successfully.
203
+ */
61
204
  .post(
62
205
  "/api/tables/:tableId/import",
63
206
  paramResource("tableId"),
@@ -54,6 +54,17 @@ export enum IncludeRelationships {
54
54
  EXCLUDE = 0,
55
55
  }
56
56
 
57
+ export enum FilterTypes {
58
+ STRING = "string",
59
+ FUZZY = "fuzzy",
60
+ RANGE = "range",
61
+ EQUAL = "equal",
62
+ NOT_EQUAL = "notEqual",
63
+ EMPTY = "empty",
64
+ NOT_EMPTY = "notEmpty",
65
+ ONE_OF = "oneOf",
66
+ }
67
+
57
68
  export interface QueryDefinition {
58
69
  type: QueryTypes
59
70
  displayName?: string
@@ -93,7 +93,7 @@ class InternalBuilder {
93
93
  if (filters.oneOf) {
94
94
  iterate(filters.oneOf, (key, array) => {
95
95
  const fnc = allOr ? "orWhereIn" : "whereIn"
96
- query = query[fnc](key, array)
96
+ query = query[fnc](key, Array.isArray(array) ? array : [array])
97
97
  })
98
98
  }
99
99
  if (filters.string) {
@@ -435,8 +435,6 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
435
435
  id = results?.[0].id
436
436
  } else if (sqlClient === SqlClients.MY_SQL) {
437
437
  id = results?.insertId
438
- } else if (sqlClient === SqlClients.ORACLE) {
439
- id = response.outBinds[0][0]
440
438
  }
441
439
  row = processFn(
442
440
  await this.getReturningRow(queryFn, this.checkLookupKeys(id, json))
@@ -348,27 +348,7 @@ module OracleModule {
348
348
  this.schemaErrors = final.errors
349
349
  }
350
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>> {
351
+ private async internalQuery<T>(query: SqlQuery): Promise<Result<T>> {
372
352
  let connection
373
353
  try {
374
354
  connection = await this.getConnection()
@@ -376,13 +356,6 @@ module OracleModule {
376
356
  const options: ExecuteOptions = { autoCommit: true }
377
357
  const bindings: BindParameters = query.bindings || []
378
358
 
379
- if (
380
- returnColum &&
381
- (operation === Operation.CREATE || operation === Operation.UPDATE)
382
- ) {
383
- this.addReturning(query, bindings, returnColum)
384
- }
385
-
386
359
  const result: Result<T> = await connection.execute<T>(
387
360
  query.sql,
388
361
  bindings,
@@ -441,13 +414,46 @@ module OracleModule {
441
414
  }
442
415
 
443
416
  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
417
+ const operation = this._operation(json)
418
+ const input = this._query(json, { disableReturning: true })
419
+ if (Array.isArray(input)) {
420
+ const responses = []
421
+ for (let query of input) {
422
+ responses.push(await this.internalQuery(query))
423
+ }
424
+ return responses
425
+ } else {
426
+ // read the row to be deleted up front for the return
427
+ let deletedRows
428
+ if (operation === Operation.DELETE) {
429
+ const queryFn = (query: any) => this.internalQuery(query)
430
+ deletedRows = await this.getReturningRow(queryFn, json)
431
+ }
432
+
433
+ // run the query
434
+ const response = await this.internalQuery(input)
435
+
436
+ // get the results or return the created / updated / deleted row
437
+ if (deletedRows?.rows?.length) {
438
+ return deletedRows.rows
439
+ } else if (response.rows?.length) {
440
+ return response.rows
441
+ } else {
442
+ // get the last row that was updated
443
+ if (
444
+ response.lastRowid &&
445
+ json.endpoint?.entityId &&
446
+ operation !== Operation.DELETE
447
+ ) {
448
+ const lastRow = await this.internalQuery({
449
+ sql: `SELECT * FROM \"${json.endpoint.entityId}\" WHERE ROWID = '${response.lastRowid}'`,
450
+ })
451
+ return lastRow.rows
452
+ } else {
453
+ return [{ [ operation.toLowerCase() ]: true }]
454
+ }
455
+ }
456
+ }
451
457
  }
452
458
  }
453
459