@budibase/server 0.9.174 → 0.9.176-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 (203) hide show
  1. package/builder/assets/{index.7469e1e4.css → index.75ed4773.css} +1 -1
  2. package/builder/assets/{index.ba2741f9.js → index.d3780441.js} +34 -34
  3. package/builder/index.html +2 -2
  4. package/coverage/clover.xml +383 -207
  5. package/coverage/coverage-final.json +8 -6
  6. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  7. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/application.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/datasource.js.html +120 -24
  15. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +19 -19
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/query.js.html +9 -3
  23. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/index.html +14 -14
  27. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/utils.js.html +11 -32
  31. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  32. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/table/external.js.html +908 -0
  34. package/coverage/lcov-report/api/controllers/table/index.html +59 -29
  35. package/coverage/lcov-report/api/controllers/table/index.js.html +52 -376
  36. package/coverage/lcov-report/api/controllers/table/internal.js.html +494 -0
  37. package/coverage/lcov-report/api/controllers/table/utils.js.html +70 -10
  38. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  46. package/coverage/lcov-report/api/index.html +1 -1
  47. package/coverage/lcov-report/api/index.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/index.html +1 -1
  61. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  78. package/coverage/lcov-report/automations/actions.js.html +1 -1
  79. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  80. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  81. package/coverage/lcov-report/automations/index.html +1 -1
  82. package/coverage/lcov-report/automations/index.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/index.html +1 -1
  92. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  101. package/coverage/lcov-report/automations/thread.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  111. package/coverage/lcov-report/automations/utils.js.html +1 -1
  112. package/coverage/lcov-report/constants/index.html +5 -5
  113. package/coverage/lcov-report/constants/index.js.html +25 -4
  114. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  115. package/coverage/lcov-report/constants/screens.js.html +1 -1
  116. package/coverage/lcov-report/db/client.js.html +1 -1
  117. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  118. package/coverage/lcov-report/db/index.html +1 -1
  119. package/coverage/lcov-report/db/index.js.html +1 -1
  120. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  121. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  122. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  123. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  124. package/coverage/lcov-report/db/newid.js.html +1 -1
  125. package/coverage/lcov-report/db/utils.js.html +1 -1
  126. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  127. package/coverage/lcov-report/events/index.html +1 -1
  128. package/coverage/lcov-report/events/index.js.html +1 -1
  129. package/coverage/lcov-report/events/utils.js.html +1 -1
  130. package/coverage/lcov-report/index.html +38 -38
  131. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  132. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  133. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  134. package/coverage/lcov-report/middleware/authorized.js.html +1 -1
  135. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  136. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  137. package/coverage/lcov-report/middleware/index.html +1 -1
  138. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  139. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  140. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  141. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  142. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  143. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  144. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  145. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  146. package/coverage/lcov-report/utilities/global.js.html +1 -1
  147. package/coverage/lcov-report/utilities/index.html +1 -1
  148. package/coverage/lcov-report/utilities/index.js.html +1 -1
  149. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  150. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  151. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  152. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  153. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  154. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  155. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  156. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  157. package/coverage/lcov-report/utilities/security.js.html +1 -1
  158. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  159. package/coverage/lcov-report/utilities/users.js.html +1 -1
  160. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  161. package/coverage/lcov.info +652 -332
  162. package/dist/api/controllers/datasource.js +41 -14
  163. package/dist/api/controllers/query.js +3 -1
  164. package/dist/api/controllers/row/ExternalRequest.js +12 -10
  165. package/dist/api/controllers/row/utils.js +3 -11
  166. package/dist/api/controllers/table/external.js +222 -0
  167. package/dist/api/controllers/table/index.js +28 -121
  168. package/dist/api/controllers/table/internal.js +138 -0
  169. package/dist/api/controllers/table/utils.js +17 -0
  170. package/dist/constants/index.js +6 -0
  171. package/dist/definitions/datasource.js +3 -0
  172. package/dist/integrations/base/datasourcePlus.js +2 -0
  173. package/dist/integrations/base/sql.js +16 -11
  174. package/dist/integrations/base/sqlTable.js +141 -0
  175. package/dist/integrations/base/utils.js +30 -0
  176. package/dist/integrations/mysql.js +13 -7
  177. package/dist/integrations/postgres.js +18 -8
  178. package/dist/integrations/utils.js +21 -6
  179. package/dist/package.json +4 -4
  180. package/dist/tests/utilities/TestConfiguration.js +2 -1
  181. package/dist/tsconfig.tsbuildinfo +1 -1
  182. package/package.json +5 -5
  183. package/src/api/controllers/datasource.js +46 -14
  184. package/src/api/controllers/query.js +3 -1
  185. package/src/api/controllers/row/ExternalRequest.ts +12 -10
  186. package/src/api/controllers/row/utils.js +3 -10
  187. package/src/api/controllers/table/external.js +276 -0
  188. package/src/api/controllers/table/index.js +27 -135
  189. package/src/api/controllers/table/internal.js +138 -0
  190. package/src/api/controllers/table/utils.js +20 -0
  191. package/src/api/routes/tests/datasource.spec.js +2 -2
  192. package/src/api/routes/tests/query.spec.js +0 -1
  193. package/src/constants/index.js +7 -0
  194. package/src/definitions/common.ts +7 -1
  195. package/src/definitions/datasource.ts +5 -0
  196. package/src/integrations/base/datasourcePlus.ts +8 -0
  197. package/src/integrations/base/sql.ts +15 -16
  198. package/src/integrations/base/sqlTable.ts +167 -0
  199. package/src/integrations/base/utils.ts +19 -0
  200. package/src/integrations/mysql.ts +15 -9
  201. package/src/integrations/postgres.ts +19 -9
  202. package/src/integrations/utils.ts +22 -6
  203. package/src/tests/utilities/TestConfiguration.js +2 -1
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ const CouchDB = require("../../../db");
23
+ const linkRows = require("../../../db/linkedRows");
24
+ const { getRowParams, generateTableID } = require("../../../db/utils");
25
+ const { FieldTypes } = require("../../../constants");
26
+ const { TableSaveFunctions } = require("./utils");
27
+ exports.save = function (ctx) {
28
+ return __awaiter(this, void 0, void 0, function* () {
29
+ const appId = ctx.appId;
30
+ const db = new CouchDB(appId);
31
+ const _a = ctx.request.body, { dataImport } = _a, rest = __rest(_a, ["dataImport"]);
32
+ let tableToSave = Object.assign({ type: "table", _id: generateTableID(), views: {} }, rest);
33
+ // if the table obj had an _id then it will have been retrieved
34
+ let oldTable;
35
+ if (ctx.request.body && ctx.request.body._id) {
36
+ oldTable = yield db.get(ctx.request.body._id);
37
+ }
38
+ // saving a table is a complex operation, involving many different steps, this
39
+ // has been broken out into a utility to make it more obvious/easier to manipulate
40
+ const tableSaveFunctions = new TableSaveFunctions({
41
+ db,
42
+ ctx,
43
+ oldTable,
44
+ dataImport,
45
+ });
46
+ tableToSave = yield tableSaveFunctions.before(tableToSave);
47
+ // make sure that types don't change of a column, have to remove
48
+ // the column if you want to change the type
49
+ if (oldTable && oldTable.schema) {
50
+ for (let propKey of Object.keys(tableToSave.schema)) {
51
+ let column = tableToSave.schema[propKey];
52
+ let oldColumn = oldTable.schema[propKey];
53
+ if (oldColumn && oldColumn.type === "internal") {
54
+ oldColumn.type = "auto";
55
+ }
56
+ if (oldColumn && oldColumn.type !== column.type) {
57
+ ctx.throw(400, "Cannot change the type of a column");
58
+ }
59
+ }
60
+ }
61
+ // Don't rename if the name is the same
62
+ let { _rename } = tableToSave;
63
+ /* istanbul ignore next */
64
+ if (_rename && _rename.old === _rename.updated) {
65
+ _rename = null;
66
+ delete tableToSave._rename;
67
+ }
68
+ // rename row fields when table column is renamed
69
+ /* istanbul ignore next */
70
+ if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) {
71
+ ctx.throw(400, "Cannot rename a linked column.");
72
+ }
73
+ tableToSave = yield tableSaveFunctions.mid(tableToSave);
74
+ // update schema of non-statistics views when new columns are added
75
+ for (let view in tableToSave.views) {
76
+ const tableView = tableToSave.views[view];
77
+ if (!tableView)
78
+ continue;
79
+ if (tableView.schema.group || tableView.schema.field)
80
+ continue;
81
+ tableView.schema = tableToSave.schema;
82
+ }
83
+ // update linked rows
84
+ try {
85
+ const linkResp = yield linkRows.updateLinks({
86
+ appId,
87
+ eventType: oldTable
88
+ ? linkRows.EventType.TABLE_UPDATED
89
+ : linkRows.EventType.TABLE_SAVE,
90
+ table: tableToSave,
91
+ oldTable: oldTable,
92
+ });
93
+ if (linkResp != null && linkResp._rev) {
94
+ tableToSave._rev = linkResp._rev;
95
+ }
96
+ }
97
+ catch (err) {
98
+ ctx.throw(400, err);
99
+ }
100
+ // don't perform any updates until relationships have been
101
+ // checked by the updateLinks function
102
+ const updatedRows = tableSaveFunctions.getUpdatedRows();
103
+ if (updatedRows && updatedRows.length !== 0) {
104
+ yield db.bulkDocs(updatedRows);
105
+ }
106
+ const result = yield db.put(tableToSave);
107
+ tableToSave._rev = result.rev;
108
+ tableToSave = yield tableSaveFunctions.after(tableToSave);
109
+ return tableToSave;
110
+ });
111
+ };
112
+ exports.destroy = function (ctx) {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ const appId = ctx.appId;
115
+ const db = new CouchDB(appId);
116
+ const tableToDelete = yield db.get(ctx.params.tableId);
117
+ // Delete all rows for that table
118
+ const rows = yield db.allDocs(getRowParams(ctx.params.tableId, null, {
119
+ include_docs: true,
120
+ }));
121
+ yield db.bulkDocs(rows.rows.map(row => (Object.assign(Object.assign({}, row.doc), { _deleted: true }))));
122
+ // update linked rows
123
+ yield linkRows.updateLinks({
124
+ appId,
125
+ eventType: linkRows.EventType.TABLE_DELETE,
126
+ table: tableToDelete,
127
+ });
128
+ // don't remove the table itself until very end
129
+ yield db.remove(tableToDelete);
130
+ // remove table search index
131
+ const currentIndexes = yield db.getIndexes();
132
+ const existingIndex = currentIndexes.indexes.find(existing => existing.name === `search:${ctx.params.tableId}`);
133
+ if (existingIndex) {
134
+ yield db.deleteIndex(existingIndex);
135
+ }
136
+ return tableToDelete;
137
+ });
138
+ };
@@ -277,4 +277,21 @@ exports.checkForViewUpdates = (db, table, rename, deletedColumns) => __awaiter(v
277
277
  }
