Merge pull request #2857 from Budibase/fix/2792
Allow SQL many to many relationships to use arbitrarily named columns in junction table
This commit is contained in:
commit
bfb7766333
|
@ -156,6 +156,8 @@
|
|||
...relateTo,
|
||||
through: through._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
|
||||
|
@ -251,6 +253,22 @@
|
|||
bind:error={errors.through}
|
||||
bind:value={fromRelationship.through}
|
||||
/>
|
||||
{#if fromTable && toTable && through}
|
||||
<Select
|
||||
label={`Foreign Key (${fromTable?.name})`}
|
||||
options={Object.keys(through?.schema)}
|
||||
on:change={() => ($touched.fromForeign = true)}
|
||||
bind:error={errors.fromForeign}
|
||||
bind:value={fromRelationship.throughTo}
|
||||
/>
|
||||
<Select
|
||||
label={`Foreign Key (${toTable?.name})`}
|
||||
options={Object.keys(through?.schema)}
|
||||
on:change={() => ($touched.toForeign = true)}
|
||||
bind:error={errors.toForeign}
|
||||
bind:value={fromRelationship.throughFrom}
|
||||
/>
|
||||
{/if}
|
||||
{:else if fromRelationship?.relationshipType && toTable}
|
||||
<Select
|
||||
label={`Foreign Key (${toTable?.name})`}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
db:
|
||||
container_name: postgres
|
||||
image: postgres
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: root
|
||||
POSTGRES_DB: main
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
#- pg_data:/var/lib/postgresql/data/
|
||||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
|
||||
pgadmin:
|
||||
container_name: pgadmin-pg
|
||||
image: dpage/pgadmin4
|
||||
restart: always
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: root@root.com
|
||||
PGADMIN_DEFAULT_PASSWORD: root
|
||||
ports:
|
||||
- "5050:80"
|
||||
|
||||
#volumes:
|
||||
# pg_data:
|
|
@ -0,0 +1,41 @@
|
|||
SELECT 'CREATE DATABASE main'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'main')\gexec
|
||||
|
||||
CREATE TABLE categories
|
||||
(
|
||||
name text COLLATE pg_catalog."default",
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
CONSTRAINT categories_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE customers
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
name text COLLATE pg_catalog."default",
|
||||
email text COLLATE pg_catalog."default",
|
||||
age integer,
|
||||
"dateOfBirth" date,
|
||||
CONSTRAINT customers_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE customer_category
|
||||
(
|
||||
customer_id integer,
|
||||
category_id integer,
|
||||
notes text COLLATE pg_catalog."default",
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
CONSTRAINT "Category" FOREIGN KEY (category_id)
|
||||
REFERENCES public.categories (id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE NO ACTION
|
||||
NOT VALID,
|
||||
CONSTRAINT "Customer" FOREIGN KEY (customer_id)
|
||||
REFERENCES public.customers (id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE NO ACTION
|
||||
NOT VALID
|
||||
);
|
||||
|
||||
|
||||
INSERT INTO customers (name, email, age) VALUES ('Mike', 'mike@mike.com', 30);
|
||||
INSERT INTO categories (name) VALUES ('Books');
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
docker-compose down
|
||||
docker volume prune -f
|
|
@ -205,9 +205,9 @@ module External {
|
|||
} else {
|
||||
// we're not inserting a doc, will be a bunch of update calls
|
||||
const isUpdate = !field.through
|
||||
const thisKey: string = isUpdate ? "id" : linkTablePrimary
|
||||
const thisKey: string = isUpdate ? "id" : (field.throughTo || linkTablePrimary)
|
||||
// @ts-ignore
|
||||
const otherKey: string = isUpdate ? field.fieldName : tablePrimary
|
||||
const otherKey: string = isUpdate ? field.fieldName : (field.throughFrom || tablePrimary)
|
||||
row[key].map((relationship: any) => {
|
||||
// we don't really support composite keys for relationships, this is why [0] is used
|
||||
manyRelationships.push({
|
||||
|
@ -328,12 +328,11 @@ module External {
|
|||
if (!table.primary || !linkTable.primary) {
|
||||
continue
|
||||
}
|
||||
const definition = {
|
||||
const definition: any = {
|
||||
// if no foreign key specified then use the name of the field in other table
|
||||
from: field.foreignKey || table.primary[0],
|
||||
to: field.fieldName,
|
||||
tableName: linkTableName,
|
||||
through: undefined,
|
||||
// need to specify where to put this back into
|
||||
column: fieldName,
|
||||
}
|
||||
|
@ -343,8 +342,10 @@ module External {
|
|||
)
|
||||
definition.through = throughTableName
|
||||
// don't support composite keys for relationships
|
||||
definition.from = table.primary[0]
|
||||
definition.to = linkTable.primary[0]
|
||||
definition.from = field.throughFrom || table.primary[0]
|
||||
definition.to = field.throughTo || linkTable.primary[0]
|
||||
definition.fromPrimary = table.primary[0]
|
||||
definition.toPrimary = linkTable.primary[0]
|
||||
}
|
||||
relationships.push(definition)
|
||||
}
|
||||
|
@ -369,7 +370,8 @@ module External {
|
|||
}
|
||||
const isMany = field.relationshipType === RelationshipTypes.MANY_TO_MANY
|
||||
const tableId = isMany ? field.through : field.tableId
|
||||
const fieldName = isMany ? primaryKey : field.fieldName
|
||||
const manyKey = field.throughFrom || primaryKey
|
||||
const fieldName = isMany ? manyKey : field.fieldName
|
||||
const response = await makeExternalQuery(this.appId, {
|
||||
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
||||
filters: {
|
||||
|
|
|
@ -15,6 +15,8 @@ export interface FieldSchema {
|
|||
through?: string
|
||||
foreignKey?: string
|
||||
autocolumn?: boolean
|
||||
throughFrom?: string
|
||||
throughTo?: string
|
||||
constraints?: {
|
||||
type?: string
|
||||
email?: boolean
|
||||
|
|
|
@ -121,6 +121,8 @@ export interface RelationshipsJson {
|
|||
through?: string
|
||||
from?: string
|
||||
to?: string
|
||||
fromPrimary?: string
|
||||
toPrimary?: string
|
||||
tableName: string
|
||||
column: string
|
||||
}
|
||||
|
|
|
@ -112,14 +112,16 @@ function addRelationships(
|
|||
)
|
||||
} else {
|
||||
const throughTable = relationship.through
|
||||
const fromPrimary = relationship.fromPrimary
|
||||
const toPrimary = relationship.toPrimary
|
||||
query = query
|
||||
// @ts-ignore
|
||||
.leftJoin(
|
||||
throughTable,
|
||||
`${fromTable}.${from}`,
|
||||
`${fromTable}.${fromPrimary}`,
|
||||
`${throughTable}.${from}`
|
||||
)
|
||||
.leftJoin(toTable, `${toTable}.${to}`, `${throughTable}.${to}`)
|
||||
.leftJoin(toTable, `${toTable}.${toPrimary}`, `${throughTable}.${to}`)
|
||||
}
|
||||
}
|
||||
return query
|
||||
|
|
Loading…
Reference in New Issue