Merge pull request #1070 from Budibase/bug/integration-fixes
Some data source/integration fixes
This commit is contained in:
commit
03fe6af077
|
@ -119,6 +119,18 @@ export const getBackendUiStore = () => {
|
||||||
return json
|
return json
|
||||||
},
|
},
|
||||||
save: async (datasourceId, query) => {
|
save: async (datasourceId, query) => {
|
||||||
|
const integrations = get(store).integrations
|
||||||
|
const dataSource = get(store).datasources.filter(
|
||||||
|
ds => ds._id === datasourceId
|
||||||
|
)
|
||||||
|
// check if readable attribute is found
|
||||||
|
if (dataSource.length !== 0) {
|
||||||
|
const integration = integrations[dataSource[0].source]
|
||||||
|
const readable = integration.query[query.queryVerb].readable
|
||||||
|
if (readable) {
|
||||||
|
query.readable = readable
|
||||||
|
}
|
||||||
|
}
|
||||||
query.datasourceId = datasourceId
|
query.datasourceId = datasourceId
|
||||||
const response = await api.post(`/api/queries`, query)
|
const response = await api.post(`/api/queries`, query)
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
return [...acc, ...viewsArr]
|
return [...acc, ...viewsArr]
|
||||||
}, [])
|
}, [])
|
||||||
$: queries = $backendUiStore.queries
|
$: queries = $backendUiStore.queries
|
||||||
.filter(query => query.queryVerb === "read")
|
.filter(query => query.queryVerb === "read" || query.readable)
|
||||||
.map(query => ({
|
.map(query => ({
|
||||||
label: query.name,
|
label: query.name,
|
||||||
name: query.name,
|
name: query.name,
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
const handlebars = require("handlebars")
|
const { processString } = require("@budibase/string-templates")
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
const { generateQueryID, getQueryParams } = require("../../db/utils")
|
const { generateQueryID, getQueryParams } = require("../../db/utils")
|
||||||
const { integrations } = require("../../integrations")
|
const { integrations } = require("../../integrations")
|
||||||
|
|
||||||
|
function formatResponse(resp) {
|
||||||
|
if (typeof resp === "string") {
|
||||||
|
resp = JSON.parse(resp)
|
||||||
|
}
|
||||||
|
if (!Array.isArray(resp)) {
|
||||||
|
resp = [resp]
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
exports.fetch = async function(ctx) {
|
exports.fetch = async function(ctx) {
|
||||||
const db = new CouchDB(ctx.user.appId)
|
const db = new CouchDB(ctx.user.appId)
|
||||||
|
|
||||||
|
@ -29,19 +39,22 @@ exports.save = async function(ctx) {
|
||||||
ctx.message = `Query ${query.name} saved successfully.`
|
ctx.message = `Query ${query.name} saved successfully.`
|
||||||
}
|
}
|
||||||
|
|
||||||
function enrichQueryFields(fields, parameters) {
|
async function enrichQueryFields(fields, parameters) {
|
||||||
const enrichedQuery = {}
|
const enrichedQuery = {}
|
||||||
|
|
||||||
// enrich the fields with dynamic parameters
|
// enrich the fields with dynamic parameters
|
||||||
for (let key in fields) {
|
for (let key of Object.keys(fields)) {
|
||||||
const template = handlebars.compile(fields[key])
|
enrichedQuery[key] = await processString(fields[key], parameters)
|
||||||
enrichedQuery[key] = template(parameters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enrichedQuery.json || enrichedQuery.customData) {
|
if (enrichedQuery.json || enrichedQuery.customData) {
|
||||||
enrichedQuery.json = JSON.parse(
|
try {
|
||||||
enrichedQuery.json || enrichedQuery.customData
|
enrichedQuery.json = JSON.parse(
|
||||||
)
|
enrichedQuery.json || enrichedQuery.customData
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
throw { message: `JSON Invalid - error: ${err}` }
|
||||||
|
}
|
||||||
delete enrichedQuery.customData
|
delete enrichedQuery.customData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +75,11 @@ exports.preview = async function(ctx) {
|
||||||
|
|
||||||
const { fields, parameters, queryVerb } = ctx.request.body
|
const { fields, parameters, queryVerb } = ctx.request.body
|
||||||
|
|
||||||
const enrichedQuery = enrichQueryFields(fields, parameters)
|
const enrichedQuery = await enrichQueryFields(fields, parameters)
|
||||||
|
|
||||||
ctx.body = await new Integration(datasource.config)[queryVerb](enrichedQuery)
|
ctx.body = formatResponse(
|
||||||
|
await new Integration(datasource.config)[queryVerb](enrichedQuery)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.execute = async function(ctx) {
|
exports.execute = async function(ctx) {
|
||||||
|
@ -80,17 +95,15 @@ exports.execute = async function(ctx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const enrichedQuery = enrichQueryFields(
|
const enrichedQuery = await enrichQueryFields(
|
||||||
query.fields,
|
query.fields,
|
||||||
ctx.request.body.parameters
|
ctx.request.body.parameters
|
||||||
)
|
)
|
||||||
|
|
||||||
// call the relevant CRUD method on the integration class
|
// call the relevant CRUD method on the integration class
|
||||||
const response = await new Integration(datasource.config)[query.queryVerb](
|
ctx.body = formatResponse(
|
||||||
enrichedQuery
|
await new Integration(datasource.config)[query.queryVerb](enrichedQuery)
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx.body = response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async function(ctx) {
|
exports.destroy = async function(ctx) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ function generateQueryValidation() {
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
fields: Joi.object().required(),
|
fields: Joi.object().required(),
|
||||||
datasourceId: Joi.string().required(),
|
datasourceId: Joi.string().required(),
|
||||||
|
readable: Joi.boolean(),
|
||||||
parameters: Joi.array().items(Joi.object({
|
parameters: Joi.array().items(Joi.object({
|
||||||
name: Joi.string(),
|
name: Joi.string(),
|
||||||
default: Joi.string()
|
default: Joi.string()
|
||||||
|
|
|
@ -17,20 +17,27 @@ const SCHEMA = {
|
||||||
type: FIELD_TYPES.PASSWORD,
|
type: FIELD_TYPES.PASSWORD,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
endpoint: {
|
||||||
|
type: FIELD_TYPES.STRING,
|
||||||
|
required: false,
|
||||||
|
default: "https://dynamodb.us-east-1.amazonaws.com",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
create: {
|
create: {
|
||||||
type: QUERY_TYPES.FIELDS,
|
type: QUERY_TYPES.FIELDS,
|
||||||
|
customisable: true,
|
||||||
fields: {
|
fields: {
|
||||||
table: {
|
table: {
|
||||||
type: FIELD_TYPES.STRING,
|
type: FIELD_TYPES.STRING,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
customisable: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
read: {
|
read: {
|
||||||
type: QUERY_TYPES.FIELDS,
|
type: QUERY_TYPES.FIELDS,
|
||||||
|
customisable: true,
|
||||||
|
readable: true,
|
||||||
fields: {
|
fields: {
|
||||||
table: {
|
table: {
|
||||||
type: FIELD_TYPES.STRING,
|
type: FIELD_TYPES.STRING,
|
||||||
|
@ -39,30 +46,51 @@ const SCHEMA = {
|
||||||
index: {
|
index: {
|
||||||
type: FIELD_TYPES.STRING,
|
type: FIELD_TYPES.STRING,
|
||||||
},
|
},
|
||||||
customisable: true,
|
},
|
||||||
|
},
|
||||||
|
scan: {
|
||||||
|
type: QUERY_TYPES.FIELDS,
|
||||||
|
customisable: true,
|
||||||
|
readable: true,
|
||||||
|
fields: {
|
||||||
|
table: {
|
||||||
|
type: FIELD_TYPES.STRING,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: FIELD_TYPES.STRING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get: {
|
||||||
|
type: QUERY_TYPES.FIELDS,
|
||||||
|
customisable: true,
|
||||||
|
readable: true,
|
||||||
|
fields: {
|
||||||
|
table: {
|
||||||
|
type: FIELD_TYPES.STRING,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
type: QUERY_TYPES.FIELDS,
|
type: QUERY_TYPES.FIELDS,
|
||||||
|
customisable: true,
|
||||||
fields: {
|
fields: {
|
||||||
table: {
|
table: {
|
||||||
type: FIELD_TYPES.STRING,
|
type: FIELD_TYPES.STRING,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
customisable: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
type: QUERY_TYPES.FIELDS,
|
type: QUERY_TYPES.FIELDS,
|
||||||
|
customisable: true,
|
||||||
fields: {
|
fields: {
|
||||||
table: {
|
table: {
|
||||||
type: FIELD_TYPES.STRING,
|
type: FIELD_TYPES.STRING,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
key: {
|
|
||||||
type: FIELD_TYPES.STRING,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -72,7 +100,15 @@ class DynamoDBIntegration {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.connect()
|
this.connect()
|
||||||
this.client = new AWS.DynamoDB.DocumentClient()
|
let options = {
|
||||||
|
correctClockSkew: true,
|
||||||
|
}
|
||||||
|
if (config.endpoint) {
|
||||||
|
options.endpoint = config.endpoint
|
||||||
|
}
|
||||||
|
this.client = new AWS.DynamoDB.DocumentClient({
|
||||||
|
correctClockSkew: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
|
@ -80,37 +116,65 @@ class DynamoDBIntegration {
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(query) {
|
async create(query) {
|
||||||
const response = await this.client.query({
|
const params = {
|
||||||
TableName: query.table,
|
TableName: query.table,
|
||||||
Item: query.json,
|
...query.json,
|
||||||
})
|
}
|
||||||
return response
|
return this.client.put(params).promise()
|
||||||
}
|
}
|
||||||
|
|
||||||
async read(query) {
|
async read(query) {
|
||||||
const response = await this.client.query({
|
const params = {
|
||||||
TableName: query.Table,
|
TableName: query.table,
|
||||||
...query.json,
|
...query.json,
|
||||||
})
|
}
|
||||||
|
if (query.index) {
|
||||||
|
params.IndexName = query.index
|
||||||
|
}
|
||||||
|
const response = await this.client.query(params).promise()
|
||||||
|
if (response.Items) {
|
||||||
|
return response.Items
|
||||||
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async scan(query) {
|
||||||
|
const params = {
|
||||||
|
TableName: query.table,
|
||||||
|
...query.json,
|
||||||
|
}
|
||||||
|
if (query.index) {
|
||||||
|
params.IndexName = query.index
|
||||||
|
}
|
||||||
|
const response = await this.client.scan(params).promise()
|
||||||
|
if (response.Items) {
|
||||||
|
return response.Items
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(query) {
|
||||||
|
const params = {
|
||||||
|
TableName: query.table,
|
||||||
|
...query.json,
|
||||||
|
}
|
||||||
|
return this.client.get(params).promise()
|
||||||
|
}
|
||||||
|
|
||||||
async update(query) {
|
async update(query) {
|
||||||
const response = await this.client.query({
|
const params = {
|
||||||
TableName: query.Table,
|
TableName: query.Table,
|
||||||
...query.json,
|
...query.json,
|
||||||
})
|
}
|
||||||
return response
|
return this.client.update(params).promise()
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(query) {
|
async delete(query) {
|
||||||
const response = await this.client.query({
|
const params = {
|
||||||
TableName: query.Table,
|
TableName: query.table,
|
||||||
Key: {
|
...query.json,
|
||||||
id: query.key,
|
}
|
||||||
},
|
return this.client.delete(params).promise()
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,9 +40,9 @@
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@budibase/bbui@^1.55.1":
|
"@budibase/bbui@^1.55.1":
|
||||||
version "1.55.1"
|
version "1.56.2"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.55.1.tgz#291fb6fa10479b49f078d3a911ad0ed42c2e6b12"
|
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.56.2.tgz#bb8f7d9b9b5ed06a22df877fbe028780d7602471"
|
||||||
integrity sha512-bxsHBwkOqCtuFz89e0hAXwvwycfS4xPPrEge5PxK1Lh3uqetO4bXoIxYaIDjfi2Ku7CYIzEmOwSloNaQWeTF4g==
|
integrity sha512-cWYkT1FNwNGTjisxtC5/MlQ1zeu7MYbMJsD6UyCEW3Ku6JIQZ6jyOkV6HKrmNND8VzVfddEGpzR37q+NoDpDFQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
markdown-it "^12.0.2"
|
markdown-it "^12.0.2"
|
||||||
quill "^1.3.7"
|
quill "^1.3.7"
|
||||||
|
@ -1034,7 +1034,12 @@ fill-range@^7.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range "^5.0.1"
|
to-regex-range "^5.0.1"
|
||||||
|
|
||||||
flatpickr@^4.5.2, flatpickr@^4.6.6:
|
flatpickr@^4.5.2:
|
||||||
|
version "4.6.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/flatpickr/-/flatpickr-4.6.9.tgz#9a13383e8a6814bda5d232eae3fcdccb97dc1499"
|
||||||
|
integrity sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==
|
||||||
|
|
||||||
|
flatpickr@^4.6.6:
|
||||||
version "4.6.6"
|
version "4.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/flatpickr/-/flatpickr-4.6.6.tgz#34d2ad80adfa34254e62583a34264d472f1038d6"
|
resolved "https://registry.yarnpkg.com/flatpickr/-/flatpickr-4.6.6.tgz#34d2ad80adfa34254e62583a34264d472f1038d6"
|
||||||
integrity sha512-EZ48CJMttMg3maMhJoX+GvTuuEhX/RbA1YeuI19attP3pwBdbYy6+yqAEVm0o0hSBFYBiLbVxscLW6gJXq6H3A==
|
integrity sha512-EZ48CJMttMg3maMhJoX+GvTuuEhX/RbA1YeuI19attP3pwBdbYy6+yqAEVm0o0hSBFYBiLbVxscLW6gJXq6H3A==
|
||||||
|
@ -1558,9 +1563,9 @@ loader-utils@^1.1.0:
|
||||||
json5 "^1.0.1"
|
json5 "^1.0.1"
|
||||||
|
|
||||||
local-access@^1.0.1:
|
local-access@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.0.1.tgz#5121258146d64e869046c642ea4f1dd39ff942bb"
|
resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.1.0.tgz#e007c76ba2ca83d5877ba1a125fc8dfe23ba4798"
|
||||||
integrity sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA==
|
integrity sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==
|
||||||
|
|
||||||
lodash.camelcase@^4.3.0:
|
lodash.camelcase@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
|
@ -1648,9 +1653,9 @@ miller-rabin@^4.0.0:
|
||||||
brorand "^1.0.1"
|
brorand "^1.0.1"
|
||||||
|
|
||||||
mime@^2.3.1:
|
mime@^2.3.1:
|
||||||
version "2.4.6"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
|
resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.0.tgz#2b4af934401779806ee98026bb42e8c1ae1876b1"
|
||||||
integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
|
integrity sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==
|
||||||
|
|
||||||
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
|
@ -2481,9 +2486,9 @@ rollup@^2.11.2:
|
||||||
fsevents "~2.1.2"
|
fsevents "~2.1.2"
|
||||||
|
|
||||||
sade@^1.4.0:
|
sade@^1.4.0:
|
||||||
version "1.7.3"
|
version "1.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.3.tgz#a217ccc4fb4abb2d271648bf48f6628b2636fa1b"
|
resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.4.tgz#ea681e0c65d248d2095c90578c03ca0bb1b54691"
|
||||||
integrity sha512-m4BctppMvJ60W1dXnHq7jMmFe3hPJZDAH85kQ3ACTo7XZNVUuTItCQ+2HfyaMeV5cKrbw7l4vD/6We3GBxvdJw==
|
integrity sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==
|
||||||
dependencies:
|
dependencies:
|
||||||
mri "^1.1.0"
|
mri "^1.1.0"
|
||||||
|
|
||||||
|
|
|
@ -302,6 +302,11 @@ describe("Cover a few complex use cases", () => {
|
||||||
expect(validity).toBe(true)
|
expect(validity).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should make sure object functions check out valid", () => {
|
||||||
|
const validity = isValid("{{ JSONstringify obj }}")
|
||||||
|
expect(validity).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
it("should be able to solve an example from docs", async () => {
|
it("should be able to solve an example from docs", async () => {
|
||||||
const output = await processString(`{{first ( split "a-b-c" "-") 2}}`, {})
|
const output = await processString(`{{first ( split "a-b-c" "-") 2}}`, {})
|
||||||
expect(output).toBe(`a,b`)
|
expect(output).toBe(`a,b`)
|
||||||
|
|
Loading…
Reference in New Issue