Saving. TODO - Validation
This commit is contained in:
parent
bb77871b59
commit
fc73a2f358
|
@ -0,0 +1,271 @@
|
||||||
|
<script>
|
||||||
|
import { RelationshipTypes } from "constants/backend"
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Input,
|
||||||
|
ModalContent,
|
||||||
|
Select,
|
||||||
|
Detail,
|
||||||
|
Body,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import { tables } from "stores/backend"
|
||||||
|
import { Helpers } from "@budibase/bbui"
|
||||||
|
|
||||||
|
export let save
|
||||||
|
export let datasource
|
||||||
|
export let plusTables = []
|
||||||
|
export let fromRelationship = {}
|
||||||
|
export let toRelationship = {}
|
||||||
|
export let close
|
||||||
|
|
||||||
|
const relationshipTypes = [
|
||||||
|
{
|
||||||
|
label: "One to Many",
|
||||||
|
value: RelationshipTypes.MANY_TO_ONE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Many to Many",
|
||||||
|
value: RelationshipTypes.MANY_TO_MANY,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let originalFromColumnName = fromRelationship.name,
|
||||||
|
originalToColumnName = toRelationship.name
|
||||||
|
let originalFromTable = plusTables.find(
|
||||||
|
table => table._id === toRelationship?.tableId
|
||||||
|
)
|
||||||
|
let originalToTable = plusTables.find(
|
||||||
|
table => table._id === fromRelationship?.tableId
|
||||||
|
)
|
||||||
|
|
||||||
|
let tableOptions
|
||||||
|
let fromPrimary,
|
||||||
|
fromForeign,
|
||||||
|
fromTable,
|
||||||
|
toTable,
|
||||||
|
throughTable,
|
||||||
|
fromColumn,
|
||||||
|
toColumn
|
||||||
|
let fromId, toId, throughId, throughToKey, throughFromKey
|
||||||
|
let isManyToMany, isManyToOne, relationshipType
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (!fromPrimary) {
|
||||||
|
fromPrimary = fromRelationship.foreignKey
|
||||||
|
fromForeign = toRelationship.foreignKey
|
||||||
|
}
|
||||||
|
if (!fromColumn) {
|
||||||
|
fromColumn = toRelationship.name
|
||||||
|
fromId = toRelationship.tableId
|
||||||
|
}
|
||||||
|
if (!toColumn) {
|
||||||
|
toColumn = fromRelationship.name
|
||||||
|
toId = fromRelationship.tableId
|
||||||
|
}
|
||||||
|
if (!throughId) {
|
||||||
|
throughId = fromRelationship.through
|
||||||
|
throughFromKey = fromRelationship.throughFrom
|
||||||
|
throughToKey = fromRelationship.throughTo
|
||||||
|
}
|
||||||
|
if (!relationshipType) {
|
||||||
|
relationshipType = fromRelationship.relationshipType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: tableOptions = plusTables.map(table => ({
|
||||||
|
label: table.name,
|
||||||
|
value: table._id,
|
||||||
|
}))
|
||||||
|
|
||||||
|
$: isManyToMany = relationshipType === RelationshipTypes.MANY_TO_MANY
|
||||||
|
$: isManyToOne = relationshipType === RelationshipTypes.MANY_TO_ONE
|
||||||
|
$: fromTable = plusTables.find(table => table._id === fromId)
|
||||||
|
$: toTable = plusTables.find(table => table._id === toId)
|
||||||
|
$: throughTable = plusTables.find(table => table._id === throughId)
|
||||||
|
|
||||||
|
$: toRelationship.relationshipType = fromRelationship?.relationshipType
|
||||||
|
|
||||||
|
function buildRelationships() {
|
||||||
|
const id = Helpers.uuid()
|
||||||
|
//Map temporary variables
|
||||||
|
let relateFrom = {
|
||||||
|
...fromRelationship,
|
||||||
|
tableId: toId,
|
||||||
|
name: toColumn,
|
||||||
|
relationshipType,
|
||||||
|
fieldName: fromForeign,
|
||||||
|
through: throughId,
|
||||||
|
throughFrom: throughFromKey,
|
||||||
|
throughTo: throughToKey,
|
||||||
|
type: "link",
|
||||||
|
main: true,
|
||||||
|
_id: id,
|
||||||
|
}
|
||||||
|
let relateTo = (toRelationship = {
|
||||||
|
...toRelationship,
|
||||||
|
tableId: fromId,
|
||||||
|
name: fromColumn,
|
||||||
|
through: throughId,
|
||||||
|
type: "link",
|
||||||
|
_id: id,
|
||||||
|
})
|
||||||
|
|
||||||
|
// if any to many only need to check from
|
||||||
|
const manyToMany =
|
||||||
|
relateFrom.relationshipType === RelationshipTypes.MANY_TO_MANY
|
||||||
|
|
||||||
|
if (!manyToMany) {
|
||||||
|
delete relateFrom.through
|
||||||
|
delete relateTo.through
|
||||||
|
}
|
||||||
|
|
||||||
|
// [0] is because we don't support composite keys for relationships right now
|
||||||
|
if (manyToMany) {
|
||||||
|
relateFrom = {
|
||||||
|
...relateFrom,
|
||||||
|
through: throughTable._id,
|
||||||
|
fieldName: toTable.primary[0],
|
||||||
|
}
|
||||||
|
relateTo = {
|
||||||
|
...relateTo,
|
||||||
|
through: throughTable._id,
|
||||||
|
fieldName: fromTable.primary[0],
|
||||||
|
throughFrom: relateFrom.throughTo,
|
||||||
|
throughTo: relateFrom.throughFrom,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the relateFrom.fieldName should remain the same, as it is the foreignKey in the other
|
||||||
|
// table, this is due to the way that budibase represents relationships, the fieldName in a
|
||||||
|
// link column schema is the column linked to (FK in this case). The foreignKey column is
|
||||||
|
// essentially what is linked to in the from table, this is unique to SQL as this isn't a feature
|
||||||
|
// of Budibase internal tables.
|
||||||
|
// Essentially this means the fieldName is what we are linking to in the other table, and the
|
||||||
|
// foreignKey is what is linking out of the current table.
|
||||||
|
relateFrom = {
|
||||||
|
...relateFrom,
|
||||||
|
foreignKey: fromPrimary,
|
||||||
|
}
|
||||||
|
relateTo = {
|
||||||
|
...relateTo,
|
||||||
|
relationshipType: RelationshipTypes.ONE_TO_MANY,
|
||||||
|
foreignKey: relateFrom.fieldName,
|
||||||
|
fieldName: fromPrimary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fromRelationship = relateFrom
|
||||||
|
toRelationship = relateTo
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeExistingRelationship() {
|
||||||
|
if (originalFromTable && originalFromColumnName) {
|
||||||
|
delete datasource.entities[originalFromTable.name].schema[
|
||||||
|
originalFromColumnName
|
||||||
|
]
|
||||||
|
}
|
||||||
|
if (originalToTable && originalToColumnName) {
|
||||||
|
delete datasource.entities[originalToTable.name].schema[
|
||||||
|
originalToColumnName
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveRelationship() {
|
||||||
|
buildRelationships()
|
||||||
|
removeExistingRelationship()
|
||||||
|
|
||||||
|
// source of relationship
|
||||||
|
datasource.entities[fromTable.name].schema[fromRelationship.name] =
|
||||||
|
fromRelationship
|
||||||
|
// save other side of relationship in the other schema
|
||||||
|
datasource.entities[toTable.name].schema[toRelationship.name] =
|
||||||
|
toRelationship
|
||||||
|
|
||||||
|
await save()
|
||||||
|
}
|
||||||
|
async function deleteRelationship() {
|
||||||
|
removeExistingRelationship()
|
||||||
|
await save()
|
||||||
|
await tables.fetch()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ModalContent
|
||||||
|
title="Define Relationship COPY"
|
||||||
|
confirmText="Save"
|
||||||
|
onConfirm={saveRelationship}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
label="Relationship type"
|
||||||
|
options={relationshipTypes}
|
||||||
|
bind:value={relationshipType}
|
||||||
|
/>
|
||||||
|
<div class="headings">
|
||||||
|
<Detail>Tables</Detail>
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
label="Select from table"
|
||||||
|
options={tableOptions}
|
||||||
|
bind:value={fromId}
|
||||||
|
on:change={e => {
|
||||||
|
fromColumn = tableOptions.find(opt => opt.value === e.detail).label
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{#if isManyToOne && fromTable}
|
||||||
|
<Select
|
||||||
|
label={`Primary Key (${fromTable.name})`}
|
||||||
|
options={Object.keys(fromTable.schema)}
|
||||||
|
bind:value={fromPrimary}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<Select
|
||||||
|
label={"Select to table"}
|
||||||
|
options={tableOptions}
|
||||||
|
bind:value={toId}
|
||||||
|
on:change={e => {
|
||||||
|
toColumn = tableOptions.find(opt => opt.value === e.detail).label
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{#if isManyToMany}
|
||||||
|
<Select label={"Through"} options={tableOptions} bind:value={throughId} />
|
||||||
|
{#if fromTable && toTable && throughTable}
|
||||||
|
<Select
|
||||||
|
label={`Foreign Key (${fromTable?.name})`}
|
||||||
|
options={Object.keys(throughTable?.schema)}
|
||||||
|
bind:value={throughToKey}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label={`Foreign Key (${toTable?.name})`}
|
||||||
|
options={Object.keys(throughTable?.schema)}
|
||||||
|
bind:value={throughFromKey}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{:else if isManyToOne && toTable}
|
||||||
|
<Select
|
||||||
|
label={`Foreign Key (${toTable?.name})`}
|
||||||
|
options={Object.keys(toTable?.schema)}
|
||||||
|
bind:value={fromForeign}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<div class="headings">
|
||||||
|
<Detail>Column names</Detail>
|
||||||
|
</div>
|
||||||
|
<Body>
|
||||||
|
Budibase manages SQL relationships as a new column in the table, please
|
||||||
|
provide a name for these columns.
|
||||||
|
</Body>
|
||||||
|
<Input label="From table column" bind:value={fromColumn} />
|
||||||
|
<Input label="To table column" bind:value={toColumn} />
|
||||||
|
<div slot="footer">
|
||||||
|
{#if originalFromColumnName != null}
|
||||||
|
<Button warning text on:click={deleteRelationship}>Delete</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</ModalContent>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.headings {
|
||||||
|
margin-top: var(--spacing-s);
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue