@budibase/server 2.6.18 → 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.
- package/builder/assets/{index.86c992bf.css → index.07382a47.css} +2 -2
- package/builder/assets/{index.69c5c1ea.js → index.b9eeb2a8.js} +310 -318
- package/builder/index.html +2 -2
- package/dist/api/controllers/datasource.js +70 -39
- package/dist/api/controllers/integration.js +2 -2
- package/dist/api/routes/datasource.js +1 -0
- package/dist/automations/steps/make.js +19 -5
- package/dist/automations/steps/zapier.js +19 -6
- package/dist/automations/utils.js +13 -7
- package/dist/db/dynamoClient.js +1 -1
- package/dist/integrations/airtable.js +28 -2
- package/dist/integrations/arangodb.js +19 -3
- package/dist/integrations/couchdb.js +16 -1
- package/dist/integrations/dynamodb.js +16 -0
- package/dist/integrations/elasticsearch.js +15 -0
- package/dist/integrations/firebase.js +15 -0
- package/dist/integrations/googlesheets.js +30 -1
- package/dist/integrations/index.js +5 -2
- package/dist/integrations/microsoftSqlServer.js +16 -0
- package/dist/integrations/mongodb.js +16 -0
- package/dist/integrations/mysql.js +21 -5
- package/dist/integrations/oracle.js +29 -0
- package/dist/integrations/postgres.js +26 -7
- package/dist/integrations/redis.js +20 -1
- package/dist/integrations/s3.js +23 -4
- package/dist/integrations/snowflake.js +15 -0
- package/dist/migrations/functions/backfill/app/queries.js +1 -2
- package/dist/sdk/app/datasources/datasources.js +10 -3
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/jest.config.ts +3 -3
- package/nodemon.json +7 -3
- package/package.json +10 -9
- package/src/api/controllers/datasource.ts +88 -49
- package/src/api/controllers/integration.ts +3 -3
- package/src/api/routes/datasource.ts +5 -0
- package/src/automations/steps/make.ts +18 -1
- package/src/automations/steps/zapier.ts +18 -1
- package/src/automations/tests/make.spec.ts +54 -0
- package/src/automations/tests/zapier.spec.ts +56 -0
- package/src/automations/utils.ts +13 -7
- package/src/db/dynamoClient.ts +1 -1
- package/src/integration-test/postgres.spec.ts +0 -1
- package/src/integrations/airtable.ts +31 -4
- package/src/integrations/arangodb.ts +18 -2
- package/src/integrations/couchdb.ts +18 -4
- package/src/integrations/dynamodb.ts +34 -5
- package/src/integrations/elasticsearch.ts +16 -1
- package/src/integrations/firebase.ts +15 -0
- package/src/integrations/googlesheets.ts +31 -2
- package/src/integrations/index.ts +12 -7
- package/src/integrations/microsoftSqlServer.ts +16 -0
- package/src/integrations/mongodb.ts +16 -0
- package/src/integrations/mysql.ts +27 -16
- package/src/integrations/oracle.ts +28 -6
- package/src/integrations/postgres.ts +21 -3
- package/src/integrations/redis.ts +26 -3
- package/src/integrations/s3.ts +19 -3
- package/src/integrations/snowflake.ts +20 -1
- package/src/migrations/functions/backfill/app/queries.ts +1 -1
- package/src/sdk/app/datasources/datasources.ts +7 -1
- package/tsconfig.json +1 -1
- package/src/automations/tests/zapier.spec.js +0 -27
|
@@ -3,10 +3,13 @@ import {
|
|
|
3
3
|
DatasourceFieldType,
|
|
4
4
|
QueryType,
|
|
5
5
|
IntegrationBase,
|
|
6
|
+
DatasourceFeature,
|
|
7
|
+
ConnectionInfo,
|
|
6
8
|
} from "@budibase/types"
|
|
7
9
|
|
|
8
10
|
import AWS from "aws-sdk"
|
|
9
11
|
import { AWS_REGION } from "../db/dynamoClient"
|
|
12
|
+
import { DocumentClient } from "aws-sdk/clients/dynamodb"
|
|
10
13
|
|
|
11
14
|
interface DynamoDBConfig {
|
|
12
15
|
region: string
|
|
@@ -22,6 +25,7 @@ const SCHEMA: Integration = {
|
|
|
22
25
|
"Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale.",
|
|
23
26
|
friendlyName: "DynamoDB",
|
|
24
27
|
type: "Non-relational",
|
|
28
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
25
29
|
datasource: {
|
|
26
30
|
region: {
|
|
27
31
|
type: DatasourceFieldType.STRING,
|
|
@@ -128,7 +132,7 @@ const SCHEMA: Integration = {
|
|
|
128
132
|
|
|
129
133
|
class DynamoDBIntegration implements IntegrationBase {
|
|
130
134
|
private config: DynamoDBConfig
|
|
131
|
-
private client
|
|
135
|
+
private client
|
|
132
136
|
|
|
133
137
|
constructor(config: DynamoDBConfig) {
|
|
134
138
|
this.config = config
|
|
@@ -148,7 +152,23 @@ class DynamoDBIntegration implements IntegrationBase {
|
|
|
148
152
|
this.client = new AWS.DynamoDB.DocumentClient(this.config)
|
|
149
153
|
}
|
|
150
154
|
|
|
151
|
-
async
|
|
155
|
+
async testConnection() {
|
|
156
|
+
const response: ConnectionInfo = {
|
|
157
|
+
connected: false,
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const scanRes = await new AWS.DynamoDB(this.config).listTables().promise()
|
|
161
|
+
response.connected = !!scanRes.$response
|
|
162
|
+
} catch (e: any) {
|
|
163
|
+
response.error = e.message as string
|
|
164
|
+
}
|
|
165
|
+
return response
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async create(query: {
|
|
169
|
+
table: string
|
|
170
|
+
json: Omit<DocumentClient.PutItemInput, "TableName">
|
|
171
|
+
}) {
|
|
152
172
|
const params = {
|
|
153
173
|
TableName: query.table,
|
|
154
174
|
...query.json,
|
|
@@ -189,7 +209,10 @@ class DynamoDBIntegration implements IntegrationBase {
|
|
|
189
209
|
return new AWS.DynamoDB(this.config).describeTable(params).promise()
|
|
190
210
|
}
|
|
191
211
|
|
|
192
|
-
async get(query: {
|
|
212
|
+
async get(query: {
|
|
213
|
+
table: string
|
|
214
|
+
json: Omit<DocumentClient.GetItemInput, "TableName">
|
|
215
|
+
}) {
|
|
193
216
|
const params = {
|
|
194
217
|
TableName: query.table,
|
|
195
218
|
...query.json,
|
|
@@ -197,7 +220,10 @@ class DynamoDBIntegration implements IntegrationBase {
|
|
|
197
220
|
return this.client.get(params).promise()
|
|
198
221
|
}
|
|
199
222
|
|
|
200
|
-
async update(query: {
|
|
223
|
+
async update(query: {
|
|
224
|
+
table: string
|
|
225
|
+
json: Omit<DocumentClient.UpdateItemInput, "TableName">
|
|
226
|
+
}) {
|
|
201
227
|
const params = {
|
|
202
228
|
TableName: query.table,
|
|
203
229
|
...query.json,
|
|
@@ -205,7 +231,10 @@ class DynamoDBIntegration implements IntegrationBase {
|
|
|
205
231
|
return this.client.update(params).promise()
|
|
206
232
|
}
|
|
207
233
|
|
|
208
|
-
async delete(query: {
|
|
234
|
+
async delete(query: {
|
|
235
|
+
table: string
|
|
236
|
+
json: Omit<DocumentClient.DeleteItemInput, "TableName">
|
|
237
|
+
}) {
|
|
209
238
|
const params = {
|
|
210
239
|
TableName: query.table,
|
|
211
240
|
...query.json,
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
DatasourceFieldType,
|
|
4
4
|
QueryType,
|
|
5
5
|
IntegrationBase,
|
|
6
|
+
DatasourceFeature,
|
|
7
|
+
ConnectionInfo,
|
|
6
8
|
} from "@budibase/types"
|
|
7
9
|
|
|
8
10
|
import { Client, ClientOptions } from "@elastic/elasticsearch"
|
|
@@ -20,6 +22,7 @@ const SCHEMA: Integration = {
|
|
|
20
22
|
"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.",
|
|
21
23
|
friendlyName: "ElasticSearch",
|
|
22
24
|
type: "Non-relational",
|
|
25
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
23
26
|
datasource: {
|
|
24
27
|
url: {
|
|
25
28
|
type: DatasourceFieldType.STRING,
|
|
@@ -95,7 +98,7 @@ const SCHEMA: Integration = {
|
|
|
95
98
|
|
|
96
99
|
class ElasticSearchIntegration implements IntegrationBase {
|
|
97
100
|
private config: ElasticsearchConfig
|
|
98
|
-
private client
|
|
101
|
+
private client
|
|
99
102
|
|
|
100
103
|
constructor(config: ElasticsearchConfig) {
|
|
101
104
|
this.config = config
|
|
@@ -114,6 +117,18 @@ class ElasticSearchIntegration implements IntegrationBase {
|
|
|
114
117
|
this.client = new Client(clientConfig)
|
|
115
118
|
}
|
|
116
119
|
|
|
120
|
+
async testConnection(): Promise<ConnectionInfo> {
|
|
121
|
+
try {
|
|
122
|
+
await this.client.info()
|
|
123
|
+
return { connected: true }
|
|
124
|
+
} catch (e: any) {
|
|
125
|
+
return {
|
|
126
|
+
connected: false,
|
|
127
|
+
error: e.message as string,
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
117
132
|
async create(query: { index: string; json: object }) {
|
|
118
133
|
const { index, json } = query
|
|
119
134
|
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
Integration,
|
|
4
4
|
QueryType,
|
|
5
5
|
IntegrationBase,
|
|
6
|
+
DatasourceFeature,
|
|
7
|
+
ConnectionInfo,
|
|
6
8
|
} from "@budibase/types"
|
|
7
9
|
import { Firestore, WhereFilterOp } from "@google-cloud/firestore"
|
|
8
10
|
|
|
@@ -18,6 +20,7 @@ const SCHEMA: Integration = {
|
|
|
18
20
|
type: "Non-relational",
|
|
19
21
|
description:
|
|
20
22
|
"Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud.",
|
|
23
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
21
24
|
datasource: {
|
|
22
25
|
email: {
|
|
23
26
|
type: DatasourceFieldType.STRING,
|
|
@@ -99,6 +102,18 @@ class FirebaseIntegration implements IntegrationBase {
|
|
|
99
102
|
})
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
async testConnection(): Promise<ConnectionInfo> {
|
|
106
|
+
try {
|
|
107
|
+
await this.client.listCollections()
|
|
108
|
+
return { connected: true }
|
|
109
|
+
} catch (e: any) {
|
|
110
|
+
return {
|
|
111
|
+
connected: false,
|
|
112
|
+
error: e.message as string,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
102
117
|
async create(query: { json: object; extra: { [key: string]: string } }) {
|
|
103
118
|
try {
|
|
104
119
|
const documentReference = this.client
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ConnectionInfo,
|
|
3
|
+
DatasourceFeature,
|
|
2
4
|
DatasourceFieldType,
|
|
3
5
|
DatasourcePlus,
|
|
4
6
|
FieldType,
|
|
@@ -15,7 +17,7 @@ import {
|
|
|
15
17
|
} from "@budibase/types"
|
|
16
18
|
import { OAuth2Client } from "google-auth-library"
|
|
17
19
|
import { buildExternalTableId, finaliseExternalTables } from "./utils"
|
|
18
|
-
import { GoogleSpreadsheet } from "google-spreadsheet"
|
|
20
|
+
import { GoogleSpreadsheet, GoogleSpreadsheetRow } from "google-spreadsheet"
|
|
19
21
|
import fetch from "node-fetch"
|
|
20
22
|
import { configs, HTTPError } from "@budibase/backend-core"
|
|
21
23
|
import { dataFilters } from "@budibase/shared-core"
|
|
@@ -64,6 +66,7 @@ const SCHEMA: Integration = {
|
|
|
64
66
|
"Create and collaborate on online spreadsheets in real-time and from any device. ",
|
|
65
67
|
friendlyName: "Google Sheets",
|
|
66
68
|
type: "Spreadsheet",
|
|
69
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
67
70
|
datasource: {
|
|
68
71
|
spreadsheetId: {
|
|
69
72
|
display: "Google Sheet URL",
|
|
@@ -139,6 +142,19 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|
|
139
142
|
this.client = new GoogleSpreadsheet(spreadsheetId)
|
|
140
143
|
}
|
|
141
144
|
|
|
145
|
+
async testConnection(): Promise<ConnectionInfo> {
|
|
146
|
+
try {
|
|
147
|
+
await this.connect()
|
|
148
|
+
await this.client.loadInfo()
|
|
149
|
+
return { connected: true }
|
|
150
|
+
} catch (e: any) {
|
|
151
|
+
return {
|
|
152
|
+
connected: false,
|
|
153
|
+
error: e.message as string,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
142
158
|
getBindingIdentifier() {
|
|
143
159
|
return ""
|
|
144
160
|
}
|
|
@@ -434,7 +450,20 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|
|
434
450
|
try {
|
|
435
451
|
await this.connect()
|
|
436
452
|
const sheet = this.client.sheetsByTitle[query.sheet]
|
|
437
|
-
|
|
453
|
+
let rows: GoogleSpreadsheetRow[] = []
|
|
454
|
+
if (query.paginate) {
|
|
455
|
+
const limit = query.paginate.limit || 100
|
|
456
|
+
let page: number =
|
|
457
|
+
typeof query.paginate.page === "number"
|
|
458
|
+
? query.paginate.page
|
|
459
|
+
: parseInt(query.paginate.page || "1")
|
|
460
|
+
rows = await sheet.getRows({
|
|
461
|
+
limit,
|
|
462
|
+
offset: (page - 1) * limit,
|
|
463
|
+
})
|
|
464
|
+
} else {
|
|
465
|
+
rows = await sheet.getRows()
|
|
466
|
+
}
|
|
438
467
|
const filtered = dataFilters.runLuceneQuery(rows, query.filters)
|
|
439
468
|
const headerValues = sheet.headerValues
|
|
440
469
|
let response = []
|
|
@@ -20,7 +20,7 @@ import env from "../environment"
|
|
|
20
20
|
import { cloneDeep } from "lodash"
|
|
21
21
|
import sdk from "../sdk"
|
|
22
22
|
|
|
23
|
-
const DEFINITIONS:
|
|
23
|
+
const DEFINITIONS: Record<SourceName, Integration | undefined> = {
|
|
24
24
|
[SourceName.POSTGRES]: postgres.schema,
|
|
25
25
|
[SourceName.DYNAMODB]: dynamodb.schema,
|
|
26
26
|
[SourceName.MONGODB]: mongodb.schema,
|
|
@@ -36,9 +36,10 @@ const DEFINITIONS: { [key: string]: Integration } = {
|
|
|
36
36
|
[SourceName.GOOGLE_SHEETS]: googlesheets.schema,
|
|
37
37
|
[SourceName.REDIS]: redis.schema,
|
|
38
38
|
[SourceName.SNOWFLAKE]: snowflake.schema,
|
|
39
|
+
[SourceName.ORACLE]: undefined,
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const INTEGRATIONS:
|
|
42
|
+
const INTEGRATIONS: Record<SourceName, any> = {
|
|
42
43
|
[SourceName.POSTGRES]: postgres.integration,
|
|
43
44
|
[SourceName.DYNAMODB]: dynamodb.integration,
|
|
44
45
|
[SourceName.MONGODB]: mongodb.integration,
|
|
@@ -55,6 +56,7 @@ const INTEGRATIONS: { [key: string]: any } = {
|
|
|
55
56
|
[SourceName.REDIS]: redis.integration,
|
|
56
57
|
[SourceName.FIRESTORE]: firebase.integration,
|
|
57
58
|
[SourceName.SNOWFLAKE]: snowflake.integration,
|
|
59
|
+
[SourceName.ORACLE]: undefined,
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
// optionally add oracle integration if the oracle binary can be installed
|
|
@@ -67,10 +69,13 @@ if (
|
|
|
67
69
|
INTEGRATIONS[SourceName.ORACLE] = oracle.integration
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
export async function getDefinition(
|
|
72
|
+
export async function getDefinition(
|
|
73
|
+
source: SourceName
|
|
74
|
+
): Promise<Integration | undefined> {
|
|
71
75
|
// check if its integrated, faster
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
const definition = DEFINITIONS[source]
|
|
77
|
+
if (definition) {
|
|
78
|
+
return definition
|
|
74
79
|
}
|
|
75
80
|
const allDefinitions = await getDefinitions()
|
|
76
81
|
return allDefinitions[source]
|
|
@@ -98,7 +103,7 @@ export async function getDefinitions() {
|
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
|
|
101
|
-
export async function getIntegration(integration:
|
|
106
|
+
export async function getIntegration(integration: SourceName) {
|
|
102
107
|
if (INTEGRATIONS[integration]) {
|
|
103
108
|
return INTEGRATIONS[integration]
|
|
104
109
|
}
|
|
@@ -107,7 +112,7 @@ export async function getIntegration(integration: string) {
|
|
|
107
112
|
for (let plugin of plugins) {
|
|
108
113
|
if (plugin.name === integration) {
|
|
109
114
|
// need to use commonJS require due to its dynamic runtime nature
|
|
110
|
-
const retrieved
|
|
115
|
+
const retrieved = await getDatasourcePlugin(plugin)
|
|
111
116
|
if (retrieved.integration) {
|
|
112
117
|
return retrieved.integration
|
|
113
118
|
} else {
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
QueryType,
|
|
9
9
|
SqlQuery,
|
|
10
10
|
DatasourcePlus,
|
|
11
|
+
DatasourceFeature,
|
|
12
|
+
ConnectionInfo,
|
|
11
13
|
} from "@budibase/types"
|
|
12
14
|
import {
|
|
13
15
|
getSqlQuery,
|
|
@@ -39,6 +41,7 @@ const SCHEMA: Integration = {
|
|
|
39
41
|
"Microsoft SQL Server is a relational database management system developed by Microsoft. ",
|
|
40
42
|
friendlyName: "MS SQL Server",
|
|
41
43
|
type: "Relational",
|
|
44
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
42
45
|
datasource: {
|
|
43
46
|
user: {
|
|
44
47
|
type: DatasourceFieldType.STRING,
|
|
@@ -121,6 +124,19 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
|
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
async testConnection() {
|
|
128
|
+
const response: ConnectionInfo = {
|
|
129
|
+
connected: false,
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
await this.connect()
|
|
133
|
+
response.connected = true
|
|
134
|
+
} catch (e: any) {
|
|
135
|
+
response.error = e.message as string
|
|
136
|
+
}
|
|
137
|
+
return response
|
|
138
|
+
}
|
|
139
|
+
|
|
124
140
|
getBindingIdentifier(): string {
|
|
125
141
|
return `@p${this.index++}`
|
|
126
142
|
}
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
DatasourceFieldType,
|
|
4
4
|
QueryType,
|
|
5
5
|
IntegrationBase,
|
|
6
|
+
DatasourceFeature,
|
|
7
|
+
ConnectionInfo,
|
|
6
8
|
} from "@budibase/types"
|
|
7
9
|
import {
|
|
8
10
|
MongoClient,
|
|
@@ -38,6 +40,7 @@ const getSchema = () => {
|
|
|
38
40
|
type: "Non-relational",
|
|
39
41
|
description:
|
|
40
42
|
"MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era.",
|
|
43
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
41
44
|
datasource: {
|
|
42
45
|
connectionString: {
|
|
43
46
|
type: DatasourceFieldType.STRING,
|
|
@@ -358,6 +361,19 @@ class MongoIntegration implements IntegrationBase {
|
|
|
358
361
|
this.client = new MongoClient(config.connectionString, options)
|
|
359
362
|
}
|
|
360
363
|
|
|
364
|
+
async testConnection() {
|
|
365
|
+
const response: ConnectionInfo = {
|
|
366
|
+
connected: false,
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
await this.connect()
|
|
370
|
+
response.connected = true
|
|
371
|
+
} catch (e: any) {
|
|
372
|
+
response.error = e.message as string
|
|
373
|
+
}
|
|
374
|
+
return response
|
|
375
|
+
}
|
|
376
|
+
|
|
361
377
|
async connect() {
|
|
362
378
|
return this.client.connect()
|
|
363
379
|
}
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
Table,
|
|
8
8
|
TableSchema,
|
|
9
9
|
DatasourcePlus,
|
|
10
|
+
DatasourceFeature,
|
|
11
|
+
ConnectionInfo,
|
|
10
12
|
} from "@budibase/types"
|
|
11
13
|
import {
|
|
12
14
|
getSqlQuery,
|
|
@@ -20,18 +22,11 @@ import { NUMBER_REGEX } from "../utilities"
|
|
|
20
22
|
import Sql from "./base/sql"
|
|
21
23
|
import { MySQLColumn } from "./base/types"
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
import mysql from "mysql2/promise"
|
|
24
26
|
|
|
25
|
-
interface MySQLConfig {
|
|
26
|
-
host: string
|
|
27
|
-
port: number
|
|
28
|
-
user: string
|
|
29
|
-
password: string
|
|
27
|
+
interface MySQLConfig extends mysql.ConnectionOptions {
|
|
30
28
|
database: string
|
|
31
|
-
ssl?: { [key: string]: any }
|
|
32
29
|
rejectUnauthorized: boolean
|
|
33
|
-
typeCast: Function
|
|
34
|
-
multipleStatements: boolean
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
const SCHEMA: Integration = {
|
|
@@ -41,6 +36,7 @@ const SCHEMA: Integration = {
|
|
|
41
36
|
type: "Relational",
|
|
42
37
|
description:
|
|
43
38
|
"MySQL Database Service is a fully managed database service to deploy cloud-native applications. ",
|
|
39
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
44
40
|
datasource: {
|
|
45
41
|
host: {
|
|
46
42
|
type: DatasourceFieldType.STRING,
|
|
@@ -92,8 +88,6 @@ const SCHEMA: Integration = {
|
|
|
92
88
|
},
|
|
93
89
|
}
|
|
94
90
|
|
|
95
|
-
const TimezoneAwareDateTypes = ["timestamp"]
|
|
96
|
-
|
|
97
91
|
function bindingTypeCoerce(bindings: any[]) {
|
|
98
92
|
for (let i = 0; i < bindings.length; i++) {
|
|
99
93
|
const binding = bindings[i]
|
|
@@ -120,7 +114,7 @@ function bindingTypeCoerce(bindings: any[]) {
|
|
|
120
114
|
|
|
121
115
|
class MySQLIntegration extends Sql implements DatasourcePlus {
|
|
122
116
|
private config: MySQLConfig
|
|
123
|
-
private client
|
|
117
|
+
private client?: mysql.Connection
|
|
124
118
|
public tables: Record<string, Table> = {}
|
|
125
119
|
public schemaErrors: Record<string, string> = {}
|
|
126
120
|
|
|
@@ -134,7 +128,8 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|
|
134
128
|
if (
|
|
135
129
|
config.rejectUnauthorized != null &&
|
|
136
130
|
!config.rejectUnauthorized &&
|
|
137
|
-
config.ssl
|
|
131
|
+
config.ssl &&
|
|
132
|
+
typeof config.ssl !== "string"
|
|
138
133
|
) {
|
|
139
134
|
config.ssl.rejectUnauthorized = config.rejectUnauthorized
|
|
140
135
|
}
|
|
@@ -160,6 +155,22 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|
|
160
155
|
}
|
|
161
156
|
}
|
|
162
157
|
|
|
158
|
+
async testConnection() {
|
|
159
|
+
const response: ConnectionInfo = {
|
|
160
|
+
connected: false,
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const [result] = await this.internalQuery(
|
|
164
|
+
{ sql: "SELECT 1+1 AS checkRes" },
|
|
165
|
+
{ connect: true }
|
|
166
|
+
)
|
|
167
|
+
response.connected = result?.checkRes == 2
|
|
168
|
+
} catch (e: any) {
|
|
169
|
+
response.error = e.message as string
|
|
170
|
+
}
|
|
171
|
+
return response
|
|
172
|
+
}
|
|
173
|
+
|
|
163
174
|
getBindingIdentifier(): string {
|
|
164
175
|
return "?"
|
|
165
176
|
}
|
|
@@ -173,7 +184,7 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|
|
173
184
|
}
|
|
174
185
|
|
|
175
186
|
async disconnect() {
|
|
176
|
-
await this.client
|
|
187
|
+
await this.client!.end()
|
|
177
188
|
}
|
|
178
189
|
|
|
179
190
|
async internalQuery(
|
|
@@ -192,10 +203,10 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|
|
192
203
|
? baseBindings
|
|
193
204
|
: bindingTypeCoerce(baseBindings)
|
|
194
205
|
// Node MySQL is callback based, so we must wrap our call in a promise
|
|
195
|
-
const response = await this.client
|
|
206
|
+
const response = await this.client!.query(query.sql, bindings)
|
|
196
207
|
return response[0]
|
|
197
208
|
} finally {
|
|
198
|
-
if (opts?.connect) {
|
|
209
|
+
if (opts?.connect && this.client) {
|
|
199
210
|
await this.disconnect()
|
|
200
211
|
}
|
|
201
212
|
}
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
SqlQuery,
|
|
8
8
|
Table,
|
|
9
9
|
DatasourcePlus,
|
|
10
|
+
DatasourceFeature,
|
|
11
|
+
ConnectionInfo,
|
|
10
12
|
} from "@budibase/types"
|
|
11
13
|
import {
|
|
12
14
|
buildExternalTableId,
|
|
@@ -24,12 +26,7 @@ import {
|
|
|
24
26
|
ExecuteOptions,
|
|
25
27
|
Result,
|
|
26
28
|
} from "oracledb"
|
|
27
|
-
import {
|
|
28
|
-
OracleTable,
|
|
29
|
-
OracleColumn,
|
|
30
|
-
OracleColumnsResponse,
|
|
31
|
-
OracleConstraint,
|
|
32
|
-
} from "./base/types"
|
|
29
|
+
import { OracleTable, OracleColumn, OracleColumnsResponse } from "./base/types"
|
|
33
30
|
let oracledb: any
|
|
34
31
|
try {
|
|
35
32
|
oracledb = require("oracledb")
|
|
@@ -53,6 +50,7 @@ const SCHEMA: Integration = {
|
|
|
53
50
|
type: "Relational",
|
|
54
51
|
description:
|
|
55
52
|
"Oracle Database is an object-relational database management system developed by Oracle Corporation",
|
|
53
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
56
54
|
datasource: {
|
|
57
55
|
host: {
|
|
58
56
|
type: DatasourceFieldType.STRING,
|
|
@@ -325,6 +323,30 @@ class OracleIntegration extends Sql implements DatasourcePlus {
|
|
|
325
323
|
this.schemaErrors = final.errors
|
|
326
324
|
}
|
|
327
325
|
|
|
326
|
+
async testConnection() {
|
|
327
|
+
const response: ConnectionInfo = {
|
|
328
|
+
connected: false,
|
|
329
|
+
}
|
|
330
|
+
let connection
|
|
331
|
+
try {
|
|
332
|
+
connection = await this.getConnection()
|
|
333
|
+
response.connected = true
|
|
334
|
+
} catch (err: any) {
|
|
335
|
+
response.connected = false
|
|
336
|
+
response.error = err.message
|
|
337
|
+
} finally {
|
|
338
|
+
if (connection) {
|
|
339
|
+
try {
|
|
340
|
+
await connection.close()
|
|
341
|
+
} catch (err: any) {
|
|
342
|
+
response.connected = false
|
|
343
|
+
response.error = err.message
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return response
|
|
348
|
+
}
|
|
349
|
+
|
|
328
350
|
private async internalQuery<T>(query: SqlQuery): Promise<Result<T>> {
|
|
329
351
|
let connection
|
|
330
352
|
try {
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
SqlQuery,
|
|
7
7
|
Table,
|
|
8
8
|
DatasourcePlus,
|
|
9
|
+
DatasourceFeature,
|
|
10
|
+
ConnectionInfo,
|
|
9
11
|
} from "@budibase/types"
|
|
10
12
|
import {
|
|
11
13
|
getSqlQuery,
|
|
@@ -18,7 +20,7 @@ import Sql from "./base/sql"
|
|
|
18
20
|
import { PostgresColumn } from "./base/types"
|
|
19
21
|
import { escapeDangerousCharacters } from "../utilities"
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
import { Client, types } from "pg"
|
|
22
24
|
|
|
23
25
|
// Return "date" and "timestamp" types as plain strings.
|
|
24
26
|
// This lets us reference the original stored timezone.
|
|
@@ -50,6 +52,7 @@ const SCHEMA: Integration = {
|
|
|
50
52
|
type: "Relational",
|
|
51
53
|
description:
|
|
52
54
|
"PostgreSQL, also known as Postgres, is a free and open-source relational database management system emphasizing extensibility and SQL compliance.",
|
|
55
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
53
56
|
datasource: {
|
|
54
57
|
host: {
|
|
55
58
|
type: DatasourceFieldType.STRING,
|
|
@@ -114,7 +117,7 @@ const SCHEMA: Integration = {
|
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
class PostgresIntegration extends Sql implements DatasourcePlus {
|
|
117
|
-
private readonly client:
|
|
120
|
+
private readonly client: Client
|
|
118
121
|
private readonly config: PostgresConfig
|
|
119
122
|
private index: number = 1
|
|
120
123
|
private open: boolean
|
|
@@ -150,6 +153,21 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
|
|
|
150
153
|
this.open = false
|
|
151
154
|
}
|
|
152
155
|
|
|
156
|
+
async testConnection() {
|
|
157
|
+
const response: ConnectionInfo = {
|
|
158
|
+
connected: false,
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
await this.openConnection()
|
|
162
|
+
response.connected = true
|
|
163
|
+
} catch (e: any) {
|
|
164
|
+
response.error = e.message as string
|
|
165
|
+
} finally {
|
|
166
|
+
await this.closeConnection()
|
|
167
|
+
}
|
|
168
|
+
return response
|
|
169
|
+
}
|
|
170
|
+
|
|
153
171
|
getBindingIdentifier(): string {
|
|
154
172
|
return `$${this.index++}`
|
|
155
173
|
}
|
|
@@ -163,7 +181,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
|
|
|
163
181
|
if (!this.config.schema) {
|
|
164
182
|
this.config.schema = "public"
|
|
165
183
|
}
|
|
166
|
-
this.client.query(`SET search_path TO ${this.config.schema}`)
|
|
184
|
+
await this.client.query(`SET search_path TO ${this.config.schema}`)
|
|
167
185
|
this.COLUMNS_SQL = `select * from information_schema.columns where table_schema = '${this.config.schema}'`
|
|
168
186
|
this.open = true
|
|
169
187
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ConnectionInfo,
|
|
3
|
+
DatasourceFeature,
|
|
4
|
+
DatasourceFieldType,
|
|
5
|
+
Integration,
|
|
6
|
+
QueryType,
|
|
7
|
+
} from "@budibase/types"
|
|
2
8
|
import Redis from "ioredis"
|
|
3
9
|
|
|
4
10
|
interface RedisConfig {
|
|
@@ -11,9 +17,11 @@ interface RedisConfig {
|
|
|
11
17
|
|
|
12
18
|
const SCHEMA: Integration = {
|
|
13
19
|
docs: "https://redis.io/docs/",
|
|
14
|
-
description:
|
|
20
|
+
description:
|
|
21
|
+
"Redis is a caching tool, providing powerful key-value store capabilities.",
|
|
15
22
|
friendlyName: "Redis",
|
|
16
23
|
type: "Non-relational",
|
|
24
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
17
25
|
datasource: {
|
|
18
26
|
host: {
|
|
19
27
|
type: "string",
|
|
@@ -86,7 +94,7 @@ const SCHEMA: Integration = {
|
|
|
86
94
|
|
|
87
95
|
class RedisIntegration {
|
|
88
96
|
private readonly config: RedisConfig
|
|
89
|
-
private client
|
|
97
|
+
private client
|
|
90
98
|
|
|
91
99
|
constructor(config: RedisConfig) {
|
|
92
100
|
this.config = config
|
|
@@ -99,6 +107,21 @@ class RedisIntegration {
|
|
|
99
107
|
})
|
|
100
108
|
}
|
|
101
109
|
|
|
110
|
+
async testConnection() {
|
|
111
|
+
const response: ConnectionInfo = {
|
|
112
|
+
connected: false,
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
await this.client.ping()
|
|
116
|
+
response.connected = true
|
|
117
|
+
} catch (e: any) {
|
|
118
|
+
response.error = e.message as string
|
|
119
|
+
} finally {
|
|
120
|
+
await this.disconnect()
|
|
121
|
+
}
|
|
122
|
+
return response
|
|
123
|
+
}
|
|
124
|
+
|
|
102
125
|
async disconnect() {
|
|
103
126
|
return this.client.quit()
|
|
104
127
|
}
|