278
278
  }
279
279
  });
280
+ exports.generateForeignKey = (column, relatedTable) => {
281
+ return `fk_${relatedTable.name}_${column.fieldName}`;
282
+ };
283
+ exports.generateJunctionTableName = (column, table, relatedTable) => {
284
+ return `jt_${table.name}_${relatedTable.name}_${column.name}_${column.fieldName}`;
285
+ };
286
+ exports.foreignKeyStructure = (keyName, meta = null) => {
287
+ const structure = {
288
+ type: FieldTypes.NUMBER,
289
+ constraints: {},
290
+ name: keyName,
291
+ };
292
+ if (meta) {
293
+ structure.meta = meta;
294
+ }
295
+ return structure;
296
+ };
280
297
  exports.TableSaveFunctions = TableSaveFunctions;
@@ -56,6 +56,9 @@ exports.DataSourceOperation = {
56
56
  READ: "READ",
57
57
  UPDATE: "UPDATE",
58
58
  DELETE: "DELETE",
59
+ CREATE_TABLE: "CREATE_TABLE",
60
+ UPDATE_TABLE: "UPDATE_TABLE",
61
+ DELETE_TABLE: "DELETE_TABLE",
59
62
  };
60
63
  exports.SortDirection = {
61
64
  ASCENDING: "ASCENDING",
@@ -140,5 +143,8 @@ exports.MetadataTypes = {
140
143
  AUTOMATION_TEST_INPUT: "automationTestInput",
141
144
  AUTOMATION_TEST_HISTORY: "automationTestHistory",
142
145
  };
146
+ exports.BuildSchemaErrors = {
147
+ NO_KEY: "no_key",
148
+ };
143
149
  // pass through the list from the auth/core lib
144
150
  exports.ObjectStoreBuckets = ObjectStoreBuckets;
@@ -7,6 +7,9 @@ var Operation;
7
7
  Operation["READ"] = "READ";
8
8
  Operation["UPDATE"] = "UPDATE";
9
9
  Operation["DELETE"] = "DELETE";
10
+ Operation["CREATE_TABLE"] = "CREATE_TABLE";
11
+ Operation["UPDATE_TABLE"] = "UPDATE_TABLE";
12
+ Operation["DELETE_TABLE"] = "DELETE_TABLE";
10
13
  })(Operation = exports.Operation || (exports.Operation = {}));
