@budibase/server 2.6.16-alpha.4 → 2.6.16-alpha.5
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.8bf0a95b.js → index.b9eeb2a8.js} +202 -202
- package/builder/index.html +1 -1
- 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/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 +16 -0
- 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/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/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 +16 -0
- 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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.6.16-alpha.
|
|
4
|
+
"version": "2.6.16-alpha.5",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
"license": "GPL-3.0",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@apidevtools/swagger-parser": "10.0.3",
|
|
48
|
-
"@budibase/backend-core": "2.6.16-alpha.
|
|
49
|
-
"@budibase/client": "2.6.16-alpha.
|
|
50
|
-
"@budibase/pro": "2.6.16-alpha.
|
|
51
|
-
"@budibase/shared-core": "2.6.16-alpha.
|
|
52
|
-
"@budibase/string-templates": "2.6.16-alpha.
|
|
53
|
-
"@budibase/types": "2.6.16-alpha.
|
|
48
|
+
"@budibase/backend-core": "2.6.16-alpha.5",
|
|
49
|
+
"@budibase/client": "2.6.16-alpha.5",
|
|
50
|
+
"@budibase/pro": "2.6.16-alpha.5",
|
|
51
|
+
"@budibase/shared-core": "2.6.16-alpha.5",
|
|
52
|
+
"@budibase/string-templates": "2.6.16-alpha.5",
|
|
53
|
+
"@budibase/types": "2.6.16-alpha.5",
|
|
54
54
|
"@bull-board/api": "3.7.0",
|
|
55
55
|
"@bull-board/koa": "3.9.4",
|
|
56
56
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"mysql2": "2.3.3",
|
|
100
100
|
"node-fetch": "2.6.7",
|
|
101
101
|
"open": "8.4.0",
|
|
102
|
-
"pg": "8.
|
|
102
|
+
"pg": "8.10.0",
|
|
103
103
|
"posthog-node": "1.3.0",
|
|
104
104
|
"pouchdb": "7.3.0",
|
|
105
105
|
"pouchdb-adapter-memory": "7.2.2",
|
|
@@ -141,6 +141,7 @@
|
|
|
141
141
|
"@types/node": "14.18.20",
|
|
142
142
|
"@types/node-fetch": "2.6.1",
|
|
143
143
|
"@types/oracledb": "5.2.2",
|
|
144
|
+
"@types/pg": "8.6.6",
|
|
144
145
|
"@types/pouchdb": "6.4.0",
|
|
145
146
|
"@types/redis": "4.0.11",
|
|
146
147
|
"@types/server-destroy": "1.0.1",
|
|
@@ -176,5 +177,5 @@
|
|
|
176
177
|
"optionalDependencies": {
|
|
177
178
|
"oracledb": "5.3.0"
|
|
178
179
|
},
|
|
179
|
-
"gitHead": "
|
|
180
|
+
"gitHead": "bbb516f26ae966668b5fa65418d81fbccf3dce37"
|
|
180
181
|
}
|
|
@@ -18,11 +18,71 @@ import {
|
|
|
18
18
|
Row,
|
|
19
19
|
CreateDatasourceResponse,
|
|
20
20
|
UpdateDatasourceResponse,
|
|
21
|
-
UpdateDatasourceRequest,
|
|
22
21
|
CreateDatasourceRequest,
|
|
22
|
+
VerifyDatasourceRequest,
|
|
23
|
+
VerifyDatasourceResponse,
|
|
24
|
+
IntegrationBase,
|
|
25
|
+
DatasourcePlus,
|
|
23
26
|
} from "@budibase/types"
|
|
24
27
|
import sdk from "../../sdk"
|
|
25
28
|
|
|
29
|
+
function getErrorTables(errors: any, errorType: string) {
|
|
30
|
+
return Object.entries(errors)
|
|
31
|
+
.filter(entry => entry[1] === errorType)
|
|
32
|
+
.map(([name]) => name)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function updateError(error: any, newError: any, tables: string[]) {
|
|
36
|
+
if (!error) {
|
|
37
|
+
error = ""
|
|
38
|
+
}
|
|
39
|
+
if (error.length > 0) {
|
|
40
|
+
error += "\n"
|
|
41
|
+
}
|
|
42
|
+
error += `${newError} ${tables.join(", ")}`
|
|
43
|
+
return error
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function getConnector(
|
|
47
|
+
datasource: Datasource
|
|
48
|
+
): Promise<IntegrationBase | DatasourcePlus> {
|
|
49
|
+
const Connector = await getIntegration(datasource.source)
|
|
50
|
+
// can't enrich if it doesn't have an ID yet
|
|
51
|
+
if (datasource._id) {
|
|
52
|
+
datasource = await sdk.datasources.enrich(datasource)
|
|
53
|
+
}
|
|
54
|
+
// Connect to the DB and build the schema
|
|
55
|
+
return new Connector(datasource.config)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function buildSchemaHelper(datasource: Datasource) {
|
|
59
|
+
const connector = (await getConnector(datasource)) as DatasourcePlus
|
|
60
|
+
await connector.buildSchema(datasource._id!, datasource.entities!)
|
|
61
|
+
|
|
62
|
+
const errors = connector.schemaErrors
|
|
63
|
+
let error = null
|
|
64
|
+
if (errors && Object.keys(errors).length > 0) {
|
|
65
|
+
const noKey = getErrorTables(errors, BuildSchemaErrors.NO_KEY)
|
|
66
|
+
const invalidCol = getErrorTables(errors, BuildSchemaErrors.INVALID_COLUMN)
|
|
67
|
+
if (noKey.length) {
|
|
68
|
+
error = updateError(
|
|
69
|
+
error,
|
|
70
|
+
"No primary key constraint found for the following:",
|
|
71
|
+
noKey
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
if (invalidCol.length) {
|
|
75
|
+
const invalidCols = Object.values(InvalidColumns).join(", ")
|
|
76
|
+
error = updateError(
|
|
77
|
+
error,
|
|
78
|
+
`Cannot use columns ${invalidCols} found in following:`,
|
|
79
|
+
invalidCol
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { tables: connector.tables, error }
|
|
84
|
+
}
|
|
85
|
+
|
|
26
86
|
export async function fetch(ctx: UserCtx) {
|
|
27
87
|
// Get internal tables
|
|
28
88
|
const db = context.getAppDB()
|
|
@@ -66,6 +126,33 @@ export async function fetch(ctx: UserCtx) {
|
|
|
66
126
|
ctx.body = [bbInternalDb, ...datasources]
|
|
67
127
|
}
|
|
68
128
|
|
|
129
|
+
export async function verify(
|
|
130
|
+
ctx: UserCtx<VerifyDatasourceRequest, VerifyDatasourceResponse>
|
|
131
|
+
) {
|
|
132
|
+
const { datasource } = ctx.request.body
|
|
133
|
+
let existingDatasource: undefined | Datasource
|
|
134
|
+
if (datasource._id) {
|
|
135
|
+
existingDatasource = await sdk.datasources.get(datasource._id)
|
|
136
|
+
}
|
|
137
|
+
let enrichedDatasource = datasource
|
|
138
|
+
if (existingDatasource) {
|
|
139
|
+
enrichedDatasource = sdk.datasources.mergeConfigs(
|
|
140
|
+
datasource,
|
|
141
|
+
existingDatasource
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
const connector = await getConnector(enrichedDatasource)
|
|
145
|
+
if (!connector.testConnection) {
|
|
146
|
+
ctx.throw(400, "Connection information verification not supported")
|
|
147
|
+
}
|
|
148
|
+
const response = await connector.testConnection()
|
|
149
|
+
|
|
150
|
+
ctx.body = {
|
|
151
|
+
connected: response.connected,
|
|
152
|
+
error: response.error,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
69
156
|
export async function buildSchemaFromDb(ctx: UserCtx) {
|
|
70
157
|
const db = context.getAppDB()
|
|
71
158
|
const datasource = await sdk.datasources.get(ctx.params.datasourceId)
|
|
@@ -311,51 +398,3 @@ export async function query(ctx: UserCtx) {
|
|
|
311
398
|
ctx.throw(400, err)
|
|
312
399
|
}
|
|
313
400
|
}
|
|
314
|
-
|
|
315
|
-
function getErrorTables(errors: any, errorType: string) {
|
|
316
|
-
return Object.entries(errors)
|
|
317
|
-
.filter(entry => entry[1] === errorType)
|
|
318
|
-
.map(([name]) => name)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
function updateError(error: any, newError: any, tables: string[]) {
|
|
322
|
-
if (!error) {
|
|
323
|
-
error = ""
|
|
324
|
-
}
|
|
325
|
-
if (error.length > 0) {
|
|
326
|
-
error += "\n"
|
|
327
|
-
}
|
|
328
|
-
error += `${newError} ${tables.join(", ")}`
|
|
329
|
-
return error
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async function buildSchemaHelper(datasource: Datasource) {
|
|
333
|
-
const Connector = await getIntegration(datasource.source)
|
|
334
|
-
datasource = await sdk.datasources.enrich(datasource)
|
|
335
|
-
// Connect to the DB and build the schema
|
|
336
|
-
const connector = new Connector(datasource.config)
|
|
337
|
-
await connector.buildSchema(datasource._id, datasource.entities)
|
|
338
|
-
|
|
339
|
-
const errors = connector.schemaErrors
|
|
340
|
-
let error = null
|
|
341
|
-
if (errors && Object.keys(errors).length > 0) {
|
|
342
|
-
const noKey = getErrorTables(errors, BuildSchemaErrors.NO_KEY)
|
|
343
|
-
const invalidCol = getErrorTables(errors, BuildSchemaErrors.INVALID_COLUMN)
|
|
344
|
-
if (noKey.length) {
|
|
345
|
-
error = updateError(
|
|
346
|
-
error,
|
|
347
|
-
"No primary key constraint found for the following:",
|
|
348
|
-
noKey
|
|
349
|
-
)
|
|
350
|
-
}
|
|
351
|
-
if (invalidCol.length) {
|
|
352
|
-
const invalidCols = Object.values(InvalidColumns).join(", ")
|
|
353
|
-
error = updateError(
|
|
354
|
-
error,
|
|
355
|
-
`Cannot use columns ${invalidCols} found in following:`,
|
|
356
|
-
invalidCol
|
|
357
|
-
)
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return { tables: connector.tables, error }
|
|
361
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDefinitions } from "../../integrations"
|
|
1
|
+
import { getDefinition, getDefinitions } from "../../integrations"
|
|
2
2
|
import { BBContext } from "@budibase/types"
|
|
3
3
|
|
|
4
4
|
export async function fetch(ctx: BBContext) {
|
|
@@ -7,7 +7,7 @@ export async function fetch(ctx: BBContext) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export async function find(ctx: BBContext) {
|
|
10
|
-
const
|
|
10
|
+
const def = await getDefinition(ctx.params.type)
|
|
11
|
+
ctx.body = def
|
|
11
12
|
ctx.status = 200
|
|
12
|
-
ctx.body = defs[ctx.params.type]
|
|
13
13
|
}
|
package/src/db/dynamoClient.ts
CHANGED
|
@@ -140,7 +140,7 @@ export function init(endpoint: string) {
|
|
|
140
140
|
docClient = new AWS.DynamoDB.DocumentClient(docClientParams)
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
if (!env.isProd()) {
|
|
143
|
+
if (!env.isProd() && !env.isJest()) {
|
|
144
144
|
env._set("AWS_ACCESS_KEY_ID", "KEY_ID")
|
|
145
145
|
env._set("AWS_SECRET_ACCESS_KEY", "SECRET_KEY")
|
|
146
146
|
init("http://localhost:8333")
|
|
@@ -19,7 +19,6 @@ import _ from "lodash"
|
|
|
19
19
|
import { generator } from "@budibase/backend-core/tests"
|
|
20
20
|
import { utils } from "@budibase/backend-core"
|
|
21
21
|
import { GenericContainer } from "testcontainers"
|
|
22
|
-
import { generateRowIdField } from "../integrations/utils"
|
|
23
22
|
|
|
24
23
|
const config = setup.getConfig()!
|
|
25
24
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
ConnectionInfo,
|
|
3
|
+
DatasourceFeature,
|
|
3
4
|
DatasourceFieldType,
|
|
4
|
-
|
|
5
|
+
Integration,
|
|
5
6
|
IntegrationBase,
|
|
7
|
+
QueryType,
|
|
6
8
|
} from "@budibase/types"
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
import Airtable from "airtable"
|
|
9
11
|
|
|
10
12
|
interface AirtableConfig {
|
|
11
13
|
apiKey: string
|
|
@@ -18,6 +20,7 @@ const SCHEMA: Integration = {
|
|
|
18
20
|
"Airtable is a spreadsheet-database hybrid, with the features of a database but applied to a spreadsheet.",
|
|
19
21
|
friendlyName: "Airtable",
|
|
20
22
|
type: "Spreadsheet",
|
|
23
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
21
24
|
datasource: {
|
|
22
25
|
apiKey: {
|
|
23
26
|
type: DatasourceFieldType.PASSWORD,
|
|
@@ -81,13 +84,37 @@ const SCHEMA: Integration = {
|
|
|
81
84
|
|
|
82
85
|
class AirtableIntegration implements IntegrationBase {
|
|
83
86
|
private config: AirtableConfig
|
|
84
|
-
private client
|
|
87
|
+
private client
|
|
85
88
|
|
|
86
89
|
constructor(config: AirtableConfig) {
|
|
87
90
|
this.config = config
|
|
88
91
|
this.client = new Airtable(config).base(config.base)
|
|
89
92
|
}
|
|
90
93
|
|
|
94
|
+
async testConnection(): Promise<ConnectionInfo> {
|
|
95
|
+
const mockTable = Date.now().toString()
|
|
96
|
+
try {
|
|
97
|
+
await this.client.makeRequest({
|
|
98
|
+
path: `/${mockTable}`,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return { connected: true }
|
|
102
|
+
} catch (e: any) {
|
|
103
|
+
if (
|
|
104
|
+
e.message ===
|
|
105
|
+
`Could not find table ${mockTable} in application ${this.config.base}`
|
|
106
|
+
) {
|
|
107
|
+
// The request managed to check the application, so the credentials are valid
|
|
108
|
+
return { connected: true }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
connected: false,
|
|
113
|
+
error: e.message as string,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
91
118
|
async create(query: { table: any; json: any }) {
|
|
92
119
|
const { table, json } = query
|
|
93
120
|
|
|
@@ -3,9 +3,11 @@ import {
|
|
|
3
3
|
DatasourceFieldType,
|
|
4
4
|
QueryType,
|
|
5
5
|
IntegrationBase,
|
|
6
|
+
DatasourceFeature,
|
|
7
|
+
ConnectionInfo,
|
|
6
8
|
} from "@budibase/types"
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
import { Database, aql } from "arangojs"
|
|
9
11
|
|
|
10
12
|
interface ArangodbConfig {
|
|
11
13
|
url: string
|
|
@@ -21,6 +23,7 @@ const SCHEMA: Integration = {
|
|
|
21
23
|
type: "Non-relational",
|
|
22
24
|
description:
|
|
23
25
|
"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. ",
|
|
26
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
24
27
|
datasource: {
|
|
25
28
|
url: {
|
|
26
29
|
type: DatasourceFieldType.STRING,
|
|
@@ -58,7 +61,7 @@ const SCHEMA: Integration = {
|
|
|
58
61
|
|
|
59
62
|
class ArangoDBIntegration implements IntegrationBase {
|
|
60
63
|
private config: ArangodbConfig
|
|
61
|
-
private client
|
|
64
|
+
private client
|
|
62
65
|
|
|
63
66
|
constructor(config: ArangodbConfig) {
|
|
64
67
|
const newConfig = {
|
|
@@ -74,6 +77,19 @@ class ArangoDBIntegration implements IntegrationBase {
|
|
|
74
77
|
this.client = new Database(newConfig)
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
async testConnection() {
|
|
81
|
+
const response: ConnectionInfo = {
|
|
82
|
+
connected: false,
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
await this.client.get()
|
|
86
|
+
response.connected = true
|
|
87
|
+
} catch (e: any) {
|
|
88
|
+
response.error = e.message as string
|
|
89
|
+
}
|
|
90
|
+
return response
|
|
91
|
+
}
|
|
92
|
+
|
|
77
93
|
async read(query: { sql: any }) {
|
|
78
94
|
try {
|
|
79
95
|
const result = await this.client.query(query.sql)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ConnectionInfo,
|
|
3
|
+
DatasourceFeature,
|
|
2
4
|
DatasourceFieldType,
|
|
3
5
|
Document,
|
|
4
6
|
Integration,
|
|
@@ -18,6 +20,7 @@ const SCHEMA: Integration = {
|
|
|
18
20
|
type: "Non-relational",
|
|
19
21
|
description:
|
|
20
22
|
"Apache CouchDB is an open-source document-oriented NoSQL database, implemented in Erlang.",
|
|
23
|
+
features: [DatasourceFeature.CONNECTION_CHECKING],
|
|
21
24
|
datasource: {
|
|
22
25
|
url: {
|
|
23
26
|
type: DatasourceFieldType.STRING,
|
|
@@ -61,21 +64,32 @@ const SCHEMA: Integration = {
|
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
class CouchDBIntegration implements IntegrationBase {
|
|
64
|
-
private
|
|
65
|
-
private readonly client: any
|
|
67
|
+
private readonly client: dbCore.DatabaseImpl
|
|
66
68
|
|
|
67
69
|
constructor(config: CouchDBConfig) {
|
|
68
|
-
this.config = config
|
|
69
70
|
this.client = dbCore.DatabaseWithConnection(config.database, config.url)
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
async testConnection() {
|
|
74
|
+
const response: ConnectionInfo = {
|
|
75
|
+
connected: false,
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const result = await this.query("exists", "validation error", {})
|
|
79
|
+
response.connected = result === true
|
|
80
|
+
} catch (e: any) {
|
|
81
|
+
response.error = e.message as string
|
|
82
|
+
}
|
|
83
|
+
return response
|
|
84
|
+
}
|
|
85
|
+
|
|
72
86
|
async query(
|
|
73
87
|
command: string,
|
|
74
88
|
errorMsg: string,
|
|
75
89
|
query: { json?: object; id?: string }
|
|
76
90
|
) {
|
|
77
91
|
try {
|
|
78
|
-
return await this.client[command](query.id || query.json)
|
|
92
|
+
return await (this.client as any)[command](query.id || query.json)
|
|
79
93
|
} catch (err) {
|
|
80
94
|
console.error(errorMsg, err)
|
|
81
95
|
throw err
|
|
@@ -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,
|
|
@@ -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
|
}
|
|
@@ -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 {
|