@budibase/server 2.6.17 → 2.6.19-alpha.0

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 (62) hide show
  1. package/builder/assets/{index.86c992bf.css → index.07382a47.css} +2 -2
  2. package/builder/assets/{index.a40dcadd.js → index.b9eeb2a8.js} +307 -315
  3. package/builder/index.html +2 -2
  4. package/dist/api/controllers/datasource.js +70 -39
  5. package/dist/api/controllers/integration.js +2 -2
  6. package/dist/api/routes/datasource.js +1 -0
  7. package/dist/automations/steps/make.js +19 -5
  8. package/dist/automations/steps/zapier.js +19 -6
  9. package/dist/automations/utils.js +13 -7
  10. package/dist/db/dynamoClient.js +1 -1
  11. package/dist/integrations/airtable.js +28 -2
  12. package/dist/integrations/arangodb.js +19 -3
  13. package/dist/integrations/couchdb.js +16 -1
  14. package/dist/integrations/dynamodb.js +16 -0
  15. package/dist/integrations/elasticsearch.js +15 -0
  16. package/dist/integrations/firebase.js +15 -0
  17. package/dist/integrations/googlesheets.js +30 -1
  18. package/dist/integrations/index.js +5 -2
  19. package/dist/integrations/microsoftSqlServer.js +16 -0
  20. package/dist/integrations/mongodb.js +16 -0
  21. package/dist/integrations/mysql.js +21 -5
  22. package/dist/integrations/oracle.js +29 -0
  23. package/dist/integrations/postgres.js +26 -7
  24. package/dist/integrations/redis.js +20 -1
  25. package/dist/integrations/s3.js +23 -4
  26. package/dist/integrations/snowflake.js +15 -0
  27. package/dist/migrations/functions/backfill/app/queries.js +1 -2
  28. package/dist/sdk/app/datasources/datasources.js +10 -3
  29. package/dist/tsconfig.build.tsbuildinfo +1 -1
  30. package/jest.config.ts +3 -3
  31. package/nodemon.json +7 -3
  32. package/package.json +10 -9
  33. package/src/api/controllers/datasource.ts +88 -49
  34. package/src/api/controllers/integration.ts +3 -3
  35. package/src/api/routes/datasource.ts +5 -0
  36. package/src/automations/steps/make.ts +18 -1
  37. package/src/automations/steps/zapier.ts +18 -1
  38. package/src/automations/tests/make.spec.ts +54 -0
  39. package/src/automations/tests/zapier.spec.ts +56 -0
  40. package/src/automations/utils.ts +13 -7
  41. package/src/db/dynamoClient.ts +1 -1
  42. package/src/integration-test/postgres.spec.ts +0 -1
  43. package/src/integrations/airtable.ts +31 -4
  44. package/src/integrations/arangodb.ts +18 -2
  45. package/src/integrations/couchdb.ts +18 -4
  46. package/src/integrations/dynamodb.ts +34 -5
  47. package/src/integrations/elasticsearch.ts +16 -1
  48. package/src/integrations/firebase.ts +15 -0
  49. package/src/integrations/googlesheets.ts +31 -2
  50. package/src/integrations/index.ts +12 -7
  51. package/src/integrations/microsoftSqlServer.ts +16 -0
  52. package/src/integrations/mongodb.ts +16 -0
  53. package/src/integrations/mysql.ts +27 -16
  54. package/src/integrations/oracle.ts +28 -6
  55. package/src/integrations/postgres.ts +21 -3
  56. package/src/integrations/redis.ts +26 -3
  57. package/src/integrations/s3.ts +19 -3
  58. package/src/integrations/snowflake.ts +20 -1
  59. package/src/migrations/functions/backfill/app/queries.ts +1 -1
  60. package/src/sdk/app/datasources/datasources.ts +7 -1
  61. package/tsconfig.json +1 -1
  62. package/src/automations/tests/zapier.spec.js +0 -27
@@ -8,8 +8,8 @@
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" />
9
9
  <link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap"
10
10
  rel="stylesheet" />
11
- <script type="module" crossorigin src="/builder/assets/index.a40dcadd.js"></script>
12
- <link rel="stylesheet" href="/builder/assets/index.86c992bf.css">
11
+ <script type="module" crossorigin src="/builder/assets/index.b9eeb2a8.js"></script>
12
+ <link rel="stylesheet" href="/builder/assets/index.07382a47.css">
13
13
  </head>