11
14
  var SortDirection;
12
15
  (function (SortDirection) {
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,11 +1,18 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  const knex_1 = require("knex");
4
- const BASE_LIMIT = 5000;
5
7
  const datasource_1 = require("../../definitions/datasource");
6
8
  const utils_1 = require("../utils");
9
+ const sqlTable_1 = __importDefault(require("./sqlTable"));
10
+ const BASE_LIMIT = 5000;
7
11
  function parseBody(body) {
8
12
  for (let [key, value] of Object.entries(body)) {
13
+ if (Array.isArray(value)) {
14
+ body[key] = JSON.stringify(value);
15
+ }
9
16
  if (typeof value !== "string") {
10
17
  continue;
11
18
  }
@@ -192,19 +199,12 @@ function buildDelete(knex, json, opts) {
192
199
  return query.delete().returning("*");
193
200
  }
194
201
  }
195
- class SqlQueryBuilder {
202
+ class SqlQueryBuilder extends sqlTable_1.default {
196
203
  // pass through client to get flavour of SQL
197
204
  constructor(client, limit = BASE_LIMIT) {
198
- this.sqlClient = client;
205
+ super(client);
199
206
  this.limit = limit;
200
207
  }
201
- /**
202
- * @param json the input JSON structure from which an SQL query will be built.
203
- * @return {string} the operation that was found in the JSON.
204
- */
205
- _operation(json) {
206
- return json.endpoint.operation;
207
- }
208
208
  /**
209
209
  * @param json The JSON query DSL which is to be converted to SQL.
210
210
  * @param opts extra options which are to be passed into the query builder, e.g. disableReturning
@@ -212,7 +212,8 @@ class SqlQueryBuilder {
212
212
  * @return {{ sql: string, bindings: object }} the query ready to be passed to the driver.
213
213
  */
214
214
  _query(json, opts = {}) {
215
- const client = knex_1.knex({ client: this.sqlClient });
215
+ const sqlClient = this.getSqlClient();
216
+ const client = knex_1.knex({ client: sqlClient });
216
217
  let query;
217
218
  switch (this._operation(json)) {
218
219
  case datasource_1.Operation.CREATE:
@@ -227,6 +228,10 @@ class SqlQueryBuilder {
227
228
  case datasource_1.Operation.DELETE:
228
229
  query = buildDelete(client, json, opts);
229
230
  break;
231
+ case datasource_1.Operation.CREATE_TABLE:
232
+ case datasource_1.Operation.UPDATE_TABLE:
233
+ case datasource_1.Operation.DELETE_TABLE:
234
+ return this._tableQuery(json);
230
235
  default:
231
236
  throw `Operation type is not supported by SQL query builder`;
232
237
  }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const knex_1 = require("knex");
4
+ const datasource_1 = require("../../definitions/datasource");
5
+ const utils_1 = require("../utils");
6
+ const { FieldTypes, RelationshipTypes } = require("../../constants");
7
+ function generateSchema(schema, table, tables, oldTable = null) {
8
+ let primaryKey = table && table.primary ? table.primary[0] : null;
9
+ const columns = Object.values(table.schema);
10
+ // all columns in a junction table will be meta
11
+ let metaCols = columns.filter(col => col.meta);
12
+ let isJunction = metaCols.length === columns.length;
13
+ // can't change primary once its set for now
14
+ if (primaryKey && !oldTable && !isJunction) {
15
+ schema.increments(primaryKey).primary();
16
+ }
17
+ else if (!oldTable && isJunction) {
18
+ schema.primary(metaCols.map(col => col.name));
19
+ }
20
+ // check if any columns need added
21
+ const foreignKeys = Object.values(table.schema).map(col => col.foreignKey);
22
+ for (let [key, column] of Object.entries(table.schema)) {
23
+ // skip things that are already correct
24
+ const oldColumn = oldTable ? oldTable.schema[key] : null;
25
+ if ((oldColumn && oldColumn.type === column.type) || (primaryKey === key && !isJunction)) {
26
+ continue;
27
+ }
28
+ switch (column.type) {
29
+ case FieldTypes.STRING:
30
+ case FieldTypes.OPTIONS:
31
+ case FieldTypes.LONGFORM:
32
+ schema.string(key);
33
+ break;
34
+ case FieldTypes.NUMBER:
35
+ // if meta is specified then this is a junction table entry
36
+ if (column.meta && column.meta.toKey && column.meta.toTable) {
37
+ const { toKey, toTable } = column.meta;
38
+ schema.integer(key).unsigned();
39
+ schema.foreign(key).references(`${toTable}.${toKey}`);
40
+ }
41
+ else if (foreignKeys.indexOf(key) === -1) {
42
+ schema.float(key);
43
+ }
44
+ break;
45
+ case FieldTypes.BOOLEAN:
46
+ schema.boolean(key);
47
+ break;
48
+ case FieldTypes.DATETIME:
49
+ schema.datetime(key);
50
+ break;
51
+ case FieldTypes.ARRAY:
52
+ schema.json(key);
53
+ break;
54
+ case FieldTypes.LINK:
55
+ // this side of the relationship doesn't need any SQL work
56
+ if (column.relationshipType !== RelationshipTypes.MANY_TO_ONE &&
57
+ column.relationshipType !== RelationshipTypes.MANY_TO_MANY) {
58
+ if (!column.foreignKey || !column.tableId) {
59
+ throw "Invalid relationship schema";
60
+ }
61
+ const { tableName } = utils_1.breakExternalTableId(column.tableId);
62
+ // @ts-ignore
63
+ const relatedTable = tables[tableName];
64
+ if (!relatedTable) {
65
+ throw "Referenced table doesn't exist";
66
+ }
67
+ schema.integer(column.foreignKey).unsigned();
68
+ schema.foreign(column.foreignKey).references(`${tableName}.${relatedTable.primary[0]}`);
69
+ }
70
+ break;
71
+ }
72
+ }
73
+ // need to check if any columns have been deleted
74
+ if (oldTable) {
75
+ const deletedColumns = Object.entries(oldTable.schema)
76
+ .filter(([key, schema]) => schema.type !== FieldTypes.LINK && table.schema[key] == null)
77
+ .map(([key]) => key);
78
+ deletedColumns.forEach(key => {
79
+ if (oldTable.constrained && oldTable.constrained.indexOf(key) !== -1) {
80
+ schema.dropForeign(key);
81
+ }
82
+ schema.dropColumn(key);
83
+ });
84
+ }
85
+ return schema;
86
+ }
87
+ function buildCreateTable(knex, table, tables) {
88
+ return knex.schema.createTable(table.name, schema => {
89
+ generateSchema(schema, table, tables);
90
+ });
91
+ }
92
+ function buildUpdateTable(knex, table, tables, oldTable) {
93
+ return knex.schema.alterTable(table.name, schema => {
94
+ generateSchema(schema, table, tables, oldTable);
95
+ });
96
+ }
97
+ function buildDeleteTable(knex, table) {
98
+ return knex.schema.dropTable(table.name);
99
+ }
100
+ class SqlTableQueryBuilder {
101
+ // pass through client to get flavour of SQL
102
+ constructor(client) {
103
+ this.sqlClient = client;
104
+ }
105
+ getSqlClient() {
106
+ return this.sqlClient;
107
+ }
108
+ /**
109
+ * @param json the input JSON structure from which an SQL query will be built.
110
+ * @return {string} the operation that was found in the JSON.
111
+ */
112
+ _operation(json) {
113
+ return json.endpoint.operation;
114
+ }
115
+ _tableQuery(json) {
116
+ const client = knex_1.knex({ client: this.sqlClient });
117
+ let query;
118
+ if (!json.table || !json.meta || !json.meta.tables) {
119
+ throw "Cannot execute without table being specified";
120
+ }
121
+ switch (this._operation(json)) {
122
+ case datasource_1.Operation.CREATE_TABLE:
123
+ query = buildCreateTable(client, json.table, json.meta.tables);
124
+ break;
125
+ case datasource_1.Operation.UPDATE_TABLE:
126
+ if (!json.meta || !json.meta.table) {
127
+ throw "Must specify old table for update";
128
+ }
129
+ query = buildUpdateTable(client, json.table, json.meta.tables, json.meta.table);
130
+ break;
131
+ case datasource_1.Operation.DELETE_TABLE:
132
+ query = buildDeleteTable(client, json.table);
133
+ break;
134
+ default:
135
+ throw "Table operation is of unknown type";
136
+ }
137
+ return query.toSQL();
138
+ }
139
+ }
140
+ exports.default = SqlTableQueryBuilder;
141
+ module.exports = SqlTableQueryBuilder;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ var DatasourceUtils;
13
+ (function (DatasourceUtils) {
14
+ const { integrations } = require("../index");
15
+ function makeExternalQuery(datasource, json) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const Integration = integrations[datasource.source];
18
+ // query is the opinionated function
19
+ if (Integration.prototype.query) {
20
+ const integration = new Integration(datasource.config);
21
+ return integration.query(json);
22
+ }
23
+ else {
24
+ throw "Datasource does not support query.";
25
+ }
26
+ });
27
+ }
28
+ DatasourceUtils.makeExternalQuery = makeExternalQuery;
29
+ module.exports.makeExternalQuery = makeExternalQuery;
30
+ })(DatasourceUtils || (DatasourceUtils = {}));
@@ -15,7 +15,7 @@ var MySQLModule;
15
15
  (function (MySQLModule) {
16
16
  const mysql = require("mysql2");
17
17
  const Sql = require("./base/sql");
18
- const { buildExternalTableId, convertType, copyExistingPropsOver, } = require("./utils");
18
+ const { buildExternalTableId, convertType, finaliseExternalTables, } = require("./utils");
19
19
  const { FieldTypes } = require("../constants");
20
20
  const TYPE_MAP = {
21
21
  text: FieldTypes.LONGFORM,
@@ -112,6 +112,8 @@ var MySQLModule;
112
112
  class MySQLIntegration extends Sql {
113
113
  constructor(config) {
114
114
  super("mysql");
115
+ this.tables = {};
116
+ this.schemaErrors = {};
115
117
  this.config = config;
116
118
  if (config.ssl && Object.keys(config.ssl).length === 0) {
117
119
  delete config.ssl;
@@ -148,10 +150,6 @@ var MySQLModule;
148
150
  constraints,
149
151
  };
150
152
  }
151
- // for now just default to first column
152
- if (primaryKeys.length === 0) {
153
- primaryKeys.push(descResp[0].Field);
154
- }
155
153
  if (!tables[tableName]) {
156
154
  tables[tableName] = {
157
155
  _id: buildExternalTableId(datasourceId, tableName),
@@ -160,10 +158,11 @@ var MySQLModule;
160
158
  schema,
161
159
  };
162
160
  }
163
- copyExistingPropsOver(tableName, tables, entities);
164
161
  }
165
162
  this.client.end();
166
- this.tables = tables;
163
+ const final = finaliseExternalTables(tables, entities);
164
+ this.tables = final.tables;
165
+ this.schemaErrors = final.errors;
167
166
  });
168
167
  }
169
168
  create(query) {
@@ -225,6 +224,13 @@ var MySQLModule;
225
224
  const operation = this._operation(json);
226
225
  this.client.connect();
227
226
  const input = this._query(json, { disableReturning: true });
227
+ if (Array.isArray(input)) {
228
+ const responses = [];
229
+ for (let query of input) {
230
+ responses.push(yield internalQuery(this.client, query, false));
231
+ }
232
+ return responses;
233
+ }
228
234
  let row;
229
235
  // need to manage returning, a feature mySQL can't do
230
236
  if (operation === operation.DELETE) {
@@ -16,7 +16,7 @@ var PostgresModule;
16
16
  const { Pool } = require("pg");
17
17
  const Sql = require("./base/sql");
18
18
  const { FieldTypes } = require("../constants");
19
- const { buildExternalTableId, convertType, copyExistingPropsOver, } = require("./utils");
19
+ const { buildExternalTableId, convertType, finaliseExternalTables, } = require("./utils");
20
20
  const { escapeDangerousCharacters } = require("../utilities");
21
21
  const JSON_REGEX = /'{.*}'::json/s;
22
22
  const SCHEMA = {
@@ -121,6 +121,8 @@ var PostgresModule;
121
121
  class PostgresIntegration extends Sql {
122
122
  constructor(config) {
123
123
  super("pg");
124
+ this.tables = {};
125
+ this.schemaErrors = {};
124
126
  this.COLUMNS_SQL = "select * from information_schema.columns where not table_schema = 'information_schema' and not table_schema = 'pg_catalog'";
125
127
  this.PRIMARY_KEYS_SQL = `
126
128
  select tc.table_schema, tc.table_name, kc.column_name as primary_key
@@ -177,7 +179,7 @@ var PostgresModule;
177
179
  if (!tables[tableName] || !tables[tableName].schema) {
178
180
  tables[tableName] = {
179
181
  _id: buildExternalTableId(datasourceId, tableName),
180
- primary: tableKeys[tableName] || ["id"],
182
+ primary: tableKeys[tableName] || [],
181
183
  name: tableName,
182
184
  schema: {},
183
185
  };
@@ -196,10 +198,9 @@ var PostgresModule;
196
198
  type,
197
199
  };
198
200
  }
199
- for (let tableName of Object.keys(tables)) {
200
- copyExistingPropsOver(tableName, tables, entities);
201
- }
202
- this.tables = tables;
201
+ const final = finaliseExternalTables(tables, entities);
202
+ this.tables = final.tables;
203
+ this.schemaErrors = final.errors;
203
204
  });
204
205
  }
205
206
  create(query) {
@@ -230,8 +231,17 @@ var PostgresModule;
230
231
  return __awaiter(this, void 0, void 0, function* () {
231
232
  const operation = this._operation(json).toLowerCase();
232
233
  const input = this._query(json);
233
- const response = yield internalQuery(this.client, input);
234
- return response.rows.length ? response.rows : [{ [operation]: true }];
234
+ if (Array.isArray(input)) {
235
+ const responses = [];
236
+ for (let query of input) {
237
+ responses.push(yield internalQuery(this.client, query));
238
+ }
239
+ return responses;
240
+ }
241
+ else {
242
+ const response = yield internalQuery(this.client, input);
243
+ return response.rows.length ? response.rows : [{ [operation]: true }];
244
+ }
235
245
  });
236
246
  }
237
247
  }
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.copyExistingPropsOver = exports.isIsoDateString = exports.isSQL = exports.getSqlQuery = exports.convertType = exports.breakRowIdField = exports.convertRowId = exports.isRowId = exports.generateRowIdField = exports.breakExternalTableId = exports.buildExternalTableId = exports.isExternalTable = void 0;
3
+ exports.finaliseExternalTables = exports.isIsoDateString = exports.isSQL = exports.getSqlQuery = exports.convertType = exports.breakRowIdField = exports.convertRowId = exports.isRowId = exports.generateRowIdField = exports.breakExternalTableId = exports.buildExternalTableId = exports.isExternalTable = void 0;
4
4
  const datasource_1 = require("../definitions/datasource");
5
5
  const { DocumentTypes, SEPARATOR } = require("../db/utils");
6
- const { FieldTypes } = require("../constants");
6
+ const { FieldTypes, BuildSchemaErrors } = require("../constants");
7
7
  const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`;
8
8
  const ROW_ID_REGEX = /^\[.*]$/g;
9
9
  function isExternalTable(tableId) {
@@ -101,10 +101,10 @@ function isIsoDateString(str) {
101
101
  }
102
102
  exports.isIsoDateString = isIsoDateString;
103
103
  // add the existing relationships from the entities if they exist, to prevent them from being overridden
104
- function copyExistingPropsOver(tableName, tables, entities) {
104
+ function copyExistingPropsOver(tableName, table, entities) {
105
105
  if (entities && entities[tableName]) {
106
106
  if (entities[tableName].primaryDisplay) {
107
- tables[tableName].primaryDisplay = entities[tableName].primaryDisplay;
107
+ table.primaryDisplay = entities[tableName].primaryDisplay;
108
108
  }
109
109
  const existingTableSchema = entities[tableName].schema;
110
110
  for (let key in existingTableSchema) {
@@ -112,9 +112,24 @@ function copyExistingPropsOver(tableName, tables, entities) {
112
112
  continue;
113
113
  }
114
114
  if (existingTableSchema[key].type === "link") {
115
- tables[tableName].schema[key] = existingTableSchema[key];
115
+ table.schema[key] = existingTableSchema[key];
116
116
  }
117
117
  }
118
118
  }
119
+ return table;
119
120
  }
120
- exports.copyExistingPropsOver = copyExistingPropsOver;
121
+ function finaliseExternalTables(tables, entities) {
122
+ const finalTables = {};
123
+ const errors = {};
124
+ for (let [name, table] of Object.entries(tables)) {
125
+ // make sure every table has a key
126
+ if (table.primary == null || table.primary.length === 0) {
127
+ errors[name] = BuildSchemaErrors.NO_KEY;
128
+ continue;
129
+ }
130
+ // make sure all previous props have been added back
131
+ finalTables[name] = copyExistingPropsOver(name, table, entities);
132
+ }
133
+ return { tables: finalTables, errors };
134
+ }
135
+ exports.finaliseExternalTables = finaliseExternalTables;
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "0.9.173",
4
+ "version": "0.9.176-alpha.1",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.js",
7
7
  "repository": {
@@ -68,9 +68,9 @@
68
68
  "author": "Budibase",
69
69
  "license": "AGPL-3.0-or-later",
70
70
  "dependencies": {
71
- "@budibase/auth": "^0.9.173",
72
- "@budibase/client": "^0.9.173",
73
- "@budibase/string-templates": "^0.9.173",
71
+ "@budibase/auth": "^0.9.176-alpha.1",
72
+ "@budibase/client": "^0.9.176-alpha.1",
73
+ "@budibase/string-templates": "^0.9.176-alpha.1",
74
74
  "@elastic/elasticsearch": "7.10.0",
75
75
  "@koa/router": "8.0.0",
76
76
  "@sendgrid/mail": "7.1.1",
@@ -289,7 +289,8 @@ class TestConfiguration {
289
289
  createDatasource(config = null) {
290
290
  return __awaiter(this, void 0, void 0, function* () {
291
291
  config = config || basicDatasource();
292
- this.datasource = yield this._req(config, null, controllers.datasource.save);
292
+ const response = yield this._req(config, null, controllers.datasource.save);
293
+ this.datasource = response.datasource;
293
294
  return this.datasource;
294
295
  });
295
296
  }