@@ -156,7 +160,10 @@
-
+
diff --git a/packages/builder/src/components/integration/index.svelte b/packages/builder/src/components/integration/index.svelte
index 9e3e9aaa08..b0003ef2ef 100644
--- a/packages/builder/src/components/integration/index.svelte
+++ b/packages/builder/src/components/integration/index.svelte
@@ -2,6 +2,7 @@
import { TextArea, Label, Input, Heading, Spacer } from "@budibase/bbui"
import Editor from "./SvelteEditor.svelte"
import ParameterBuilder from "./QueryParameterBuilder.svelte"
+ import FieldsBuilder from "./QueryFieldsBuilder.svelte"
const QueryTypes = {
SQL: "sql",
@@ -10,9 +11,10 @@
}
export let query
+ export let schema
function updateQuery({ detail }) {
- query.queryString = detail.value
+ query.fields.sql = detail.value
}
@@ -22,20 +24,19 @@
Query
-{#if query.queryType === QueryTypes.SQL}
-
+{#if schema.type === QueryTypes.SQL}
-{:else if query.queryType === QueryTypes.JSON}
+ value={query.fields.sql} />
+{:else if schema.type === QueryTypes.JSON}
-{:else if query.queryType === QueryTypes.FIELDS}
-
+ value={query.fields.json} />
+{:else if schema.type === QueryTypes.FIELDS}
+
{/if}
diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/ExecuteQuery.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/ExecuteQuery.svelte
index 2cbfbcd6e3..910fa1e593 100644
--- a/packages/builder/src/components/userInterface/EventsEditor/actions/ExecuteQuery.svelte
+++ b/packages/builder/src/components/userInterface/EventsEditor/actions/ExecuteQuery.svelte
@@ -57,7 +57,9 @@
bind:customParams={parameters.queryParams}
parameters={query.parameters}
bindings={bindableProperties} />
-
{query.queryString}
+ {#if query.fields.sql}
+
{query.fields.queryString}
+ {/if}
{/if}
diff --git a/packages/builder/src/pages/[application]/data/datasource/[selectedDatasource]/[query]/index.svelte b/packages/builder/src/pages/[application]/data/datasource/[selectedDatasource]/[query]/index.svelte
index c10813076e..bc2cae7537 100644
--- a/packages/builder/src/pages/[application]/data/datasource/[selectedDatasource]/[query]/index.svelte
+++ b/packages/builder/src/pages/[application]/data/datasource/[selectedDatasource]/[query]/index.svelte
@@ -26,6 +26,7 @@
datasourceId: $params.selectedDatasource,
name: "New Query",
parameters: [],
+ fields: {},
}
}
}
diff --git a/packages/server/src/api/controllers/query.js b/packages/server/src/api/controllers/query.js
index d967c83d09..257e644b3c 100644
--- a/packages/server/src/api/controllers/query.js
+++ b/packages/server/src/api/controllers/query.js
@@ -29,18 +29,20 @@ exports.save = async function(ctx) {
ctx.message = `Query ${query.name} saved successfully.`
}
-exports.preview = async function(ctx) {
- const { query, datasourceId, parameters, queryVerb } = ctx.request.body
-
- let parsedQuery = ""
- if (query) {
- const queryTemplate = handlebars.compile(query)
- parsedQuery = queryTemplate(parameters)
+function enrichQueryFields(fields, parameters) {
+ const enrichedQuery = {}
+ // enrich the fields with dynamic parameters
+ for (let key in fields) {
+ const template = handlebars.compile(fields[key])
+ enrichedQuery[key] = template(parameters)
}
+ return enrichedQuery
+}
+exports.preview = async function(ctx) {
const db = new CouchDB(ctx.user.appId)
- const datasource = await db.get(datasourceId)
+ const datasource = await db.get(ctx.request.body.datasourceId)
const Integration = integrations[datasource.source]
@@ -49,7 +51,11 @@ exports.preview = async function(ctx) {
return
}
- ctx.body = await new Integration(datasource.config, parsedQuery)[queryVerb]()
+ const { fields, parameters, queryVerb } = ctx.request.body
+
+ const enrichedQuery = enrichQueryFields(fields, parameters)
+
+ ctx.body = await new Integration(datasource.config)[queryVerb](enrichedQuery)
}
exports.execute = async function(ctx) {
@@ -58,10 +64,6 @@ exports.execute = async function(ctx) {
const query = await db.get(ctx.params.queryId)
const datasource = await db.get(query.datasourceId)
- const queryTemplate = handlebars.compile(query.queryString)
-
- const parsedQuery = queryTemplate(ctx.request.body.parameters)
-
const Integration = integrations[datasource.source]
if (!Integration) {
@@ -69,10 +71,15 @@ exports.execute = async function(ctx) {
return
}
+ const enrichedQuery = enrichQueryFields(
+ query.fields,
+ ctx.request.body.parameters
+ )
+
// call the relevant CRUD method on the integration class
- const response = await new Integration(datasource.config, parsedQuery)[
- query.queryVerb
- ]()
+ const response = await new Integration(datasource.config)[query.queryVerb](
+ enrichedQuery
+ )
ctx.body = response
}
diff --git a/packages/server/src/api/routes/query.js b/packages/server/src/api/routes/query.js
index 8d1526f1e2..62ddc83ac0 100644
--- a/packages/server/src/api/routes/query.js
+++ b/packages/server/src/api/routes/query.js
@@ -24,7 +24,7 @@ function generateQueryValidation() {
_id: Joi.string(),
_rev: Joi.string(),
name: Joi.string().required(),
- queryString: Joi.string().required(),
+ fields: Joi.object().required(),
datasourceId: Joi.string().required(),
parameters: Joi.array().items(Joi.object({
name: Joi.string(),
@@ -39,7 +39,7 @@ function generateQueryValidation() {
function generateQueryPreviewValidation() {
// prettier-ignore
return joiValidator.body(Joi.object({
- query: Joi.string(),
+ fields: Joi.object().required(),
queryVerb: Joi.string().allow(...Object.values(QueryVerb)).required(),
datasourceId: Joi.string().required(),
parameters: Joi.object({}).required().unknown(true)
diff --git a/packages/server/src/integrations/Integration.js b/packages/server/src/integrations/Integration.js
index e69de29bb2..2305f0ea55 100644
--- a/packages/server/src/integrations/Integration.js
+++ b/packages/server/src/integrations/Integration.js
@@ -0,0 +1,7 @@
+class Field {
+ constructor(type, defaultValue, required) {
+ this.type = type
+ this.default = defaultValue
+ this.required = required
+ }
+}
diff --git a/packages/server/src/integrations/airtable.js b/packages/server/src/integrations/airtable.js
index f21fc3e301..b7300ac446 100644
--- a/packages/server/src/integrations/airtable.js
+++ b/packages/server/src/integrations/airtable.js
@@ -12,19 +12,51 @@ const SCHEMA = {
default: "mybase",
required: true,
},
- table: {
- type: "string",
- default: "mytable",
- required: true,
- },
},
query: {
- Custom: {
- type: "fields",
- custom: true,
+ create: {
+ "Airtable Record": {
+ type: "fields",
+ customisable: true,
+ fields: {
+ table: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
},
- "Airtable Ids": {
- type: "list",
+ read: {
+ Table: {
+ type: "fields",
+ fields: {
+ table: {
+ type: "string",
+ required: true,
+ },
+ view: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
+ },
+ update: {
+ Fields: {
+ type: "fields",
+ customisable: true,
+ fields: {
+ id: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
+ },
+ delete: {
+ "Airtable Ids": {
+ type: "list",
+ },
},
},
}
@@ -35,11 +67,13 @@ class AirtableIntegration {
this.client = new Airtable(config).base(config.base)
}
- async create(record) {
+ async create(query) {
+ const { table, ...rest } = query
+
try {
- const records = await this.client(this.config.table).create([
+ const records = await this.client(table).create([
{
- fields: record,
+ fields: rest,
},
])
return records
@@ -49,18 +83,23 @@ class AirtableIntegration {
}
}
- async read() {
- const records = await this.client(this.config.table)
- .select({ maxRecords: this.query.records, view: this.query.view })
- .firstPage()
- return records.map(({ fields }) => fields)
+ async read(query) {
+ try {
+ const records = await this.client(query.table)
+ .select({ maxRecords: 10, view: query.view })
+ .firstPage()
+ return records.map(({ fields }) => fields)
+ } catch (err) {
+ console.error("Error writing to airtable", err)
+ return []
+ }
}
- async update(document) {
- const { id, ...rest } = document
+ async update(query) {
+ const { table, id, ...rest } = query
try {
- const records = await this.client(this.config.table).update([
+ const records = await this.client(table).update([
{
id,
fields: rest,
@@ -73,9 +112,9 @@ class AirtableIntegration {
}
}
- async delete(id) {
+ async delete(query) {
try {
- const records = await this.client(this.config.table).destroy([id])
+ const records = await this.client(query.table).destroy(query.ids)
return records
} catch (err) {
console.error("Error writing to airtable", err)
diff --git a/packages/server/src/integrations/postgres.js b/packages/server/src/integrations/postgres.js
index 8b6ce6f618..d6e5041003 100644
--- a/packages/server/src/integrations/postgres.js
+++ b/packages/server/src/integrations/postgres.js
@@ -29,46 +29,57 @@ const SCHEMA = {
},
},
query: {
- SQL: {
- type: "sql",
+ create: {
+ SQL: {
+ type: "sql",
+ },
+ },
+ read: {
+ SQL: {
+ type: "sql",
+ },
+ },
+ update: {
+ SQL: {
+ type: "sql",
+ },
+ },
+ delete: {
+ SQL: {
+ type: "sql",
+ },
},
},
}
class PostgresIntegration {
- constructor(config, query) {
+ constructor(config) {
this.config = config
- this.queryString = this.buildQuery(query)
this.client = new Client(config)
this.connect()
}
- buildQuery(query) {
- // TODO: account for different types
- return query
- }
-
async connect() {
return this.client.connect()
}
- async create() {
- const response = await this.client.query(this.queryString)
+ async create({ sql }) {
+ const response = await this.client.query(sql)
return response.rows
}
- async read() {
- const response = await this.client.query(this.queryString)
+ async read({ sql }) {
+ const response = await this.client.query(sql)
return response.rows
}
- async update() {
- const response = await this.client.query(this.queryString)
+ async update({ sql }) {
+ const response = await this.client.query(sql)
return response.rows
}
- async delete() {
- const response = await this.client.query(this.queryString)
+ async delete({ sql }) {
+ const response = await this.client.query(sql)
return response.rows
}
}