switching between queries
This commit is contained in:
parent
755fa0ac4a
commit
d7a0d29b03
|
@ -8,6 +8,7 @@ const INITIAL_BACKEND_UI_STATE = {
|
|||
users: [],
|
||||
roles: [],
|
||||
datasources: [],
|
||||
queries: [],
|
||||
selectedDatabase: {},
|
||||
selectedTable: {},
|
||||
draftTable: {},
|
||||
|
@ -24,10 +25,13 @@ export const getBackendUiStore = () => {
|
|||
const tables = await tablesResponse.json()
|
||||
const datasourcesResponse = await api.get(`/api/datasources`)
|
||||
const datasources = await datasourcesResponse.json()
|
||||
const queriesResponse = await api.get(`/api/queries`)
|
||||
const queries = await queriesResponse.json()
|
||||
store.update(state => {
|
||||
state.selectedDatabase = db
|
||||
state.tables = tables
|
||||
state.datasources = datasources
|
||||
state.queries = queries
|
||||
return state
|
||||
})
|
||||
},
|
||||
|
@ -98,35 +102,56 @@ export const getBackendUiStore = () => {
|
|||
return state
|
||||
})
|
||||
},
|
||||
saveQuery: async (datasourceId, query) => {
|
||||
const response = await api.post(
|
||||
`/api/datasources/${datasourceId}/queries`,
|
||||
query
|
||||
)
|
||||
},
|
||||
queries: {
|
||||
fetch: async () => {
|
||||
const response = await api.get(`/api/queries`)
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
const currentIdx = state.datasources.findIndex(
|
||||
ds => ds._id === json._id
|
||||
state.queries = json
|
||||
return state
|
||||
})
|
||||
return json
|
||||
},
|
||||
save: async (datasourceId, query) => {
|
||||
query.datasourceId = datasourceId
|
||||
const response = await api.post(`/api/queries`, query)
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
const currentIdx = state.queries.findIndex(
|
||||
query => query._id === json._id
|
||||
)
|
||||
|
||||
if (currentIdx >= 0) {
|
||||
state.datasources.splice(currentIdx, 1, json)
|
||||
state.queries.splice(currentIdx, 1, json)
|
||||
} else {
|
||||
state.datasources.push(json)
|
||||
state.queries.push(json)
|
||||
}
|
||||
|
||||
state.datasources = state.datasources
|
||||
state.queries = state.queries
|
||||
state.selectedQueryId = json._id
|
||||
return state
|
||||
})
|
||||
},
|
||||
},
|
||||
queries: {
|
||||
select: queryId =>
|
||||
store.update(state => {
|
||||
state.selectedDatasourceId = null
|
||||
state.selectedQueryId = queryId
|
||||
return state
|
||||
}),
|
||||
delete: async queryId => {
|
||||
await api.delete(`/api/queries/${queryId}`)
|
||||
store.update(state => {
|
||||
state.datasources = state.queries.filter(
|
||||
existing => existing._id !== queryId
|
||||
)
|
||||
if (state.selectedQueryId === queryId) {
|
||||
state.selectedQueryId = null
|
||||
}
|
||||
|
||||
return state
|
||||
})
|
||||
},
|
||||
},
|
||||
tables: {
|
||||
fetch: async () => {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
import Table from "./Table.svelte"
|
||||
import CreateQueryButton from "components/backend/DataTable/buttons/CreateQueryButton.svelte"
|
||||
|
||||
export let datasource
|
||||
export let query = {}
|
||||
|
||||
let data = []
|
||||
|
@ -23,7 +22,6 @@
|
|||
data = response.rows || []
|
||||
error = false
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
error = `${query}: Query error. (${err.message}). This could be a problem with your datasource configuration.`
|
||||
notifier.danger(error)
|
||||
} finally {
|
||||
|
@ -32,14 +30,14 @@
|
|||
}
|
||||
|
||||
// Fetch rows for specified query
|
||||
$: fetchData()
|
||||
$: query && fetchData()
|
||||
</script>
|
||||
|
||||
{#if error}
|
||||
<div class="errors">{error}</div>
|
||||
{/if}
|
||||
<Table title={query.name} schema={query.schema} {data} {loading}>
|
||||
<CreateQueryButton {query} {datasource} />
|
||||
<CreateQueryButton {query} edit />
|
||||
</Table>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -32,7 +32,7 @@ export async function fetchDataForView(view) {
|
|||
}
|
||||
|
||||
export async function fetchDataForQuery(datasourceId, queryId) {
|
||||
const FETCH_QUERY_URL = `/api/datasources/${datasourceId}/queries/${queryId}`
|
||||
const FETCH_QUERY_URL = `/api/queries/${queryId}`
|
||||
|
||||
const response = await api.get(FETCH_QUERY_URL)
|
||||
const json = await response.json()
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
import EditIntegrationConfig from "../modals/EditIntegrationConfig.svelte"
|
||||
import CreateEditQuery from "components/backend/DataTable/modals/CreateEditQuery.svelte"
|
||||
|
||||
export let datasource
|
||||
export let query = {}
|
||||
export let edit
|
||||
|
||||
let modal
|
||||
let fields = []
|
||||
|
||||
async function saveQuery() {
|
||||
try {
|
||||
await backendUiStore.actions.datasources.saveQuery(datasource._id, query)
|
||||
await backendUiStore.actions.queries.save(query.datasourceId, query)
|
||||
notifier.success(`Query created successfully.`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
@ -35,7 +35,7 @@
|
|||
<div>
|
||||
<Button text small on:click={modal.show}>
|
||||
<Icon name="filter" />
|
||||
{$backendUiStore.selectedQueryId ? 'Edit' : 'Create'} Query
|
||||
{edit ? 'Edit' : 'Create'} Query
|
||||
</Button>
|
||||
</div>
|
||||
<Modal bind:this={modal}>
|
||||
|
@ -43,7 +43,7 @@
|
|||
confirmText="Save"
|
||||
cancelText="Cancel"
|
||||
onConfirm={saveQuery}
|
||||
title={query ? 'Edit Query' : 'Create New Query'}>
|
||||
<CreateEditQuery {datasource} bind:query />
|
||||
title={edit ? 'Edit Query' : 'Create New Query'}>
|
||||
<CreateEditQuery bind:query />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
|
|
@ -27,17 +27,20 @@
|
|||
},
|
||||
]
|
||||
|
||||
export let datasource
|
||||
export let query
|
||||
export let fields = []
|
||||
|
||||
console.log(query)
|
||||
|
||||
let config = {}
|
||||
let queryType
|
||||
let previewTab = "PREVIEW"
|
||||
let preview
|
||||
|
||||
$: datasource = $backendUiStore.datasources.find(
|
||||
ds => ds._id === query.datasourceId
|
||||
)
|
||||
|
||||
$: query.datasourceId =
|
||||
query.datasourceId || $backendUiStore.selectedDatasourceId
|
||||
|
||||
$: query.schema = fields.reduce(
|
||||
(acc, next) => ({
|
||||
...acc,
|
||||
|
@ -72,9 +75,8 @@
|
|||
|
||||
async function previewQuery() {
|
||||
try {
|
||||
const response = await api.post(`/api/datasources/queries/preview`, {
|
||||
type: datasource.source,
|
||||
config: datasource.config,
|
||||
const response = await api.post(`/api/queries/preview`, {
|
||||
datasourceId: datasource._id,
|
||||
query: query.queryString,
|
||||
})
|
||||
const json = await response.json()
|
||||
|
@ -101,18 +103,13 @@
|
|||
|
||||
<section>
|
||||
<div class="config">
|
||||
<h6>Datasource Type</h6>
|
||||
<span>{datasource.source}</span>
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
<Label extraSmall grey>Query Name</Label>
|
||||
<Input type="text" thin bind:value={query.name} />
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
<Label extraSmall grey>Query Type</Label>
|
||||
<Select secondary bind:value={queryType}>
|
||||
<Select secondary bind:value={query.queryType}>
|
||||
<option value={''}>Select an option</option>
|
||||
{#each Object.keys(config) as queryType}
|
||||
<option value={queryType}>{queryType}</option>
|
||||
|
@ -121,7 +118,9 @@
|
|||
|
||||
<Spacer medium />
|
||||
|
||||
<IntegrationQueryEditor {queryType} bind:query={query.queryString} />
|
||||
<IntegrationQueryEditor
|
||||
type={query.queryType}
|
||||
bind:query={query.queryString} />
|
||||
|
||||
<Spacer small />
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import { TableNames } from "constants"
|
||||
import CreateDatasourceModal from "./modals/CreateDatasourceModal.svelte"
|
||||
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
|
||||
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
|
||||
import { Modal, Switcher } from "@budibase/bbui"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
|
||||
|
@ -18,6 +19,7 @@
|
|||
}
|
||||
|
||||
function onClickQuery(datasourceId, queryId) {
|
||||
console.log(backendUiStore.selectedQueryId, queryId)
|
||||
if ($backendUiStore.selectedQueryId === queryId) {
|
||||
return
|
||||
}
|
||||
|
@ -28,6 +30,7 @@
|
|||
|
||||
onMount(() => {
|
||||
backendUiStore.actions.datasources.fetch()
|
||||
backendUiStore.actions.queries.fetch()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -42,15 +45,14 @@
|
|||
on:click={() => selectDatasource(datasource)}>
|
||||
<EditDatasourcePopover {datasource} />
|
||||
</NavItem>
|
||||
{#each Object.keys(datasource.queries) as queryId}
|
||||
{#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
|
||||
<NavItem
|
||||
indentLevel={1}
|
||||
icon="ri-eye-line"
|
||||
text={datasource.queries[queryId].name}
|
||||
selected={$backendUiStore.selectedQueryId === queryId}
|
||||
on:click={() => onClickQuery(datasource._id, queryId)}>
|
||||
<!-- <EditViewPopover
|
||||
view={{ name: viewName, ...table.views[viewName] }} /> -->
|
||||
text={query.name}
|
||||
selected={$backendUiStore.selectedQueryId === query._id}
|
||||
on:click={() => onClickQuery(datasource._id, query._id)}>
|
||||
<EditQueryPopover {query} />
|
||||
</NavItem>
|
||||
{/each}
|
||||
{/each}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<script>
|
||||
import { backendUiStore, store, allScreens } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import { DropdownMenu, Button, Input } from "@budibase/bbui"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import IntegrationConfigForm from "../TableIntegrationMenu//IntegrationConfigForm.svelte"
|
||||
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
||||
|
||||
export let query
|
||||
|
||||
let anchor
|
||||
let dropdown
|
||||
let confirmDeleteDialog
|
||||
let error = ""
|
||||
let willBeDeleted
|
||||
|
||||
function hideEditor() {
|
||||
dropdown?.hide()
|
||||
}
|
||||
|
||||
function showModal() {
|
||||
hideEditor()
|
||||
confirmDeleteDialog.show()
|
||||
}
|
||||
|
||||
async function deleteQuery() {
|
||||
await backendUiStore.actions.queries.delete(query._id)
|
||||
notifier.success("Query deleted")
|
||||
hideEditor()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div on:click|stopPropagation>
|
||||
<div bind:this={anchor} class="icon" on:click={dropdown.show}>
|
||||
<i class="ri-more-line" />
|
||||
</div>
|
||||
<DropdownMenu align="left" {anchor} bind:this={dropdown}>
|
||||
<DropdownContainer>
|
||||
<DropdownItem
|
||||
icon="ri-delete-bin-line"
|
||||
title="Delete"
|
||||
on:click={showModal}
|
||||
data-cy="delete-datasource" />
|
||||
</DropdownContainer>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
bind:this={confirmDeleteDialog}
|
||||
okText="Delete Query"
|
||||
onOk={deleteQuery}
|
||||
title="Confirm Deletion">
|
||||
Are you sure you wish to delete this query?
|
||||
This action cannot be undone.
|
||||
</ConfirmDialog>
|
||||
|
||||
<style>
|
||||
div.icon {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div.icon i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding: var(--spacing-xl);
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-xl);
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -1,17 +1,28 @@
|
|||
<script>
|
||||
import { TextArea } from "@budibase/bbui"
|
||||
import { TextArea, Label, Input } from "@budibase/bbui"
|
||||
import Editor from "./Editor.svelte"
|
||||
|
||||
const CAPTURE_VAR_INSIDE_MUSTACHE = /{{([^}]+)}}/g
|
||||
|
||||
const QueryTypes = {
|
||||
SQL: "sql",
|
||||
}
|
||||
|
||||
export let queryType
|
||||
export let type
|
||||
export let query
|
||||
|
||||
$: console.log(query)
|
||||
// $: parameters = Array.from(
|
||||
// query
|
||||
// .matchAll(CAPTURE_VAR_INSIDE_MUSTACHE)
|
||||
// .map(([_, paramName]) => paramName)
|
||||
// )
|
||||
</script>
|
||||
|
||||
{#if queryType === QueryTypes.SQL}
|
||||
<!-- {#each parameters as param}
|
||||
<Label grey extraSmall>{param}</Label>
|
||||
<Input thin bind:value={query.params[param]} />
|
||||
{/each} -->
|
||||
|
||||
{#if type === QueryTypes.SQL}
|
||||
<Editor label="Query" bind:value={query} />
|
||||
{/if}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<Label size="m" color="dark">Query</Label>
|
||||
<Select secondary bind:value={parameters.queryId}>
|
||||
<option value="" />
|
||||
{#each Object.keys(datasource.queries) as query}
|
||||
{#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
|
||||
<option value={query}>{datasource.queries[query].name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
|
|
|
@ -31,17 +31,13 @@
|
|||
return [...acc, ...viewsArr]
|
||||
}, [])
|
||||
|
||||
$: queries = $backendUiStore.datasources.reduce((acc, cur) => {
|
||||
let queriesArr = Object.entries(cur.queries).map(([key, value]) => ({
|
||||
label: value.name,
|
||||
name: value.name,
|
||||
datasourceId: cur._id,
|
||||
queryId: key,
|
||||
schema: value.schema,
|
||||
$: queries = $backendUiStore.queries.map(query => ({
|
||||
label: query.name,
|
||||
name: query.name,
|
||||
...query,
|
||||
schema: query.schema,
|
||||
type: "query",
|
||||
}))
|
||||
return [...acc, ...queriesArr]
|
||||
}, [])
|
||||
}))
|
||||
|
||||
$: bindableProperties = fetchBindableProperties({
|
||||
componentInstanceId: $store.selectedComponentId,
|
||||
|
|
|
@ -3,13 +3,10 @@
|
|||
import { backendUiStore } from "builderStore"
|
||||
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
|
||||
|
||||
// TODO: refactor
|
||||
$: datasource = $backendUiStore.datasources.find(
|
||||
ds => ds._id === $params.selectedDatasource
|
||||
)
|
||||
$: query = datasource && datasource.queries[$params.query]
|
||||
$: query = $backendUiStore.queries.find(query => query._id === $params.query)
|
||||
$: console.log("updated", query)
|
||||
</script>
|
||||
|
||||
{#if $backendUiStore.selectedDatabase._id && datasource && query}
|
||||
<ExternalDataSourceTable {query} {datasource} />
|
||||
{#if $backendUiStore.selectedDatabase._id && query}
|
||||
<ExternalDataSourceTable {query} />
|
||||
{/if}
|
||||
|
|
|
@ -3,9 +3,9 @@ import API from "./api"
|
|||
/**
|
||||
* Fetches all rows from a query.
|
||||
*/
|
||||
export const fetchQueryData = async ({ datasourceId, queryId }) => {
|
||||
export const fetchQueryData = async ({ _id }) => {
|
||||
const response = await API.get({
|
||||
url: `/api/datasources/${datasourceId}/queries/${queryId}`,
|
||||
url: `/api/queries/${_id}`,
|
||||
})
|
||||
return response.rows
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ export const fetchQueryData = async ({ datasourceId, queryId }) => {
|
|||
/**
|
||||
* Executes a query against an external data connector.
|
||||
*/
|
||||
export const executeQuery = async ({ datasourceId, queryId }) => {
|
||||
export const executeQuery = async ({ _id }) => {
|
||||
const response = await API.post({
|
||||
url: `/api/datasources/${datasourceId}/queries/${queryId}`,
|
||||
url: `/api/queries/${_id}`,
|
||||
// body: params,
|
||||
})
|
||||
return response.rows
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
const CouchDB = require("../../db")
|
||||
const bcrypt = require("../../utilities/bcrypt")
|
||||
const {
|
||||
generateDatasourceID,
|
||||
getDatasourceParams,
|
||||
generateQueryID,
|
||||
} = require("../../db/utils")
|
||||
const { integrations } = require("../../integrations")
|
||||
const { generateDatasourceID, getDatasourceParams } = require("../../db/utils")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const database = new CouchDB(ctx.user.appId)
|
||||
|
@ -30,7 +25,6 @@ exports.save = async function(ctx) {
|
|||
const datasource = {
|
||||
_id: generateDatasourceID(),
|
||||
type: "datasource",
|
||||
queries: {},
|
||||
...ctx.request.body,
|
||||
}
|
||||
|
||||
|
@ -77,90 +71,3 @@ exports.find = async function(ctx) {
|
|||
const datasource = await database.get(ctx.params.datasourceId)
|
||||
ctx.body = datasource
|
||||
}
|
||||
|
||||
exports.saveQuery = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
const query = ctx.request.body
|
||||
|
||||
//
|
||||
// {
|
||||
// type: "",
|
||||
// query: "",
|
||||
// otherStuff: ""
|
||||
// }
|
||||
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
||||
const queryId = generateQueryID()
|
||||
|
||||
datasource.queries[queryId] = query
|
||||
|
||||
const response = await db.put(datasource)
|
||||
datasource._rev = response.rev
|
||||
|
||||
ctx.body = datasource
|
||||
ctx.message = `Query ${query.name} saved successfully.`
|
||||
}
|
||||
|
||||
exports.previewQuery = async function(ctx) {
|
||||
const { type, config, query } = ctx.request.body
|
||||
|
||||
const Integration = integrations[type]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.body = await new Integration(config, query).query()
|
||||
}
|
||||
|
||||
exports.fetchQuery = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
||||
const query = datasource.queries[ctx.params.queryId]
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
const rows = await new Integration(
|
||||
datasource.config,
|
||||
query.queryString
|
||||
).query()
|
||||
|
||||
ctx.body = {
|
||||
schema: query.schema,
|
||||
rows,
|
||||
}
|
||||
}
|
||||
|
||||
exports.executeQuery = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
||||
const query = datasource.queries[ctx.params.queryId]
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: allow the ability to POST parameters down when executing the query
|
||||
// const customParams = ctx.request.body
|
||||
|
||||
const response = await new Integration(
|
||||
datasource.config,
|
||||
query.queryString
|
||||
).query()
|
||||
|
||||
ctx.body = response
|
||||
}
|
||||
|
|
|
@ -1,39 +1,128 @@
|
|||
// const CouchDB = require("../../../db")
|
||||
// const { generateQueryID } = require("../../db/utils")
|
||||
// const viewTemplate = require("./viewBuilder")
|
||||
const handlebars = require("handlebars")
|
||||
const Joi = require("joi")
|
||||
const CouchDB = require("../../db")
|
||||
const bcrypt = require("../../utilities/bcrypt")
|
||||
const { generateQueryID, getQueryParams } = require("../../db/utils")
|
||||
const { integrations } = require("../../integrations")
|
||||
const joiValidator = require("../../middleware/joi-validator")
|
||||
|
||||
// exports.save = async ctx => {
|
||||
// const db = new CouchDB(ctx.user.appId)
|
||||
// const { datasourceId, query } = ctx.request.body
|
||||
function generateQueryValidation() {
|
||||
// prettier-ignore
|
||||
return joiValidator.body(Joi.object({
|
||||
name: Joi.string().required(),
|
||||
queryString: Joi.string().required(),
|
||||
datasourceId: Joi.string().required(),
|
||||
queryType: Joi.string().required(),
|
||||
schema: Joi.object({}).required().unknown(true)
|
||||
}))
|
||||
}
|
||||
|
||||
// const datasource = await db.get(datasourceId)
|
||||
exports.fetch = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
// const queryId = generateQueryID()
|
||||
const body = await db.allDocs(
|
||||
getQueryParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
ctx.body = body.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
// datasource.queries[queryId] = query
|
||||
exports.save = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
const query = ctx.request.body
|
||||
|
||||
// const response = await db.put(datasource)
|
||||
//
|
||||
// {
|
||||
// type: "",
|
||||
// query: "",
|
||||
// otherStuff: ""
|
||||
// }
|
||||
|
||||
// ctx.body = query
|
||||
// ctx.message = `View ${viewToSave.name} saved successfully.`
|
||||
// }
|
||||
if (!query._id) {
|
||||
query._id = generateQueryID(query.datasourceId)
|
||||
}
|
||||
|
||||
// exports.destroy = async ctx => {
|
||||
// const db = new CouchDB(ctx.user.appId)
|
||||
// const designDoc = await db.get("_design/database")
|
||||
const response = await db.put(query)
|
||||
query._rev = response.rev
|
||||
|
||||
// const viewName = decodeURI(ctx.params.viewName)
|
||||
ctx.body = query
|
||||
ctx.message = `Query ${query.name} saved successfully.`
|
||||
}
|
||||
|
||||
// const view = designDoc.views[viewName]
|
||||
exports.preview = async function(ctx) {
|
||||
const { query, datasourceId } = ctx.request.body
|
||||
|
||||
// delete designDoc.views[viewName]
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
// await db.put(designDoc)
|
||||
const datasource = await db.get(datasourceId)
|
||||
|
||||
// const table = await db.get(view.meta.tableId)
|
||||
// delete table.views[viewName]
|
||||
// await db.put(table)
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
// ctx.body = view
|
||||
// ctx.message = `View ${ctx.params.viewName} saved successfully.`
|
||||
// }
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.body = await new Integration(datasource.config, query).query()
|
||||
}
|
||||
|
||||
exports.execute = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
||||
const query = datasource.queries[ctx.params.queryId]
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: allow the ability to POST parameters down when executing the query
|
||||
// const customParams = ctx.request.body
|
||||
const queryTemplate = handlebars.compile(query.queryString)
|
||||
|
||||
const response = await new Integration(
|
||||
datasource.config,
|
||||
queryTemplate({
|
||||
// pass the params here from the UI and backend contexts
|
||||
})
|
||||
).query()
|
||||
|
||||
ctx.body = response
|
||||
}
|
||||
|
||||
exports.fetchQuery = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const query = await db.get(ctx.params.queryId)
|
||||
|
||||
const datasource = await db.get(query.datasourceId)
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
const rows = await new Integration(
|
||||
datasource.config,
|
||||
query.queryString
|
||||
).query()
|
||||
|
||||
ctx.body = {
|
||||
schema: query.schema,
|
||||
rows,
|
||||
}
|
||||
}
|
||||
|
||||
exports.destroy = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
await db.destroy(ctx.params.queryId)
|
||||
ctx.message = `Query deleted.`
|
||||
ctx.status = 200
|
||||
}
|
||||
|
|
|
@ -17,26 +17,26 @@ router
|
|||
datasourceController.find
|
||||
)
|
||||
.post("/api/datasources", authorized(BUILDER), datasourceController.save)
|
||||
.post(
|
||||
"/api/datasources/:datasourceId/queries",
|
||||
authorized(BUILDER),
|
||||
datasourceController.saveQuery
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/queries/preview",
|
||||
authorized(BUILDER),
|
||||
datasourceController.previewQuery
|
||||
)
|
||||
.get(
|
||||
"/api/datasources/:datasourceId/queries/:queryId",
|
||||
authorized(BUILDER),
|
||||
datasourceController.fetchQuery
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/:datasourceId/queries/:queryId",
|
||||
authorized(BUILDER),
|
||||
datasourceController.executeQuery
|
||||
)
|
||||
// .post(
|
||||
// "/api/datasources/:datasourceId/queries",
|
||||
// authorized(BUILDER),
|
||||
// datasourceController.saveQuery
|
||||
// )
|
||||
// .post(
|
||||
// "/api/datasources/queries/preview",
|
||||
// authorized(BUILDER),
|
||||
// datasourceController.previewQuery
|
||||
// )
|
||||
// .get(
|
||||
// "/api/datasources/:datasourceId/queries/:queryId",
|
||||
// authorized(BUILDER),
|
||||
// datasourceController.fetchQuery
|
||||
// )
|
||||
// .post(
|
||||
// "/api/datasources/:datasourceId/queries/:queryId",
|
||||
// authorized(BUILDER),
|
||||
// datasourceController.executeQuery
|
||||
// )
|
||||
.delete(
|
||||
"/api/datasources/:datasourceId/:revId",
|
||||
authorized(BUILDER),
|
||||
|
|
|
@ -19,7 +19,7 @@ const routingRoutes = require("./routing")
|
|||
const integrationRoutes = require("./integration")
|
||||
const permissionRoutes = require("./permission")
|
||||
const datasourceRoutes = require("./datasource")
|
||||
// const queryRoutes = require("./query")
|
||||
const queryRoutes = require("./query")
|
||||
|
||||
exports.mainRoutes = [
|
||||
deployRoutes,
|
||||
|
@ -39,7 +39,7 @@ exports.mainRoutes = [
|
|||
integrationRoutes,
|
||||
permissionRoutes,
|
||||
datasourceRoutes,
|
||||
// queryRoutes,
|
||||
queryRoutes,
|
||||
// these need to be handled last as they still use /api/:tableId
|
||||
// this could be breaking as koa may recognise other routes as this
|
||||
tableRoutes,
|
||||
|
|
|
@ -1,28 +1,17 @@
|
|||
// const Router = require("@koa/router")
|
||||
// const queryController = require("../controllers/query")
|
||||
// const authorized = require("../../middleware/authorized")
|
||||
// const { BUILDER } = require("../../utilities/security/permissions")
|
||||
const Router = require("@koa/router")
|
||||
const queryController = require("../controllers/query")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("../../utilities/security/permissions")
|
||||
|
||||
// const router = Router()
|
||||
const router = Router()
|
||||
|
||||
// // TODO: send down the datasource ID as well
|
||||
// TODO: sort out auth so apps have the right permissions
|
||||
router
|
||||
.get("/api/queries", authorized(BUILDER), queryController.fetch)
|
||||
.get("/api/queries/:queryId", authorized(BUILDER), queryController.fetchQuery)
|
||||
.post("/api/queries", authorized(BUILDER), queryController.save)
|
||||
.post("/api/queries/preview", authorized(BUILDER), queryController.preview)
|
||||
.post("/api/queries/:queryId", authorized(BUILDER), queryController.execute)
|
||||
.delete("/api/queries/:queryId", authorized(BUILDER), queryController.destroy)
|
||||
|
||||
// router
|
||||
// // .get("/api/queries", authorized(BUILDER), queryController.fetch)
|
||||
// // .get(
|
||||
// // "/api/datasources/:datasourceId/queries/:id",
|
||||
// // authorized(PermissionTypes.TABLE, PermissionLevels.READ),
|
||||
// // queryController.find
|
||||
// // )
|
||||
// .post(
|
||||
// "/api/datasources/:datasourceId/queries",
|
||||
// authorized(BUILDER),
|
||||
// queryController.save
|
||||
// )
|
||||
// .delete(
|
||||
// "/api/datasources/:datasourceId/queries/:queryId/:revId",
|
||||
// authorized(BUILDER),
|
||||
// queryController.destroy
|
||||
// )
|
||||
|
||||
// module.exports = router
|
||||
module.exports = router
|
||||
|
|
|
@ -38,6 +38,6 @@ function replicateLocal() {
|
|||
})
|
||||
}
|
||||
|
||||
// replicateLocal()
|
||||
replicateLocal()
|
||||
|
||||
module.exports = Pouch
|
||||
|
|
|
@ -245,8 +245,10 @@ exports.getDatasourceParams = (datasourceId = null, otherProps = {}) => {
|
|||
* Generates a new query ID.
|
||||
* @returns {string} The new query ID which the query doc can be stored under.
|
||||
*/
|
||||
exports.generateQueryID = () => {
|
||||
return `${DocumentTypes.QUERY}${SEPARATOR}${newid()}`
|
||||
exports.generateQueryID = datasourceId => {
|
||||
return `${
|
||||
DocumentTypes.QUERY
|
||||
}${SEPARATOR}${datasourceId}${SEPARATOR}${newid()}`
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,7 @@ const PermissionTypes = {
|
|||
WEBHOOK: "webhook",
|
||||
BUILDER: "builder",
|
||||
VIEW: "view",
|
||||
QUERY: "query",
|
||||
}
|
||||
|
||||
function Permission(type, level) {
|
||||
|
|
Loading…
Reference in New Issue