diff --git a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
index 3955e34041..1bcdbaca64 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
@@ -8,6 +8,7 @@
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
import { Modal, Switcher } from "@budibase/bbui"
import NavItem from "components/common/NavItem.svelte"
+ import ICONS from "./icons"
$: selectedView =
$backendUiStore.selectedView && $backendUiStore.selectedView.name
@@ -37,10 +38,15 @@
{#each $backendUiStore.datasources as datasource, idx}
0}
- icon={'ri-database-2-line'}
text={datasource.name}
selected={$backendUiStore.selectedDatasourceId === datasource._id}
on:click={() => selectDatasource(datasource)}>
+
+
+
{#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte
index d04b569fe1..29d7c0ffba 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte
@@ -2,6 +2,7 @@
import { onMount } from "svelte"
import { Input, TextArea, Spacer } from "@budibase/bbui"
import api from "builderStore/api"
+ import ICONS from "../icons"
const INTEGRATION_ICON_MAP = {
POSTGRES: "ri-database-2-line",
@@ -10,7 +11,7 @@
export let integration = {}
let integrationsPromise = fetchIntegrations()
- let selectedIntegration
+ let selectedIntegrationConfig
let integrations = []
async function fetchIntegrations() {
@@ -32,28 +33,31 @@
class="integration hoverable"
class:selected={integration.type === integrationType}
on:click={() => {
- selectedIntegration = integrations[integrationType].datasource
- integration = { type: integrationType, ...Object.keys(selectedIntegration).reduce(
+ selectedIntegrationConfig = integrations[integrationType].datasource
+ integration = { type: integrationType, ...Object.keys(selectedIntegrationConfig).reduce(
(acc, next) => {
return {
...acc,
- [next]: selectedIntegration[next].default,
+ [next]: selectedIntegrationConfig[next].default,
}
},
{}
) }
}}>
-
+
{integrationType}
{/each}
- {#if selectedIntegration}
- {#each Object.keys(selectedIntegration) as configKey}
+ {#if selectedIntegrationConfig}
+ {#each Object.keys(selectedIntegrationConfig) as configKey}
@@ -79,10 +83,13 @@
padding: 5px;
transition: 0.3s all;
border-radius: var(--border-radius-s);
+ height: 75px;
+ width: 200px;
}
span {
font-size: var(--font-size-xs);
+ margin-top: var(--spacing-m);
margin-bottom: var(--spacing-xs);
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Airtable.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Airtable.svelte
new file mode 100644
index 0000000000..ce689df205
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Airtable.svelte
@@ -0,0 +1,46 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/CouchDB.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/CouchDB.svelte
new file mode 100644
index 0000000000..1ed737fc81
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/CouchDB.svelte
@@ -0,0 +1,35 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/DynamoDB.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/DynamoDB.svelte
new file mode 100644
index 0000000000..1ec061ca20
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/DynamoDB.svelte
@@ -0,0 +1,58 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Elasticsearch.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Elasticsearch.svelte
new file mode 100644
index 0000000000..20df3bd620
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Elasticsearch.svelte
@@ -0,0 +1,47 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/MongoDB.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/MongoDB.svelte
new file mode 100644
index 0000000000..823ec3a2fa
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/MongoDB.svelte
@@ -0,0 +1,77 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Postgres.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Postgres.svelte
new file mode 100644
index 0000000000..56268f75b3
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Postgres.svelte
@@ -0,0 +1,149 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/S3.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/S3.svelte
new file mode 100644
index 0000000000..23168a3501
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/S3.svelte
@@ -0,0 +1,55 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/SQLServer.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/SQLServer.svelte
new file mode 100644
index 0000000000..6aa2fcafca
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/SQLServer.svelte
@@ -0,0 +1,391 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js b/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js
new file mode 100644
index 0000000000..fa5b0d021a
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js
@@ -0,0 +1,19 @@
+import Postgres from "./Postgres.svelte"
+import DynamoDB from "./DynamoDB.svelte"
+import Elasticsearch from "./Elasticsearch.svelte"
+import MongoDB from "./MongoDB.svelte"
+import CouchDB from "./CouchDB.svelte"
+import S3 from "./S3.svelte"
+import Airtable from "./Airtable.svelte"
+import SqlServer from "./SqlServer.svelte"
+
+export default {
+ POSTGRES: Postgres,
+ DYNAMODB: DynamoDB,
+ MONGODB: MongoDB,
+ ELASTICSEARCH: Elasticsearch,
+ COUCHDB: CouchDB,
+ SQL_SERVER: SqlServer,
+ S3: S3,
+ AIRTABLE: Airtable,
+}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
index ef458c1953..7a85ba1b8b 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
@@ -54,6 +54,6 @@
on:input={checkValid}
bind:value={name}
{error} />
-
+
diff --git a/packages/builder/src/components/common/BottomDrawer.svelte b/packages/builder/src/components/common/BottomDrawer.svelte
index 863102e826..970b8dbbd5 100644
--- a/packages/builder/src/components/common/BottomDrawer.svelte
+++ b/packages/builder/src/components/common/BottomDrawer.svelte
@@ -35,7 +35,7 @@
justify-content: space-between;
align-items: center;
border: var(--border-light);
- padding: var(--spacing-s);
+ padding: var(--spacing-m);
}
.controls {
diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte
index 8eca07b1b0..e3e9fe60eb 100644
--- a/packages/builder/src/components/common/NavItem.svelte
+++ b/packages/builder/src/components/common/NavItem.svelte
@@ -29,8 +29,12 @@
{/if}
+
+
{#if icon}
-
+
+
+
{/if}
{text}
{#if withActions}
diff --git a/packages/builder/src/components/integration/Query.js b/packages/builder/src/components/integration/Query.js
deleted file mode 100644
index 25e9bb2745..0000000000
--- a/packages/builder/src/components/integration/Query.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const handlebars = require("handlebars")
-
-class Query {
- constructor(source, schema, type, queryString) {
- this.source = source
- this.schema = schema
- this.type = type
- this.queryString = queryString
- }
-
- build(parameters) {
- this.queryStr
- }
-}
diff --git a/packages/builder/src/components/integration/QueryParameterBuilder.svelte b/packages/builder/src/components/integration/QueryParameterBuilder.svelte
index ef9a1f25a3..5db7511336 100644
--- a/packages/builder/src/components/integration/QueryParameterBuilder.svelte
+++ b/packages/builder/src/components/integration/QueryParameterBuilder.svelte
@@ -20,9 +20,11 @@
parameters = parameters
}
+ // This is necessary due to the way readable and writable bindings are stored.
+ // The readable binding in the UI gets converted to a UUID value that the client understands
+ // for parsing, then converted back so we can display it the readable form in the UI
function onBindingChange(param, valueToParse) {
const parsedBindingValue = readableToRuntimeBinding(bindings, valueToParse)
- console.log(parsedBindingValue)
customParams[param] = parsedBindingValue
}
@@ -34,8 +36,9 @@
{#if bindable}
+ {:else}
+
{/if}
-
{#each parameters as parameter, idx}
@@ -43,24 +46,27 @@
{
- console.log('changing', evt.detail)
- onBindingChange(parameter.name, evt.detail)
- }}
+ on:change={evt => onBindingChange(parameter.name, evt.detail)}
value={runtimeToReadableBinding(bindings, customParams[parameter.name])}
{bindings} />
+ {:else}
+ deleteQueryParameter(idx)} />
{/if}
- deleteQueryParameter(idx)} />
{/each}
-
+ {#if !bindable}
+
+ {/if}
+
diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte
index 66d0ca1c49..99d3afbdf4 100644
--- a/packages/builder/src/components/integration/QueryViewer.svelte
+++ b/packages/builder/src/components/integration/QueryViewer.svelte
@@ -26,16 +26,14 @@
title: "Schema",
key: "SCHEMA",
},
- {
- title: "Results",
- key: "RESULTS",
- },
{
title: "Preview",
key: "PREVIEW",
},
]
+ const QueryVerb = ["create", "read", "update", "delete"]
+
export let query
export let fields = []
@@ -86,6 +84,7 @@
async function previewQuery() {
try {
const response = await api.post(`/api/queries/preview`, {
+ queryVerb: query.queryVerb,
parameters: query.parameters.reduce(
(acc, next) => ({
...acc,
@@ -125,63 +124,80 @@
}
-
- {query.name}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+{#if query.queryVerb && query.queryType}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{/if}
diff --git a/packages/builder/src/components/integration/index.svelte b/packages/builder/src/components/integration/index.svelte
index 3c370f9b19..9e3e9aaa08 100644
--- a/packages/builder/src/components/integration/index.svelte
+++ b/packages/builder/src/components/integration/index.svelte
@@ -1,6 +1,6 @@
-
+
Query
+
{#if query.queryType === QueryTypes.SQL}
-
-
+
+
{:else if query.queryType === QueryTypes.JSON}
-
+
{:else if query.queryType === QueryTypes.FIELDS}
{/if}
diff --git a/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte b/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte
index 35a053c4aa..dd28ad1c6e 100644
--- a/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte
+++ b/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte
@@ -8,9 +8,7 @@
} from "@budibase/bbui"
import { AddIcon, ArrowDownIcon } from "components/common/Icons/"
import actionTypes from "./actions"
- import { createEventDispatcher } from "svelte"
- const dispatch = createEventDispatcher()
const eventTypeKey = "##eventHandlerType"
export let event
@@ -49,10 +47,6 @@
const selectAction = action => () => {
selectedAction = action
}
-
- const saveEventData = () => {
- dispatch("change", actions)
- }
@@ -87,23 +81,11 @@
{index + 1}. {action[eventTypeKey]}
-
-
-
+
deleteAction(index)} />
{/each}
{/if}
@@ -114,19 +96,11 @@
-
-
-
{/if}
-
-Learn more about Actions
-
diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js
index 2cbe4fb107..b3ef1d7c0e 100644
--- a/packages/server/src/api/controllers/datasource.js
+++ b/packages/server/src/api/controllers/datasource.js
@@ -1,6 +1,10 @@
const CouchDB = require("../../db")
const bcrypt = require("../../utilities/bcrypt")
-const { generateDatasourceID, getDatasourceParams } = require("../../db/utils")
+const {
+ generateDatasourceID,
+ getDatasourceParams,
+ getQueryParams,
+} = require("../../db/utils")
exports.fetch = async function(ctx) {
const database = new CouchDB(ctx.user.appId)
@@ -17,11 +21,6 @@ exports.fetch = async function(ctx) {
exports.save = async function(ctx) {
const db = new CouchDB(ctx.user.appId)
- // TODO: validate the config against the integration type
- // if (!somethingIsntValid) {
- // // ctx.throw(400, "email and Password Required.")
- // }
-
const datasource = {
_id: generateDatasourceID(),
type: "datasource",
@@ -60,9 +59,15 @@ exports.update = async function(ctx) {
}
exports.destroy = async function(ctx) {
- // TODO: destroy all queries as well
- const database = new CouchDB(ctx.user.appId)
- await database.destroy(ctx.params.datasourceId)
+ const db = new CouchDB(ctx.user.appId)
+
+ // Delete all queries for the datasource
+ const rows = await db.allDocs(getQueryParams(ctx.params.datasourceId, null))
+ await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
+
+ // delete the datasource
+ await db.destroy(ctx.params.datasourceId)
+
ctx.message = `Datasource deleted.`
ctx.status = 200
}
diff --git a/packages/server/src/api/controllers/query.js b/packages/server/src/api/controllers/query.js
index f1e3201681..3b907a56ec 100644
--- a/packages/server/src/api/controllers/query.js
+++ b/packages/server/src/api/controllers/query.js
@@ -30,7 +30,7 @@ exports.save = async function(ctx) {
}
exports.preview = async function(ctx) {
- const { query, datasourceId, parameters } = ctx.request.body
+ const { query, datasourceId, parameters, queryVerb } = ctx.request.body
let parsedQuery = ""
if (query) {
@@ -49,7 +49,7 @@ exports.preview = async function(ctx) {
return
}
- ctx.body = await new Integration(datasource.config, parsedQuery).query()
+ ctx.body = await new Integration(datasource.config, parsedQuery)[queryVerb]()
}
exports.execute = async function(ctx) {
@@ -60,7 +60,6 @@ exports.execute = async function(ctx) {
const queryTemplate = handlebars.compile(query.queryString)
- // TODO: Take the default params into account
const parsedQuery = queryTemplate(ctx.request.body.parameters)
const Integration = integrations[datasource.source]
@@ -69,7 +68,11 @@ exports.execute = async function(ctx) {
ctx.throw(400, "Integration type does not exist.")
return
}
- const response = await new Integration(datasource.config, parsedQuery).query()
+
+ // call the relevant CRUD method on the integration class
+ const response = await new Integration(datasource.config, parsedQuery)[
+ query.queryVerb
+ ]()
ctx.body = response
}
diff --git a/packages/server/src/api/routes/query.js b/packages/server/src/api/routes/query.js
index 22d308bac9..0159064c4c 100644
--- a/packages/server/src/api/routes/query.js
+++ b/packages/server/src/api/routes/query.js
@@ -12,10 +12,10 @@ const joiValidator = require("../../middleware/joi-validator")
const router = Router()
const QueryVerb = {
- Create: "CREATE",
- Read: "READ",
- Update: "UPDATE",
- Delete: "DELETE",
+ Create: "create",
+ Read: "read",
+ Update: "update",
+ Delete: "delete",
}
function generateQueryValidation() {
@@ -30,7 +30,7 @@ function generateQueryValidation() {
name: Joi.string(),
default: Joi.string()
})),
- // queryVerb: Joi.string().allow(...Object.values(QueryVerb)).required(),
+ queryVerb: Joi.string().allow(...Object.values(QueryVerb)).required(),
queryType: Joi.string().required(),
schema: Joi.object({}).required().unknown(true)
}))
@@ -40,6 +40,7 @@ function generateQueryPreviewValidation() {
// prettier-ignore
return joiValidator.body(Joi.object({
query: Joi.string(),
+ queryVerb: Joi.string().allow(...Object.values(QueryVerb)).required(),
datasourceId: Joi.string().required(),
parameters: Joi.object({}).required().unknown(true)
}))
diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js
index 4ebd95ca98..4045e63313 100644
--- a/packages/server/src/db/utils.js
+++ b/packages/server/src/db/utils.js
@@ -254,6 +254,14 @@ exports.generateQueryID = datasourceId => {
/**
* Gets parameters for retrieving a query, this is a utility function for the getDocParams function.
*/
-exports.getQueryParams = (queryId = null, otherProps = {}) => {
- return getDocParams(DocumentTypes.QUERY, queryId, otherProps)
+exports.getQueryParams = (datasourceId = null, otherProps = {}) => {
+ if (datasourceId == null) {
+ return getDocParams(DocumentTypes.QUERY, null, otherProps)
+ }
+
+ return getDocParams(
+ DocumentTypes.QUERY,
+ `${datasourceId}${SEPARATOR}`,
+ otherProps
+ )
}
diff --git a/packages/server/src/integrations/airtable.js b/packages/server/src/integrations/airtable.js
index 561df03cc2..0d109e8b54 100644
--- a/packages/server/src/integrations/airtable.js
+++ b/packages/server/src/integrations/airtable.js
@@ -31,11 +31,6 @@ class AirtableIntegration {
// }
- async read() {
- const response = await this.client.query(this.queryString)
- return response.rows
- }
-
// async update() {
// }
@@ -44,9 +39,9 @@ class AirtableIntegration {
// }
- async query() {
+ async read() {
const records = await this.client(this.config.table)
- .select({ maxRecords: 10, view: "Grid view" })
+ .select({ maxRecords: this.query.records, view: this.query.view })
.firstPage()
return records.map(({ fields }) => fields)
}
diff --git a/packages/server/src/integrations/couchdb.js b/packages/server/src/integrations/couchdb.js
index 0d7a1dd05d..8a2dcaa214 100644
--- a/packages/server/src/integrations/couchdb.js
+++ b/packages/server/src/integrations/couchdb.js
@@ -30,7 +30,7 @@ class CouchDBIntegration {
this.client = new PouchDB(`${config.url}/${config.database}`)
}
- async query() {
+ async read() {
try {
const result = await this.client.allDocs({
include_docs: true,
diff --git a/packages/server/src/integrations/dynamodb.js b/packages/server/src/integrations/dynamodb.js
index 3f5f3b8a76..aec93e0933 100644
--- a/packages/server/src/integrations/dynamodb.js
+++ b/packages/server/src/integrations/dynamodb.js
@@ -62,7 +62,7 @@ class DynamoDBIntegration {
AWS.config.update(this.config)
}
- async query() {
+ async read() {
const response = await this.client.query({
TableName: this.config.table,
KeyConditionExpression: this.config.KeyConditionExpression,
diff --git a/packages/server/src/integrations/elasticsearch.js b/packages/server/src/integrations/elasticsearch.js
index 048e5b4bfd..d4ac64d0e7 100644
--- a/packages/server/src/integrations/elasticsearch.js
+++ b/packages/server/src/integrations/elasticsearch.js
@@ -26,7 +26,7 @@ class ElasticSearchIntegration {
this.client = new Client({ node: config.url })
}
- async query() {
+ async read() {
try {
const result = await this.client.search({
index: this.config.index,
diff --git a/packages/server/src/integrations/microsoftSqlServer.js b/packages/server/src/integrations/microsoftSqlServer.js
index 99f661d649..d8e7949aad 100644
--- a/packages/server/src/integrations/microsoftSqlServer.js
+++ b/packages/server/src/integrations/microsoftSqlServer.js
@@ -37,7 +37,7 @@ class SqlServerIntegration {
return await this.client.connect(this.config)
}
- async query() {
+ async read() {
try {
await this.connect()
const response = await this.client.query(this.config.query)
diff --git a/packages/server/src/integrations/mongodb.js b/packages/server/src/integrations/mongodb.js
index 5a15ac906b..984ed11068 100644
--- a/packages/server/src/integrations/mongodb.js
+++ b/packages/server/src/integrations/mongodb.js
@@ -17,7 +17,7 @@ const SCHEMA = {
},
},
query: {
- json: {
+ JSON: {
type: "json",
},
},
@@ -32,15 +32,15 @@ class MongoIntegration {
} catch (err) {
this.config.query = {}
}
+ this.connect()
}
async connect() {
return this.client.connect()
}
- async query() {
+ async read() {
try {
- await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(this.config.collection)
const result = await collection.find(this.config.query).toArray()
diff --git a/packages/server/src/integrations/postgres.js b/packages/server/src/integrations/postgres.js
index 2f7eca7fd0..e7a0c4dab6 100644
--- a/packages/server/src/integrations/postgres.js
+++ b/packages/server/src/integrations/postgres.js
@@ -104,10 +104,10 @@ class PostgresIntegration {
// }
- async query() {
- const response = await this.client.query(this.queryString)
- return response.rows
- }
+ // async query() {
+ // const response = await this.client.query(this.queryString)
+ // return response.rows
+ // }
}
module.exports = {