mongoDB end to end

This commit is contained in:
Martin McKeaveney 2020-11-26 16:46:36 +00:00
parent 298ef30360
commit fbf501aebc
11 changed files with 293 additions and 51 deletions

View File

@ -27,6 +27,6 @@
}
</script>
<Table {title} {schema} {data} allowEditing={true} {loading}>
<Table {title} {schema} {data} {loading}>
<EditIntegrationConfigButton {table} />
</Table>

View File

@ -37,7 +37,7 @@
confirmText="Save"
cancelText="Cancel"
onConfirm={saveTable}
title={'Edit Datasource Configuration'}>
title={'Datasource Configuration'}>
<EditIntegrationConfig onClosed={modal.hide} bind:table />
</ModalContent>
</Modal>

View File

@ -1,11 +1,21 @@
<script>
import { Select, Button, Input, TextArea, Heading } from "@budibase/bbui"
import {
Select,
Button,
Input,
TextArea,
Heading,
Spacer,
} from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import { backendUiStore } from "builderStore"
export let table
let fields = []
let fields = Object.keys(table.schema).map(field => ({
name: field,
type: table.schema[field].type.toUpperCase(),
}))
$: {
const schema = {}
@ -27,36 +37,35 @@
</script>
<form>
<Heading extraSmall black>Schema</Heading>
<!-- {#each Object.keys(table.schema) as schemaKey, idx}
<Input
thin
type={'text'}
label={schemaKey}
bind:value={table.schema[schemaKey]} />
{/each} -->
{#each fields as field}
<div class="field">
<Input thin type={'text'} bind:value={field.name} />
<Select secondary thin bind:value={field.type}>
<option value={''}>Select an option</option>
<option value={'STRING'}>Text</option>
<option value={'NUMBER'}>Number</option>
<option value={'BOOLEAN'}>Boolean</option>
<option value={'DATETIME'}>Datetime</option>
</Select>
</div>
{/each}
<div class="config">
<h6>Schema</h6>
{#each fields as field, idx}
<div class="field">
<Input thin type={'text'} bind:value={field.name} />
<Select secondary thin bind:value={field.type}>
<option value={''}>Select an option</option>
<option value={'STRING'}>Text</option>
<option value={'NUMBER'}>Number</option>
<option value={'BOOLEAN'}>Boolean</option>
<option value={'DATETIME'}>Datetime</option>
</Select>
<i class="ri-close-circle-line" on:click={() => deleteField(idx)} />
</div>
{/each}
<Button thin secondary on:click={newField}>Add Field</Button>
</div>
<Button thin secondary on:click={newField}>Add Field</Button>
<Heading extraSmall black>Datasource</Heading>
{#each Object.keys(table.integration) as configKey}
<Input
thin
type={configKey.type}
label={configKey}
bind:value={table.integration[configKey]} />
{/each}
<div class="config">
<h6>Datasource</h6>
{#each Object.keys(table.integration) as configKey}
<Input
thin
type={configKey.type}
label={configKey}
bind:value={table.integration[configKey]} />
<Spacer small />
{/each}
</div>
</form>
<style>
@ -64,6 +73,25 @@
display: grid;
grid-gap: 10px;
grid-template-columns: 1fr 1fr;
margin-bottom: var(--spacing-xs);
margin-bottom: var(--spacing-m);
}
h6 {
font-family: var(--font-sans);
font-weight: 600;
text-rendering: var(--text-render);
color: var(--ink);
font-size: var(--heading-font-size-xs);
color: var(--ink);
margin-bottom: var(--spacing-m);
margin-top: var(--spacing-l);
}
.config {
margin-bottom: var(--spacing-s);
}
form > * {
margin-bottom: var(--spacing-s);
}
</style>

View File

@ -3,45 +3,52 @@
import { Input, TextArea } from "@budibase/bbui"
import api from "builderStore/api"
const INTEGRATION_ICON_MAP = {
POSTGRES: "ri-database-2-line",
}
export let integration = {}
let integrationsPromise = fetchIntegrations()
let selectedIntegration
let integrations = []
async function fetchIntegrations() {
const INTEGRATIONS_URL = `/api/integrations`
const response = await api.get(INTEGRATIONS_URL)
const json = await response.json()
integrations = json
return json
}
onMount(() => {
fetchIntegrations()
})
</script>
<section>
{#await integrationsPromise}
Loading integrations...
{:then integrations}
<div class="integration-list">
{#each Object.keys(integrations) as integrationType}
<div
class="integration hoverable"
on:click={() => {
selectedIntegration = integrations[integrationType]
integration.type = integrationType
}}>
<h6>{integrationType}</h6>
<span>{integrationType}</span>
<i class="ri-database-2-line" />
</div>
{/each}
{:catch}
shit itself
{/await}
</div>
{#if selectedIntegration}
{#each Object.keys(selectedIntegration) as configKey}
<Input
thin
type={configKey.type}
type={selectedIntegration[configKey].type}
label={configKey}
bind:value={integration[configKey]} />
{/each}
<TextArea label={'Query'} bind:value={integration.query} />
{/if}
</section>
@ -49,4 +56,27 @@
section {
display: grid;
}
.integration-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.integration {
display: flex;
align-items: center;
flex-direction: column;
padding: 5px;
transition: 0.3s all;
border-radius: var(--border-radius-s);
}
span {
font-size: var(--font-size-xs);
margin-bottom: var(--spacing-xs);
}
.integration:hover {
background-color: var(--grey-3);
}
</style>

View File

@ -79,6 +79,7 @@
"koa-session": "^5.12.0",
"koa-static": "^5.0.0",
"lodash": "^4.17.13",
"mongodb": "^3.6.3",
"mustache": "^4.0.1",
"node-fetch": "^2.6.0",
"pg": "^8.5.1",

View File

@ -1,7 +0,0 @@
class Integration {
definition() {
return this.options
}
}
module.exports = Integration

View File

@ -0,0 +1,64 @@
const AWS = require("aws-sdk")
const DYNAMODB_OPTIONS = {
table: {
type: "string",
required: true,
},
region: {
type: "string",
required: true,
default: "us-east-1",
},
accessKeyId: {
type: "string",
required: true,
},
secretKey: {
type: "secretKey",
required: true,
default: 5432,
},
indexName: {
type: "string",
},
keyConditionExpression: {
type: "string",
required: true,
},
attributeNames: {
type: "object",
required: true,
},
attributeValues: {
type: "object",
required: true,
},
}
class DynamoDBIntegration {
constructor(config) {
this.config = config
this.connect()
this.client = new AWS.DynamoDB.DocumentClient()
}
async connect() {
AWS.config.update(this.config)
}
async query() {
const response = await this.client.query({
TableName: this.config.table,
KeyConditionExpression: this.config.keyConditionExpression,
ExpressionAttributeNames: this.config.attributeNames,
ExpressionAttributeValues: this.config.attributeValues,
})
return response
}
}
module.exports = {
schema: DYNAMODB_OPTIONS,
integration: DynamoDBIntegration,
}

View File

@ -1,11 +1,21 @@
const postgres = require("./postgres")
const dynamodb = require("./dynamodb")
const mongodb = require("./mongodb")
// const redis = require("./redis")
// const couchdb = require("./couchdb")
// const elasticsearch = require("./elasticsearch")
// const s3 = require("./s3")
const DEFINITIONS = {
POSTGRES: postgres.schema,
DYNAMODB: dynamodb.schema,
MONGODB: mongodb.schema,
}
const INTEGRATIONS = {
POSTGRES: postgres.integration,
DYNAMODB: dynamodb.integration,
MONGODB: mongodb.integration,
}
module.exports = {

View File

@ -0,0 +1,49 @@
const { MongoClient } = require("mongodb")
const MONGODB_OPTIONS = {
connectionString: {
type: "string",
required: true,
default: "localhost",
},
db: {
type: "string",
required: true,
},
collection: {
type: "string",
required: true,
},
query: {
type: "query",
required: true,
},
}
class MongoIntegration {
constructor(config) {
this.config = config
this.client = new MongoClient(config.connectionString)
}
async connect() {
return this.client.connect()
}
async query() {
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()
return result
} finally {
await this.client.close()
}
}
}
module.exports = {
schema: MONGODB_OPTIONS,
integration: MongoIntegration,
}

View File

@ -23,6 +23,10 @@ const POSTGRES_OPTIONS = {
type: "password",
default: "root",
},
query: {
type: "query",
required: true,
},
}
class PostgresIntegration {

View File

@ -1455,6 +1455,14 @@ bl@^1.0.0:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
bl@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5"
integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==
dependencies:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
bl@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489"
@ -1550,6 +1558,11 @@ bser@2.1.1:
dependencies:
node-int64 "^0.4.0"
bson@^1.1.4:
version "1.1.5"
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.5.tgz#2aaae98fcdf6750c0848b0cba1ddec3c73060a34"
integrity sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
@ -2307,6 +2320,11 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
denque@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
depd@^1.1.2, depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@ -5377,6 +5395,11 @@ memdown@1.4.1:
ltgt "~2.2.0"
safe-buffer "~5.1.1"
memory-pager@^1.0.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@ -5482,6 +5505,19 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4:
dependencies:
minimist "^1.2.5"
mongodb@^3.6.3:
version "3.6.3"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.3.tgz#eddaed0cc3598474d7a15f0f2a5b04848489fd05"
integrity sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==
dependencies:
bl "^2.2.1"
bson "^1.1.4"
denque "^1.4.1"
require_optional "^1.0.1"
safe-buffer "^5.1.2"
optionalDependencies:
saslprep "^1.0.0"
mri@1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
@ -6767,6 +6803,14 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
require_optional@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==
dependencies:
resolve-from "^2.0.0"
semver "^5.1.0"
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@ -6774,6 +6818,11 @@ resolve-cwd@^2.0.0:
dependencies:
resolve-from "^3.0.0"
resolve-from@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
resolve-from@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
@ -6921,6 +6970,13 @@ sanitize-s3-objectkey@^0.0.1:
resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e"
integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ==
saslprep@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226"
integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==
dependencies:
sparse-bitfield "^3.0.3"
sax@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
@ -6950,7 +7006,7 @@ semver-diff@^3.1.1:
dependencies:
semver "^6.3.0"
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@ -7184,6 +7240,13 @@ spark-md5@3.0.1:
resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d"
integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig==
sparse-bitfield@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE=
dependencies:
memory-pager "^1.0.2"
spdx-correct@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"