From 3d2ba1dd62896feb4c350f83d1df7bc7ba494b63 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Sun, 29 Sep 2024 21:32:28 +0200
Subject: [PATCH] Fixed mapping problem where UK and FK share columns they are
 inserted 				 twice

---
 .../service/SchemaServiceIntegrationTest.java |  1 +
 .../src/test/resources/init/weather.sql       |  2 +-
 dbrepo-metadata-db/1_setup-schema.sql         |  3 +-
 .../database/table/columns/TableColumn.java   |  4 +--
 .../table/columns/TableColumnConcept.java     |  3 +-
 .../table/columns/TableColumnUnit.java        |  3 +-
 .../foreignKey/ForeignKeyReference.java       |  2 ++
 .../constraints/primaryKey/PrimaryKey.java    |  4 +--
 .../table/constraints/unique/Unique.java      |  5 +--
 .../java/at/tuwien/mapper/MetadataMapper.java |  1 -
 .../service/impl/DatabaseServiceImpl.java     | 33 +++++++++++++------
 11 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java
index 540e17850a..d69ea86e68 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java
@@ -194,6 +194,7 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest {
         assertEquals(1, uniques.size());
         final UniqueDto unique0 = uniques.get(0);
         assertNotNull(unique0.getTable());
+        assertEquals("some_constraint", unique0.getName());
         assertNull(unique0.getTable().getId());
         assertEquals(TABLE_1_INTERNALNAME, unique0.getTable().getName());
         assertEquals(TABLE_1_INTERNALNAME, unique0.getTable().getInternalName());
diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql
index 7c3ca99ce3..10cbf85565 100644
--- a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql
+++ b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql
@@ -17,7 +17,7 @@ CREATE TABLE weather_aus
     mintemp  DOUBLE PRECISION NULL,
     rainfall DOUBLE PRECISION NULL,
     FOREIGN KEY (location) REFERENCES weather_location (location) ON DELETE SET NULL,
-    UNIQUE (`date`),
+    CONSTRAINT some_constraint UNIQUE (`date`),
     CHECK (`mintemp` > 0)
 ) WITH SYSTEM VERSIONING COMMENT 'Weather in Australia';
 
diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql
index 47ee3a95e2..9f0f2775cb 100644
--- a/dbrepo-metadata-db/1_setup-schema.sql
+++ b/dbrepo-metadata-db/1_setup-schema.sql
@@ -176,8 +176,9 @@ CREATE TABLE IF NOT EXISTS `mdb_columns`
     std_dev          Numeric     NULL,
     created          timestamp   NOT NULL DEFAULT NOW(),
     last_modified    timestamp,
+    PRIMARY KEY (ID),
     FOREIGN KEY (tID) REFERENCES mdb_tables (ID) ON DELETE CASCADE,
-    PRIMARY KEY (ID)
+    UNIQUE (tID, internal_name)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS `mdb_columns_enums`
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
index c869e41637..dd59e21003 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
@@ -24,7 +24,7 @@ import java.util.List;
 @EqualsAndHashCode(onlyExplicitlyIncluded = true)
 @EntityListeners(AuditingEntityListener.class)
 @jakarta.persistence.Table(name = "mdb_columns", uniqueConstraints = {
-        @UniqueConstraint(columnNames = {"tid", "internalName"})
+        @UniqueConstraint(columnNames = {"tID", "internal_name"})
 })
 @NamedQueries({
         @NamedQuery(name = "TableColumn.findAllByDatabaseId", query = "select c from TableColumn c where c.table.database.id = ?1"),
@@ -56,7 +56,7 @@ public class TableColumn implements Comparable<TableColumn> {
     @Column(name = "auto_generated", columnDefinition = "BOOLEAN default false")
     private Boolean autoGenerated;
 
-    @Column(nullable = false, columnDefinition = "VARCHAR(64)")
+    @Column(name = "internal_name", nullable = false, columnDefinition = "VARCHAR(64)")
     private String internalName;
 
     @Column(columnDefinition = "VARCHAR(2048)")
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java
index 080abf87cd..e53e69f498 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java
@@ -50,7 +50,8 @@ public class TableColumnConcept {
     private Instant created;
 
     @ToString.Exclude
-    @OneToMany(fetch = FetchType.LAZY)
+    @org.springframework.data.annotation.Transient
+    @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinTable(name = "mdb_columns_concepts",
             inverseJoinColumns = {
                     @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false)
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java
index 21822c5da7..df3950785e 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java
@@ -49,7 +49,8 @@ public class TableColumnUnit {
     private Instant created;
 
     @ToString.Exclude
-    @OneToMany(fetch = FetchType.LAZY)
+    @org.springframework.data.annotation.Transient
+    @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinTable(name = "mdb_columns_units",
             inverseJoinColumns = {
                     @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false)
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java
index c63cdd22e6..c5f3570099 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java
@@ -32,12 +32,14 @@ public class ForeignKeyReference {
     @JoinColumn(name = "fkid", referencedColumnName = "fkid", nullable = false)
     private ForeignKey foreignKey;
 
+    @org.springframework.data.annotation.Transient
     @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinColumns({
             @JoinColumn(name = "cid", referencedColumnName = "id", nullable = false)
     })
     private TableColumn column;
 
+    @org.springframework.data.annotation.Transient
     @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinColumns({
             @JoinColumn(name = "rcid", referencedColumnName = "id", nullable = false)
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java
index c4ccc379c5..aaa1e5fc8f 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java
@@ -27,7 +27,7 @@ public class PrimaryKey {
 
     @ToString.Exclude
     @org.springframework.data.annotation.Transient
-    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
+    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinColumns({
             @JoinColumn(name = "tid", referencedColumnName = "id", nullable = false)
     })
@@ -35,7 +35,7 @@ public class PrimaryKey {
 
     @ToString.Exclude
     @org.springframework.data.annotation.Transient
-    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
+    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinColumns({
             @JoinColumn(name = "cid", referencedColumnName = "id", nullable = false)
     })
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java
index 25ed2eae5d..c49fc48eb6 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java
@@ -33,13 +33,14 @@ public class Unique {
 
     @ToString.Exclude
     @org.springframework.data.annotation.Transient
-    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
+    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinColumns({
             @JoinColumn(name = "tid", referencedColumnName = "id")
     })
     private Table table;
 
-    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
+    @org.springframework.data.annotation.Transient
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
     @JoinTable(
             name = "mdb_constraints_unique_columns",
             joinColumns = {
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
index a9b04058e2..f6c96f133d 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
@@ -555,7 +555,6 @@ public interface MetadataMapper {
                                 ref.getColumn().setDatabaseId(table.getTdbid());
                                 ref.getReferencedColumn().setTableId(fk.getReferencedTable().getId());
                                 ref.getReferencedColumn().setDatabaseId(table.getTdbid());
-                                log.trace("mapped foreign key part ({}) reference ({})", ref.getColumn().getInternalName(), ref.getReferencedColumn().getInternalName());
                             });
                 });
         table.getConstraints()
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
index 1c91de7be1..0a962f7d6e 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
@@ -11,9 +11,11 @@ import at.tuwien.entities.container.Container;
 import at.tuwien.entities.database.*;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
+import at.tuwien.entities.database.table.constraints.Constraints;
 import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey;
 import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference;
 import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey;
+import at.tuwien.entities.database.table.constraints.unique.Unique;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.DataServiceGateway;
@@ -212,12 +214,14 @@ public class DatabaseServiceImpl implements DatabaseService {
                                 .forEach(column -> {
                                     column.setTable(tableEntity);
                                 });
+                        log.trace("mapped unique constraint: {} ({})", tableEntity.getName(), uk.getColumns().stream().map(TableColumn::getInternalName).toList());
                     });
             /* map foreign key constraint(s) */
             tableEntity.getConstraints()
                     .getForeignKeys()
                     .forEach(fk -> {
                         fk.setTable(tableEntity);
+                        log.trace("mapped foreign key constraint: {} ({}) -> {} ({})", fk.getTable().getInternalName(), fk.getReferences().stream().map(r -> r.getColumn().getInternalName()).toList(), fk.getReferencedTable().getInternalName(), fk.getReferences().stream().map(r -> r.getReferencedColumn().getInternalName()).toList());
                     });
             /* map primary key constraint */
             for (PrimaryKey key : tableEntity.getConstraints().getPrimaryKey()) {
@@ -237,7 +241,6 @@ public class DatabaseServiceImpl implements DatabaseService {
         }
         /* update referenced tables after they are known to the service */
         for (ForeignKey foreignKey : database.getTables().stream().map(t -> t.getConstraints().getForeignKeys()).flatMap(List::stream).toList()) {
-            log.trace("lookup table {} in tables: {}", foreignKey.getReferencedTable().getInternalName(), database.getTables().stream().map(Table::getInternalName).toList());
             final Optional<Table> optional = database.getTables()
                     .stream()
                     .filter(t -> t.getInternalName().equals(foreignKey.getReferencedTable().getInternalName()))
@@ -275,15 +278,25 @@ public class DatabaseServiceImpl implements DatabaseService {
                 reference.setReferencedColumn(optional2.get());
             }
         }
-        database.getTables()
-                .stream()
-                .filter(t -> t.getConstraints().getForeignKeys().size() > 0)
-                .map(t -> t.getConstraints().getForeignKeys())
-                .flatMap(List::stream)
-                .filter(fk -> fk.getReferences().size() > 1)
-                .forEach(fk -> {
-                    log.debug("");
-                });
+        /* correct the unique constraint columns */
+        for (Table table : database.getTables()) {
+            for (Unique uniqueConstraint : table.getConstraints().getUniques()) {
+                uniqueConstraint.setColumns(uniqueConstraint.getColumns()
+                        .stream()
+                        .map(column -> {
+                            final Optional<TableColumn> optional = table.getColumns()
+                                    .stream()
+                                    .filter(c -> c.getInternalName().equals(column.getInternalName()))
+                                    .findFirst();
+                            if (optional.isEmpty()) {
+                                log.error("Failed to find unique constraint column: {}", column.getInternalName());
+                                throw new IllegalArgumentException("Failed to find unique constraint column: " + column.getInternalName());
+                            }
+                            return optional.get();
+                        })
+                        .toList());
+            }
+        }
         /* update in metadata database */
         database = databaseRepository.save(database);
         /* save in search service */
-- 
GitLab