Fix for many to many relationships where the union table has arbituarily named foreign key constraint columns, an example has been provided in the scripts directory.

This commit is contained in:
mike12345567 2021-10-01 17:16:43 +01:00
parent be7d343868
commit 80e7671444
8 changed files with 107 additions and 9 deletions

View File

@ -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})`}

View File

@ -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:

View File

@ -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');

View File

@ -0,0 +1,3 @@
#!/bin/bash
docker-compose down
docker volume prune -f

View File

@ -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: {

View File

@ -15,6 +15,8 @@ export interface FieldSchema {
through?: string
foreignKey?: string
autocolumn?: boolean
throughFrom?: string
throughTo?: string
constraints?: {
type?: string
email?: boolean

View File

@ -121,6 +121,8 @@ export interface RelationshipsJson {
through?: string
from?: string
to?: string
fromPrimary?: string
toPrimary?: string
tableName: string
column: string
}

View File

@ -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