@budibase/server 2.3.18-alpha.3 → 2.3.18-alpha.30

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 (93) hide show
  1. package/__mocks__/node-fetch.ts +3 -0
  2. package/builder/assets/blankScreenPreview.72634dd1.png +0 -0
  3. package/builder/assets/{index.9f78787d.js → index.11e16372.js} +429 -414
  4. package/builder/assets/index.b24b9dea.css +6 -0
  5. package/builder/assets/listScreenPreview.599c0aae.png +0 -0
  6. package/builder/index.html +2 -2
  7. package/dist/api/controllers/automation.js +11 -2
  8. package/dist/api/controllers/cloud.js +2 -2
  9. package/dist/api/controllers/row/ExternalRequest.js +49 -24
  10. package/dist/api/controllers/row/external.js +1 -1
  11. package/dist/api/controllers/row/internalSearch.js +6 -450
  12. package/dist/api/controllers/row/utils.js +1 -3
  13. package/dist/api/routes/automation.js +1 -1
  14. package/dist/api/routes/public/applications.js +7 -7
  15. package/dist/api/routes/public/queries.js +2 -2
  16. package/dist/api/routes/public/rows.js +5 -5
  17. package/dist/api/routes/public/tables.js +5 -5
  18. package/dist/api/routes/public/users.js +5 -5
  19. package/dist/app.js +2 -0
  20. package/dist/db/index.js +25 -2
  21. package/dist/db/utils.js +2 -5
  22. package/dist/db/views/staticViews.js +2 -1
  23. package/dist/integrations/base/sql.js +4 -8
  24. package/dist/integrations/googlesheets.js +17 -20
  25. package/dist/middleware/authorized.js +5 -3
  26. package/dist/middleware/builder.js +6 -3
  27. package/dist/migrations/functions/backfill/global/configs.js +10 -4
  28. package/dist/migrations/tests/helpers.js +1 -1
  29. package/dist/migrations/tests/structures.js +1 -1
  30. package/dist/package.json +9 -8
  31. package/dist/sdk/app/backups/constants.js +2 -1
  32. package/dist/sdk/app/backups/exports.js +12 -5
  33. package/dist/sdk/app/rows/attachments.js +1 -1
  34. package/dist/startup.js +3 -0
  35. package/dist/tsconfig.build.tsbuildinfo +1 -1
  36. package/jest.config.ts +1 -0
  37. package/package.json +10 -9
  38. package/scripts/test.sh +12 -0
  39. package/specs/{generate.js → generate.ts} +7 -9
  40. package/specs/openapi.json +24 -24
  41. package/specs/openapi.yaml +24 -24
  42. package/specs/{parameters.js → parameters.ts} +6 -6
  43. package/specs/resources/{application.js → application.ts} +4 -4
  44. package/specs/resources/{index.js → index.ts} +8 -8
  45. package/specs/resources/{misc.js → misc.ts} +3 -3
  46. package/specs/resources/{query.js → query.ts} +4 -4
  47. package/specs/resources/{row.js → row.ts} +3 -4
  48. package/specs/resources/{table.js → table.ts} +5 -5
  49. package/specs/resources/{user.js → user.ts} +3 -3
  50. package/specs/resources/utils/Resource.ts +39 -0
  51. package/specs/resources/utils/{index.js → index.ts} +1 -1
  52. package/specs/{security.js → security.ts} +1 -1
  53. package/src/api/controllers/automation.ts +13 -2
  54. package/src/api/controllers/cloud.ts +2 -2
  55. package/src/api/controllers/row/ExternalRequest.ts +95 -28
  56. package/src/api/controllers/row/external.ts +1 -1
  57. package/src/api/controllers/row/internalSearch.ts +11 -524
  58. package/src/api/controllers/row/utils.ts +1 -2
  59. package/src/api/routes/automation.ts +1 -1
  60. package/src/api/routes/public/applications.ts +7 -7
  61. package/src/api/routes/public/queries.ts +2 -2
  62. package/src/api/routes/public/rows.ts +5 -5
  63. package/src/api/routes/public/tables.ts +5 -5
  64. package/src/api/routes/public/tests/{compare.spec.js → compare.spec.ts} +44 -25
  65. package/src/api/routes/public/users.ts +5 -5
  66. package/src/api/routes/tests/{cloud.seq.spec.ts → cloud.spec.ts} +13 -20
  67. package/src/api/routes/tests/utilities/TestFunctions.ts +1 -2
  68. package/src/app.ts +2 -0
  69. package/src/db/index.ts +2 -2
  70. package/src/db/utils.ts +0 -4
  71. package/src/db/views/staticViews.ts +3 -3
  72. package/src/definitions/openapi.ts +449 -63
  73. package/src/integration-test/postgres.spec.ts +351 -81
  74. package/src/integrations/base/sql.ts +4 -8
  75. package/src/integrations/googlesheets.ts +21 -22
  76. package/src/integrations/tests/googlesheets.spec.ts +122 -0
  77. package/src/middleware/authorized.ts +6 -4
  78. package/src/middleware/builder.ts +8 -3
  79. package/src/migrations/functions/backfill/global/configs.ts +15 -9
  80. package/src/migrations/functions/tests/userEmailViewCasing.spec.js +3 -4
  81. package/src/migrations/tests/helpers.ts +2 -2
  82. package/src/migrations/tests/structures.ts +1 -0
  83. package/src/sdk/app/backups/constants.ts +1 -0
  84. package/src/sdk/app/backups/exports.ts +24 -8
  85. package/src/sdk/app/rows/attachments.ts +1 -1
  86. package/src/startup.ts +4 -1
  87. package/src/tests/jestEnv.ts +1 -0
  88. package/src/tests/utilities/TestConfiguration.ts +42 -30
  89. package/src/tests/utilities/structures.ts +0 -2
  90. package/builder/assets/index.7e76c039.css +0 -6
  91. package/dist/integrations/base/utils.js +0 -16
  92. package/specs/resources/utils/Resource.js +0 -26
  93. package/src/integrations/base/utils.ts +0 -12