14
14
 
15
15
  <body id="app">
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.query = exports.find = exports.destroy = exports.save = exports.update = exports.buildSchemaFromDb = exports.fetch = void 0;
15
+ exports.query = exports.find = exports.destroy = exports.save = exports.update = exports.buildSchemaFromDb = exports.verify = exports.fetch = void 0;
16
16
  const utils_1 = require("../../db/utils");
17
17
  const internal_1 = require("./table/internal");
18
18
  const constants_1 = require("../../constants");
@@ -21,6 +21,52 @@ const utils_2 = require("./row/utils");
21
21
  const utils_3 = require("../../threads/utils");
22
22
  const backend_core_1 = require("@budibase/backend-core");
23
23
  const sdk_1 = __importDefault(require("../../sdk"));
24
+ function getErrorTables(errors, errorType) {
25
+ return Object.entries(errors)
26
+ .filter(entry => entry[1] === errorType)
27
+ .map(([name]) => name);
28
+ }
29
+ function updateError(error, newError, tables) {
30
+ if (!error) {
31
+ error = "";
32
+ }
33
+ if (error.length > 0) {
34
+ error += "\n";
35
+ }
36
+ error += `${newError} ${tables.join(", ")}`;
37
+ return error;
38
+ }
39
+ function getConnector(datasource) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ const Connector = yield (0, integrations_1.getIntegration)(datasource.source);
42
+ // can't enrich if it doesn't have an ID yet
43
+ if (datasource._id) {
44
+ datasource = yield sdk_1.default.datasources.enrich(datasource);
45
+ }
46
+ // Connect to the DB and build the schema
47
+ return new Connector(datasource.config);
48
+ });
49
+ }
50
+ function buildSchemaHelper(datasource) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ const connector = (yield getConnector(datasource));
53
+ yield connector.buildSchema(datasource._id, datasource.entities);
54
+ const errors = connector.schemaErrors;
55
+ let error = null;
56
+ if (errors && Object.keys(errors).length > 0) {
57
+ const noKey = getErrorTables(errors, constants_1.BuildSchemaErrors.NO_KEY);
58
+ const invalidCol = getErrorTables(errors, constants_1.BuildSchemaErrors.INVALID_COLUMN);
59
+ if (noKey.length) {
60
+ error = updateError(error, "No primary key constraint found for the following:", noKey);
61
+ }
62
+ if (invalidCol.length) {
63
+ const invalidCols = Object.values(constants_1.InvalidColumns).join(", ");
64
+ error = updateError(error, `Cannot use columns ${invalidCols} found in following:`, invalidCol);
65
+ }
66
+ }
67
+ return { tables: connector.tables, error };
68
+ });
69
+ }
24
70
  function fetch(ctx) {
25
71
  return __awaiter(this, void 0, void 0, function* () {
26
72
  // Get internal tables
@@ -52,6 +98,29 @@ function fetch(ctx) {
52
98
  });
53
99
  }
54
100
  exports.fetch = fetch;
101
+ function verify(ctx) {
102
+ return __awaiter(this, void 0, void 0, function* () {
103
+ const { datasource } = ctx.request.body;
104
+ let existingDatasource;
105
+ if (datasource._id) {
106
+ existingDatasource = yield sdk_1.default.datasources.get(datasource._id);
107
+ }
108
+ let enrichedDatasource = datasource;
109
+ if (existingDatasource) {
110
+ enrichedDatasource = sdk_1.default.datasources.mergeConfigs(datasource, existingDatasource);
111
+ }
112
+ const connector = yield getConnector(enrichedDatasource);
113
+ if (!connector.testConnection) {
114
+ ctx.throw(400, "Connection information verification not supported");
115
+ }
116
+ const response = yield connector.testConnection();
117
+ ctx.body = {
118
+ connected: response.connected,
119
+ error: response.error,
120
+ };
121
+ });
122
+ }
123
+ exports.verify = verify;
55
124
  function buildSchemaFromDb(ctx) {
56
125
  return __awaiter(this, void 0, void 0, function* () {
57
126
  const db = backend_core_1.context.getAppDB();
@@ -266,41 +335,3 @@ function query(ctx) {
266
335
  });
267
336
  }
268
337
  exports.query = query;
269
- function getErrorTables(errors, errorType) {
270
- return Object.entries(errors)
271
- .filter(entry => entry[1] === errorType)
272
- .map(([name]) => name);
273
- }
274
- function updateError(error, newError, tables) {
275
- if (!error) {
276
- error = "";
277
- }
278
- if (error.length > 0) {
279
- error += "\n";
280
- }
281
- error += `${newError} ${tables.join(", ")}`;
282
- return error;
283
- }
284
- function buildSchemaHelper(datasource) {
285
- return __awaiter(this, void 0, void 0, function* () {
286
- const Connector = yield (0, integrations_1.getIntegration)(datasource.source);
287
- datasource = yield sdk_1.default.datasources.enrich(datasource);
288
- // Connect to the DB and build the schema
289
- const connector = new Connector(datasource.config);
290
- yield connector.buildSchema(datasource._id, datasource.entities);
291
- const errors = connector.schemaErrors;
292
- let error = null;
293
- if (errors && Object.keys(errors).length > 0) {
294
- const noKey = getErrorTables(errors, constants_1.BuildSchemaErrors.NO_KEY);
295
- const invalidCol = getErrorTables(errors, constants_1.BuildSchemaErrors.INVALID_COLUMN);
296
- if (noKey.length) {
297
- error = updateError(error, "No primary key constraint found for the following:", noKey);
298
- }
299
- if (invalidCol.length) {
300
- const invalidCols = Object.values(constants_1.InvalidColumns).join(", ");
301
- error = updateError(error, `Cannot use columns ${invalidCols} found in following:`, invalidCol);
302
- }
303
- }
304
- return { tables: connector.tables, error };
305
- });
306
- }
@@ -20,9 +20,9 @@ function fetch(ctx) {
20
20
  exports.fetch = fetch;
21
21
  function find(ctx) {
22
22
  return __awaiter(this, void 0, void 0, function* () {
23
- const defs = yield (0, integrations_1.getDefinitions)();
23
+ const def = yield (0, integrations_1.getDefinition)(ctx.params.type);
24
+ ctx.body = def;
24
25
  ctx.status = 200;
25
- ctx.body = defs[ctx.params.type];
26
26
  });
27
27
  }
28
28
  exports.find = find;
@@ -34,6 +34,7 @@ const validators_1 = require("./utils/validators");
34
34
  const router = new router_1.default();
35
35
  router
36
36
  .get("/api/datasources", (0, authorized_1.default)(backend_core_1.permissions.BUILDER), datasourceController.fetch)
37
+ .post("/api/datasources/verify", (0, authorized_1.default)(backend_core_1.permissions.BUILDER), datasourceController.verify)
37
38
  .get("/api/datasources/:datasourceId", (0, authorized_1.default)(backend_core_1.permissions.PermissionType.TABLE, backend_core_1.permissions.PermissionLevel.READ), datasourceController.find)
38
39
  .put("/api/datasources/:datasourceId", (0, authorized_1.default)(backend_core_1.permissions.PermissionType.TABLE, backend_core_1.permissions.PermissionLevel.READ), datasourceController.update)
39
40
  .post("/api/datasources/query", (0, authorized_1.default)(backend_core_1.permissions.PermissionType.TABLE, backend_core_1.permissions.PermissionLevel.READ), (0, validators_1.datasourceQueryValidator)(), datasourceController.query)
@@ -33,6 +33,10 @@ exports.definition = {
33
33
  type: types_1.AutomationIOType.STRING,
34
34
  title: "Webhook URL",
35
35
  },
36
+ body: {
37
+ type: types_1.AutomationIOType.JSON,
38
+ title: "Payload",
39
+ },
36
40
  value1: {
37
41
  type: types_1.AutomationIOType.STRING,
38
42
  title: "Input Value 1",
@@ -78,7 +82,19 @@ exports.definition = {
78
82
  function run({ inputs }) {
79
83
  var _a;
80
84
  return __awaiter(this, void 0, void 0, function* () {
81
- const { url, value1, value2, value3, value4, value5 } = inputs;
85
+ //TODO - Remove deprecated values 1,2,3,4,5 after November 2023
86
+ const { url, value1, value2, value3, value4, value5, body } = inputs;
87
+ let payload = {};
88
+ try {
89
+ payload = (body === null || body === void 0 ? void 0 : body.value) ? JSON.parse(body === null || body === void 0 ? void 0 : body.value) : {};
90
+ }
91
+ catch (err) {
92
+ return {
93
+ httpStatus: 400,
94
+ response: "Invalid payload JSON",
95
+ success: false,
96
+ };
97
+ }
82
98
  if (!((_a = url === null || url === void 0 ? void 0 : url.trim()) === null || _a === void 0 ? void 0 : _a.length)) {
83
99
  return {
84
100
  httpStatus: 400,
@@ -90,13 +106,11 @@ function run({ inputs }) {
90
106
  try {
91
107
  response = yield (0, node_fetch_1.default)(url, {
92
108
  method: "post",
93
- body: JSON.stringify({
94
- value1,
109
+ body: JSON.stringify(Object.assign({ value1,
95
110
  value2,
96
111
  value3,
97
112
  value4,
98
- value5,
99
- }),
113
+ value5 }, payload)),
100
114
  headers: {
101
115
  "Content-Type": "application/json",
102
116
  },
@@ -32,6 +32,10 @@ exports.definition = {
32
32
  type: types_1.AutomationIOType.STRING,
33
33
  title: "Webhook URL",
34
34
  },
35
+ body: {
36
+ type: types_1.AutomationIOType.JSON,
37
+ title: "Payload",
38
+ },
35
39
  value1: {
36
40
  type: types_1.AutomationIOType.STRING,
37
41
  title: "Payload Value 1",
@@ -72,7 +76,19 @@ exports.definition = {
72
76
  function run({ inputs }) {
73
77
  var _a;
74
78
  return __awaiter(this, void 0, void 0, function* () {
75
- const { url, value1, value2, value3, value4, value5 } = inputs;
79
+ //TODO - Remove deprecated values 1,2,3,4,5 after November 2023
80
+ const { url, value1, value2, value3, value4, value5, body } = inputs;
81
+ let payload = {};
82
+ try {
83
+ payload = (body === null || body === void 0 ? void 0 : body.value) ? JSON.parse(body === null || body === void 0 ? void 0 : body.value) : {};
84
+ }
85
+ catch (err) {
86
+ return {
87
+ httpStatus: 400,
88
+ response: "Invalid payload JSON",
89
+ success: false,
90
+ };
91
+ }
76
92
  if (!((_a = url === null || url === void 0 ? void 0 : url.trim()) === null || _a === void 0 ? void 0 : _a.length)) {
77
93
  return {
78
94
  httpStatus: 400,
@@ -86,14 +102,11 @@ function run({ inputs }) {
86
102
  try {
87
103
  response = yield (0, node_fetch_1.default)(url, {
88
104
  method: "post",
89
- body: JSON.stringify({
90
- platform: "budibase",
91
- value1,
105
+ body: JSON.stringify(Object.assign({ platform: "budibase", value1,
92
106
  value2,
93
107
  value3,
94
108
  value4,
95
- value5,
96
- }),
109
+ value5 }, payload)),
97
110
  headers: {
98
111
  "Content-Type": "application/json",
99
112
  },
@@ -30,10 +30,16 @@ const WH_STEP_ID = triggerInfo_1.definitions.WEBHOOK.stepId;
30
30
  const CRON_STEP_ID = triggerInfo_1.definitions.CRON.stepId;
31
31
  const Runner = new threads_1.Thread(threads_1.ThreadType.AUTOMATION);
32
32
  function loggingArgs(job) {
33
- return {
34
- jobId: job.id,
35
- trigger: job.data.automation.definition.trigger.event,
36
- };
33
+ return [
34
+ {
35
+ _logKey: "automation",
36
+ trigger: job.data.automation.definition.trigger.event,
37
+ },
38
+ {
39
+ _logKey: "bull",
40
+ jobId: job.id,
41
+ },
42
+ ];
37
43
  }
38
44
  function processEvent(job) {
39
45
  return __awaiter(this, void 0, void 0, function* () {
@@ -42,16 +48,16 @@ function processEvent(job) {
42
48
  const task = () => __awaiter(this, void 0, void 0, function* () {
43
49
  try {
44
50
  // need to actually await these so that an error can be captured properly
45
- console.log("automation running", loggingArgs(job));
51
+ console.log("automation running", ...loggingArgs(job));
46
52
  const runFn = () => Runner.run(job);
47
53
  const result = yield pro_1.quotas.addAutomation(runFn, {
48
54
  automationId,
49
55
  });
50
- console.log("automation completed", loggingArgs(job));
56
+ console.log("automation completed", ...loggingArgs(job));
51
57
  return result;
52
58
  }
53
59
  catch (err) {
54
- console.error(`automation was unable to run`, err, loggingArgs(job));
60
+ console.error(`automation was unable to run`, err, ...loggingArgs(job));
55
61
  return { err };
56
62
  }
57
63
  });
@@ -117,7 +117,7 @@ function init(endpoint) {
117
117
  docClient = new AWS.DynamoDB.DocumentClient(docClientParams);
118
118
  }
119
119
  exports.init = init;
120
- if (!environment_1.default.isProd()) {
120
+ if (!environment_1.default.isProd() && !environment_1.default.isJest()) {
121
121
  environment_1.default._set("AWS_ACCESS_KEY_ID", "KEY_ID");
122
122
  environment_1.default._set("AWS_SECRET_ACCESS_KEY", "SECRET_KEY");
123
123
  init("http://localhost:8333");
@@ -8,14 +8,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const types_1 = require("@budibase/types");
13
- const Airtable = require("airtable");
16
+ const airtable_1 = __importDefault(require("airtable"));
14
17
  const SCHEMA = {
15
18
  docs: "https://airtable.com/api",
16
19
  description: "Airtable is a spreadsheet-database hybrid, with the features of a database but applied to a spreadsheet.",
17
20
  friendlyName: "Airtable",
18
21
  type: "Spreadsheet",
22
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
19
23
  datasource: {
20
24
  apiKey: {
21
25
  type: types_1.DatasourceFieldType.PASSWORD,
@@ -79,7 +83,29 @@ const SCHEMA = {
79
83
  class AirtableIntegration {
80
84
  constructor(config) {
81
85
  this.config = config;
82
- this.client = new Airtable(config).base(config.base);
86
+ this.client = new airtable_1.default(config).base(config.base);
87
+ }
88
+ testConnection() {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ const mockTable = Date.now().toString();
91
+ try {
92
+ yield this.client.makeRequest({
93
+ path: `/${mockTable}`,
94
+ });
95
+ return { connected: true };
96
+ }
97
+ catch (e) {
98
+ if (e.message ===
99
+ `Could not find table ${mockTable} in application ${this.config.base}`) {
100
+ // The request managed to check the application, so the credentials are valid
101
+ return { connected: true };
102
+ }
103
+ return {
104
+ connected: false,
105
+ error: e.message,
106
+ };
107
+ }
108
+ });
83
109
  }
84
110
  create(query) {
85
111
  return __awaiter(this, void 0, void 0, function* () {
@@ -10,12 +10,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const types_1 = require("@budibase/types");
13
- const { Database, aql } = require("arangojs");
13
+ const arangojs_1 = require("arangojs");
14
14
  const SCHEMA = {
15
15
  docs: "https://github.com/arangodb/arangojs",
16
16
  friendlyName: "ArangoDB",
17
17
  type: "Non-relational",
18
18
  description: "ArangoDB is a scalable open-source multi-model database natively supporting graph, document and search. All supported data models & access patterns can be combined in queries allowing for maximal flexibility. ",
19
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
19
20
  datasource: {
20
21
  url: {
21
22
  type: types_1.DatasourceFieldType.STRING,
@@ -61,7 +62,22 @@ class ArangoDBIntegration {
61
62
  },
62
63
  };
63
64
  this.config = config;
64
- this.client = new Database(newConfig);
65
+ this.client = new arangojs_1.Database(newConfig);
66
+ }
67
+ testConnection() {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ const response = {
70
+ connected: false,
71
+ };
72
+ try {
73
+ yield this.client.get();
74
+ response.connected = true;
75
+ }
76
+ catch (e) {
77
+ response.error = e.message;
78
+ }
79
+ return response;
80
+ });
65
81
  }
66
82
  read(query) {
67
83
  return __awaiter(this, void 0, void 0, function* () {
@@ -83,7 +99,7 @@ class ArangoDBIntegration {
83
99
  return __awaiter(this, void 0, void 0, function* () {
84
100
  const clc = this.client.collection(this.config.collection);
85
101
  try {
86
- const result = yield this.client.query(aql `INSERT ${query.json} INTO ${clc} RETURN NEW`);
102
+ const result = yield this.client.query((0, arangojs_1.aql) `INSERT ${query.json} INTO ${clc} RETURN NEW`);
87
103
  return result.all();
88
104
  }
89
105
  catch (err) {
@@ -16,6 +16,7 @@ const SCHEMA = {
16
16
  friendlyName: "CouchDB",
17
17
  type: "Non-relational",
18
18
  description: "Apache CouchDB is an open-source document-oriented NoSQL database, implemented in Erlang.",
19
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
19
20
  datasource: {
20
21
  url: {
21
22
  type: types_1.DatasourceFieldType.STRING,
@@ -59,9 +60,23 @@ const SCHEMA = {
59
60
  };
60
61
  class CouchDBIntegration {
61
62
  constructor(config) {
62
- this.config = config;
63
63
  this.client = backend_core_1.db.DatabaseWithConnection(config.database, config.url);
64
64
  }
65
+ testConnection() {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ const response = {
68
+ connected: false,
69
+ };
70
+ try {
71
+ const result = yield this.query("exists", "validation error", {});
72
+ response.connected = result === true;
73
+ }
74
+ catch (e) {
75
+ response.error = e.message;
76
+ }
77
+ return response;
78
+ });
79
+ }
65
80
  query(command, errorMsg, query) {
66
81
  return __awaiter(this, void 0, void 0, function* () {
67
82
  try {
@@ -20,6 +20,7 @@ const SCHEMA = {
20
20
  description: "Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale.",
21
21
  friendlyName: "DynamoDB",
22
22
  type: "Non-relational",
23
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
23
24
  datasource: {
24
25
  region: {
25
26
  type: types_1.DatasourceFieldType.STRING,
@@ -135,6 +136,21 @@ class DynamoDBIntegration {
135
136
  this.config = Object.assign(Object.assign({}, this.config), { currentClockSkew: true, region: config.region || dynamoClient_1.AWS_REGION, endpoint: config.endpoint || undefined });
136
137
  this.client = new aws_sdk_1.default.DynamoDB.DocumentClient(this.config);
137
138
  }
139
+ testConnection() {
140
+ return __awaiter(this, void 0, void 0, function* () {
141
+ const response = {
142
+ connected: false,
143
+ };
144
+ try {
145
+ const scanRes = yield new aws_sdk_1.default.DynamoDB(this.config).listTables().promise();
146
+ response.connected = !!scanRes.$response;
147
+ }
148
+ catch (e) {
149
+ response.error = e.message;
150
+ }
151
+ return response;
152
+ });
153
+ }
138
154
  create(query) {
139
155
  return __awaiter(this, void 0, void 0, function* () {
140
156
  const params = Object.assign({ TableName: query.table }, query.json);
@@ -16,6 +16,7 @@ const SCHEMA = {
16
16
  description: "Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents.",
17
17
  friendlyName: "ElasticSearch",
18
18
  type: "Non-relational",
19
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
19
20
  datasource: {
20
21
  url: {
21
22
  type: types_1.DatasourceFieldType.STRING,
@@ -102,6 +103,20 @@ class ElasticSearchIntegration {
102
103
  }
103
104
  this.client = new elasticsearch_1.Client(clientConfig);
104
105
  }
106
+ testConnection() {
107
+ return __awaiter(this, void 0, void 0, function* () {
108
+ try {
109
+ yield this.client.info();
110
+ return { connected: true };
111
+ }
112
+ catch (e) {
113
+ return {
114
+ connected: false,
115
+ error: e.message,
116
+ };
117
+ }
118
+ });
119
+ }
105
120
  create(query) {
106
121
  return __awaiter(this, void 0, void 0, function* () {
107
122
  const { index, json } = query;
@@ -16,6 +16,7 @@ const SCHEMA = {
16
16
  friendlyName: "Firestore",
17
17
  type: "Non-relational",
18
18
  description: "Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud.",
19
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
19
20
  datasource: {
20
21
  email: {
21
22
  type: types_1.DatasourceFieldType.STRING,
@@ -93,6 +94,20 @@ class FirebaseIntegration {
93
94
  },
94
95
  });
95
96
  }
97
+ testConnection() {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ try {
100
+ yield this.client.listCollections();
101
+ return { connected: true };
102
+ }
103
+ catch (e) {
104
+ return {
105
+ connected: false,
106
+ error: e.message,
107
+ };
108
+ }
109
+ });
110
+ }
96
111
  create(query) {
97
112
  return __awaiter(this, void 0, void 0, function* () {
98
113
  try {
@@ -40,6 +40,7 @@ const SCHEMA = {
40
40
  description: "Create and collaborate on online spreadsheets in real-time and from any device. ",
41
41
  friendlyName: "Google Sheets",
42
42
  type: "Spreadsheet",
43
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
43
44
  datasource: {
44
45
  spreadsheetId: {
45
46
  display: "Google Sheet URL",
@@ -110,6 +111,21 @@ class GoogleSheetsIntegration {
110
111
  const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId);
111
112
  this.client = new google_spreadsheet_1.GoogleSpreadsheet(spreadsheetId);
112
113
  }
114
+ testConnection() {
115
+ return __awaiter(this, void 0, void 0, function* () {
116
+ try {
117
+ yield this.connect();
118
+ yield this.client.loadInfo();
119
+ return { connected: true };
120
+ }
121
+ catch (e) {
122
+ return {
123
+ connected: false,
124
+ error: e.message,
125
+ };
126
+ }
127
+ });
128
+ }
113
129
  getBindingIdentifier() {
114
130
  return "";
115
131
  }
@@ -382,7 +398,20 @@ class GoogleSheetsIntegration {
382
398
  try {
383
399
  yield this.connect();
384
400
  const sheet = this.client.sheetsByTitle[query.sheet];
385
- const rows = yield sheet.getRows();
401
+ let rows = [];
402
+ if (query.paginate) {
403
+ const limit = query.paginate.limit || 100;
404
+ let page = typeof query.paginate.page === "number"
405
+ ? query.paginate.page
406
+ : parseInt(query.paginate.page || "1");
407
+ rows = yield sheet.getRows({
408
+ limit,
409
+ offset: (page - 1) * limit,
410
+ });
411
+ }
412
+ else {
413
+ rows = yield sheet.getRows();
414
+ }
386
415
  const filtered = shared_core_1.dataFilters.runLuceneQuery(rows, query.filters);
387
416
  const headerValues = sheet.headerValues;
388
417
  let response = [];
@@ -50,6 +50,7 @@ const DEFINITIONS = {
50
50
  [types_1.SourceName.GOOGLE_SHEETS]: googlesheets_1.default.schema,
51
51
  [types_1.SourceName.REDIS]: redis_1.default.schema,
52
52
  [types_1.SourceName.SNOWFLAKE]: snowflake_1.default.schema,
53
+ [types_1.SourceName.ORACLE]: undefined,
53
54
  };
54
55
  const INTEGRATIONS = {
55
56
  [types_1.SourceName.POSTGRES]: postgres_1.default.integration,
@@ -68,6 +69,7 @@ const INTEGRATIONS = {
68
69
  [types_1.SourceName.REDIS]: redis_1.default.integration,
69
70
  [types_1.SourceName.FIRESTORE]: firebase_1.default.integration,
70
71
  [types_1.SourceName.SNOWFLAKE]: snowflake_1.default.integration,
72
+ [types_1.SourceName.ORACLE]: undefined,
71
73
  };
72
74
  // optionally add oracle integration if the oracle binary can be installed
73
75
  if (process.arch &&
@@ -79,8 +81,9 @@ if (process.arch &&
79
81
  function getDefinition(source) {
80
82
  return __awaiter(this, void 0, void 0, function* () {
81
83
  // check if its integrated, faster
82
- if (DEFINITIONS[source]) {
83
- return DEFINITIONS[source];
84
+ const definition = DEFINITIONS[source];
85
+ if (definition) {
86
+ return definition;
84
87
  }
85
88
  const allDefinitions = yield getDefinitions();
86
89
  return allDefinitions[source];
@@ -23,6 +23,7 @@ const SCHEMA = {
23
23
  description: "Microsoft SQL Server is a relational database management system developed by Microsoft. ",
24
24
  friendlyName: "MS SQL Server",
25
25
  type: "Relational",
26
+ features: [types_1.DatasourceFeature.CONNECTION_CHECKING],
26
27
  datasource: {
27
28
  user: {
28
29
  type: types_1.DatasourceFieldType.STRING,
@@ -94,6 +95,21 @@ class SqlServerIntegration extends sql_1.default {
94
95
  this.pool = new sqlServer.ConnectionPool(clientCfg);
95
96
  }
96
97
  }
98
+ testConnection() {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ const response = {
101
+ connected: false,
102
+ };
103
+ try {
104
+ yield this.connect();
105
+ response.connected = true;
106
+ }
107
+ catch (e) {
108
+ response.error = e.message;
109
+ }
110
+ return response;
111
+ });
112
+ }
97
113
  getBindingIdentifier() {
98
114
  return `@p${this.index++}`;
99
115
  }