@@ -10,8 +10,8 @@
10
10
  href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap"
11
11
  rel="stylesheet"
12
12
  />
13
- <script type="module" crossorigin src="/builder/assets/index.9f78787d.js"></script>
14
- <link rel="stylesheet" href="/builder/assets/index.7e76c039.css">
13
+ <script type="module" crossorigin src="/builder/assets/index.11e16372.js"></script>
14
+ <link rel="stylesheet" href="/builder/assets/index.b24b9dea.css">
15
15
  </head>
16
16
  <body id="app">
17
17
 
@@ -85,9 +85,13 @@ function create(ctx) {
85
85
  automation.appId = ctx.appId;
86
86
  // call through to update if already exists
87
87
  if (automation._id && automation._rev) {
88
- return update(ctx);
88
+ yield update(ctx);
89
+ return;
90
+ }
91
+ // Respect existing IDs if recreating a deleted automation
92
+ if (!automation._id) {
93
+ automation._id = (0, utils_1.generateAutomationID)();
89
94
  }
90
- automation._id = (0, utils_1.generateAutomationID)();
91
95
  automation.type = "automation";
92
96
  automation = cleanAutomationInputs(automation);
93
97
  automation = yield (0, utils_2.checkForWebhooks)({
@@ -137,6 +141,11 @@ function update(ctx) {
137
141
  const db = backend_core_1.context.getAppDB();
138
142
  let automation = ctx.request.body;
139
143
  automation.appId = ctx.appId;
144
+ // Call through to create if it doesn't exist
145
+ if (!automation._id || !automation._rev) {
146
+ yield create(ctx);
147
+ return;
148
+ }
140
149
  const oldAutomation = yield db.get(automation._id);
141
150
  automation = cleanAutomationInputs(automation);
142
151
  automation = yield (0, utils_2.checkForWebhooks)({
@@ -71,7 +71,7 @@ function exportApps(ctx) {
71
71
  exports.exportApps = exportApps;
72
72
  function checkHasBeenImported() {
73
73
  return __awaiter(this, void 0, void 0, function* () {
74
- if (!environment_1.default.SELF_HOSTED || environment_1.default.MULTI_TENANCY) {
74
+ if (!environment_1.default.SELF_HOSTED) {
75
75
  return true;
76
76
  }
77
77
  const apps = yield backend_core_1.db.getAllApps({ all: true });
@@ -88,7 +88,7 @@ function hasBeenImported(ctx) {
88
88
  exports.hasBeenImported = hasBeenImported;
89
89
  function importApps(ctx) {
90
90
  return __awaiter(this, void 0, void 0, function* () {
91
- if (!environment_1.default.SELF_HOSTED || environment_1.default.MULTI_TENANCY) {
91
+ if (!environment_1.default.SELF_HOSTED) {
92
92
  ctx.throw(400, "Importing only allowed in self hosted environments.");
93
93
  }
94
94
  const beenImported = yield checkHasBeenImported();
@@ -32,7 +32,7 @@ const utils_3 = require("../../../integrations/utils");
32
32
  const string_templates_1 = require("@budibase/string-templates");
33
33
  const fp_1 = require("lodash/fp");
34
34
  const rowProcessor_1 = require("../../../utilities/rowProcessor");
35
- const utils_4 = require("./utils");
35
+ const backend_core_1 = require("@budibase/backend-core");
36
36
  const sdk_1 = __importDefault(require("../../../sdk"));
37
37
  function buildFilters(id, filters, table) {
38
38
  const primary = table.primary;
@@ -43,7 +43,7 @@ function buildFilters(id, filters, table) {
43
43
  let prefix = 1;
44
44
  for (let operator of Object.values(filters)) {
45
45
  for (let field of Object.keys(operator || {})) {
46
- if ((0, utils_4.removeKeyNumbering)(field) === "_id") {
46
+ if (backend_core_1.db.removeKeyNumbering(field) === "_id") {
47
47
  if (primary) {
48
48
  const parts = (0, utils_1.breakRowIdField)(operator[field]);
49
49
  for (let field of primary) {
@@ -119,7 +119,7 @@ function cleanupConfig(config, table) {
119
119
  }
120
120
  return config;
121
121
  }
122
- function generateIdForRow(row, table) {
122
+ function generateIdForRow(row, table, isLinked = false) {
123
123
  const primary = table.primary;
124
124
  if (!row || !primary) {
125
125
  return "";
@@ -127,8 +127,12 @@ function generateIdForRow(row, table) {
127
127
  // build id array
128
128
  let idParts = [];
129
129
  for (let field of primary) {
130
- // need to handle table name + field or just field, depending on if relationships used
131
- const fieldValue = row[`${table.name}.${field}`] || row[field];
130
+ let fieldValue = extractFieldValue({
131
+ row,
132
+ tableName: table.name,
133
+ fieldName: field,
134
+ isLinked,
135
+ });
132
136
  if (fieldValue) {
133
137
  idParts.push(fieldValue);
134
138
  }
@@ -149,18 +153,31 @@ function getEndpoint(tableId, operation) {
149
153
  operation,
150
154
  };
151
155
  }
152
- function basicProcessing(row, table) {
156
+ // need to handle table name + field or just field, depending on if relationships used
157
+ function extractFieldValue({ row, tableName, fieldName, isLinked, }) {
158
+ let value = row[`${tableName}.${fieldName}`];
159
+ if (value == null && !isLinked) {
160
+ value = row[fieldName];
161
+ }
162
+ return value;
163
+ }
164
+ function basicProcessing({ row, table, isLinked, }) {
153
165
  const thisRow = {};
154
166
  // filter the row down to what is actually the row (not joined)
155
- for (let fieldName of Object.keys(table.schema)) {
156
- const pathValue = row[`${table.name}.${fieldName}`];
157
- const value = pathValue != null ? pathValue : row[fieldName];
167
+ for (let field of Object.values(table.schema)) {
168
+ const fieldName = field.name;
169
+ const value = extractFieldValue({
170
+ row,
171
+ tableName: table.name,
172
+ fieldName,
173
+ isLinked,
174
+ });
158
175
  // all responses include "select col as table.col" so that overlaps are handled
159
176
  if (value != null) {
160
177
  thisRow[fieldName] = value;
161
178
  }
162
179
  }
163
- thisRow._id = generateIdForRow(row, table);
180
+ thisRow._id = generateIdForRow(row, table, isLinked);
164
181
  thisRow.tableId = table._id;
165
182
  thisRow._rev = "rev";
166
183
  return (0, rowProcessor_1.processFormulas)(table, thisRow);
@@ -254,7 +271,7 @@ class ExternalRequest {
254
271
  // we're not inserting a doc, will be a bunch of update calls
255
272
  const otherKey = field.throughFrom || linkTablePrimary;
256
273
  const thisKey = field.throughTo || tablePrimary;
257
- row[key].map((relationship) => {
274
+ row[key].forEach((relationship) => {
258
275
  manyRelationships.push({
259
276
  tableId: field.through || field.tableId,
260
277
  isUpdate: false,
@@ -270,7 +287,7 @@ class ExternalRequest {
270
287
  const thisKey = "id";
271
288
  // @ts-ignore
272
289
  const otherKey = field.fieldName;
273
- row[key].map((relationship) => {
290
+ row[key].forEach((relationship) => {
274
291
  manyRelationships.push({
275
292
  tableId: field.tableId,
276
293
  isUpdate: true,
@@ -328,7 +345,7 @@ class ExternalRequest {
328
345
  ((_a = row[fromColumn]) === null || _a === void 0 ? void 0 : _a.toString()) !== ((_b = row[toColumn]) === null || _b === void 0 ? void 0 : _b.toString())) {
329
346
  continue;
330
347
  }
331
- let linked = basicProcessing(row, linkedTable);
348
+ let linked = basicProcessing({ row, table: linkedTable, isLinked: true });
332
349
  if (!linked._id) {
333
350
  continue;
334
351
  }
@@ -362,7 +379,7 @@ class ExternalRequest {
362
379
  finalRows = this.updateRelationshipColumns(table, row, finalRows, relationships);
363
380
  continue;
364
381
  }
365
- const thisRow = fixArrayTypes(basicProcessing(row, table), table);
382
+ const thisRow = fixArrayTypes(basicProcessing({ row, table, isLinked: false }), table);
366
383
  if (thisRow._id == null) {
367
384
  throw "Unable to generate row ID for SQL rows";
368
385
  }
@@ -486,16 +503,25 @@ class ExternalRequest {
486
503
  const { key, tableId, isUpdate, id } = relationship, rest = __rest(relationship, ["key", "tableId", "isUpdate", "id"]);
487
504
  const body = (0, string_templates_1.processObjectSync)(rest, row, {});
488
505
  const linkTable = this.getTable(tableId);
489
- // @ts-ignore
490
- const linkPrimary = linkTable === null || linkTable === void 0 ? void 0 : linkTable.primary[0];
506
+ const relationshipPrimary = (linkTable === null || linkTable === void 0 ? void 0 : linkTable.primary) || [];
507
+ const linkPrimary = relationshipPrimary[0];
491
508
  if (!linkTable || !linkPrimary) {
492
509
  return;
493
510
  }
511
+ const linkSecondary = relationshipPrimary[1];
494
512
  const rows = ((_a = related[key]) === null || _a === void 0 ? void 0 : _a.rows) || [];
495
- const found = rows.find((row) => row[linkPrimary] === relationship.id ||
496
- row[linkPrimary] === (body === null || body === void 0 ? void 0 : body[linkPrimary]));
513
+ function relationshipMatchPredicate({ row, linkPrimary, linkSecondary, }) {
514
+ const matchesPrimaryLink = row[linkPrimary] === relationship.id ||
515
+ row[linkPrimary] === (body === null || body === void 0 ? void 0 : body[linkPrimary]);
516
+ if (!matchesPrimaryLink || !linkSecondary) {
517
+ return matchesPrimaryLink;
518
+ }
519
+ const matchesSecondayLink = row[linkSecondary] === (body === null || body === void 0 ? void 0 : body[linkSecondary]);
520
+ return matchesPrimaryLink && matchesSecondayLink;
521
+ }
522
+ const existingRelationship = rows.find((row) => relationshipMatchPredicate({ row, linkPrimary, linkSecondary }));
497
523
  const operation = isUpdate ? types_1.Operation.UPDATE : types_1.Operation.CREATE;
498
- if (!found) {
524
+ if (!existingRelationship) {
499
525
  promises.push((0, utils_2.getDatasourceAndQuery)({
500
526
  endpoint: getEndpoint(tableId, operation),
501
527
  // if we're doing many relationships then we're writing, only one response
@@ -505,7 +531,7 @@ class ExternalRequest {
505
531
  }
506
532
  else {
507
533
  // remove the relationship from cache so it isn't adjusted again
508
- rows.splice(rows.indexOf(found), 1);
534
+ rows.splice(rows.indexOf(existingRelationship), 1);
509
535
  }
510
536
  }
511
537
  // finally cleanup anything that needs to be removed
@@ -540,7 +566,7 @@ class ExternalRequest {
540
566
  * Creating the specific list of fields that we desire, and excluding the ones that are no use to us
541
567
  * is more performant and has the added benefit of protecting against this scenario.
542
568
  */
543
- buildFields(table, includeRelations = types_1.IncludeRelationship.INCLUDE) {
569
+ buildFields(table, includeRelations) {
544
570
  function extractRealFields(table, existing = []) {
545
571
  return Object.entries(table.schema)
546
572
  .filter(column => column[1].type !== constants_1.FieldTypes.LINK &&
@@ -594,6 +620,7 @@ class ExternalRequest {
594
620
  }
595
621
  filters = buildFilters(id, filters || {}, table);
596
622
  const relationships = this.buildRelationships(table);
623
+ const includeSqlRelationships = config.includeSqlRelationships === types_1.IncludeRelationship.INCLUDE;
597
624
  // clean up row on ingress using schema
598
625
  const processed = this.inputProcessing(row, table);
599
626
  row = processed.row;
@@ -609,9 +636,7 @@ class ExternalRequest {
609
636
  },
610
637
  resource: {
611
638
  // have to specify the fields to avoid column overlap (for SQL)
612
- fields: isSql
613
- ? this.buildFields(table, config.includeSqlRelationships)
614
- : [],
639
+ fields: isSql ? this.buildFields(table, includeSqlRelationships) : [],
615
640
  },
616
641
  filters,
617
642
  sort,
@@ -86,7 +86,7 @@ function patch(ctx) {
86
86
  return handleRequest(types_1.Operation.UPDATE, tableId, {
87
87
  id: (0, utils_1.breakRowIdField)(id),
88
88
  row: inputs,
89
- includeSqlRelationships: types_1.IncludeRelationship.EXCLUDE,
89
+ includeSqlRelationships: types_1.IncludeRelationship.INCLUDE,
90
90
  });
91
91
  });
92
92
  }