-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create service which encodes the sql-command for creating a foreign-key
- Loading branch information
1 parent
8888c26
commit 1def889
Showing
8 changed files
with
341 additions
and
6 deletions.
There are no files selected for viewing
47 changes: 47 additions & 0 deletions
47
...dmin/bar/siard2/cmd/usecases/schemamapping/PostgresDownloadMultiSchemaSiardProjectIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package ch.admin.bar.siard2.cmd.usecases.schemamapping; | ||
|
||
import ch.admin.bar.siard2.cmd.SiardFromDb; | ||
import ch.admin.bar.siard2.cmd.SiardToDb; | ||
import ch.admin.bar.siard2.cmd.utils.SiardProjectExamples; | ||
import ch.admin.bar.siard2.cmd.utils.siard.SiardArchivesHandler; | ||
import ch.admin.bar.siard2.cmd.utils.siard.assertions.SiardArchiveAssertions; | ||
import lombok.val; | ||
import org.junit.Assert; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.testcontainers.containers.PostgreSQLContainer; | ||
import org.testcontainers.utility.DockerImageName; | ||
|
||
import java.io.IOException; | ||
import java.sql.SQLException; | ||
|
||
public class PostgresDownloadMultiSchemaSiardProjectIT { | ||
|
||
public final static String CREATE_MULTIPLE_SCHEMAS_SCRIPT = "usecases/schemamapping/create-multiple-schemas-with-multiple-tables_postgres.sql"; | ||
|
||
@Rule | ||
public SiardArchivesHandler siardArchivesHandler = new SiardArchivesHandler(); | ||
|
||
@Rule | ||
public PostgreSQLContainer<?> db = new PostgreSQLContainer<>(DockerImageName.parse("postgres:13")) | ||
.withInitScript(CREATE_MULTIPLE_SCHEMAS_SCRIPT); | ||
|
||
@Test | ||
public void uploadAndDownload_expectNoExceptions() throws IOException, SQLException, ClassNotFoundException { | ||
// given | ||
val actualArchive = siardArchivesHandler.prepareEmpty(); | ||
|
||
// when | ||
SiardFromDb siardFromDb = new SiardFromDb(new String[]{ | ||
"-o", | ||
"-j:" + db.getJdbcUrl(), | ||
"-u:" + db.getUsername(), | ||
"-p:" + db.getPassword(), | ||
"-s:" + actualArchive.getPathToArchiveFile() | ||
}); | ||
|
||
// then | ||
actualArchive.preserveArchive(); | ||
Assert.assertEquals(SiardFromDb.iRETURN_OK, siardFromDb.getReturn()); | ||
} | ||
} |
93 changes: 93 additions & 0 deletions
93
...ch/admin/bar/siard2/cmd/usecases/schemamapping/PostgresRenameSchemasUploadDownloadIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package ch.admin.bar.siard2.cmd.usecases.schemamapping; | ||
|
||
import ch.admin.bar.siard2.cmd.SiardFromDb; | ||
import ch.admin.bar.siard2.cmd.SiardToDb; | ||
import ch.admin.bar.siard2.cmd.utils.siard.SiardArchivesHandler; | ||
import ch.admin.bar.siard2.cmd.utils.siard.assertions.SiardArchiveAssertions; | ||
import ch.admin.bar.siard2.cmd.utils.siard.model.utils.Id; | ||
import ch.admin.bar.siard2.cmd.utils.siard.model.utils.QualifiedTableId; | ||
import lombok.val; | ||
import org.assertj.core.api.Assertions; | ||
import org.junit.Assert; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.testcontainers.containers.PostgreSQLContainer; | ||
import org.testcontainers.utility.DockerImageName; | ||
|
||
import java.io.IOException; | ||
import java.sql.SQLException; | ||
|
||
public class PostgresRenameSchemasUploadDownloadIT { | ||
|
||
/** | ||
* The file contains two schemes (Schema1 and Schema2) and each of it contains two tables | ||
* (Schema1.Table1, Schema1.Table2, Schema2.Table3 and Schema2.Table4). | ||
* </p> | ||
* See usecases/schemamapping/create-multiple-schemas-with-multiple-tables_postgres.sql (Script which is used in | ||
* {@link PostgresDownloadMultiSchemaSiardProjectIT} for generating the SIARD archive) | ||
*/ | ||
public final static String SIARD_FILE = "usecases/schemamapping/multiple-schemas-with-multiple-tables.siard"; | ||
|
||
@Rule | ||
public SiardArchivesHandler siardArchivesHandler = new SiardArchivesHandler(); | ||
|
||
@Rule | ||
public PostgreSQLContainer<?> db = new PostgreSQLContainer<>(DockerImageName.parse("postgres:13")); | ||
|
||
@Test | ||
public void uploadAndDownload_expectNoExceptions() throws IOException, SQLException, ClassNotFoundException { | ||
// given | ||
val expectedArchive = siardArchivesHandler.prepareResource(SIARD_FILE); | ||
val actualArchive = siardArchivesHandler.prepareEmpty(); | ||
|
||
// when | ||
SiardToDb siardToDb = new SiardToDb(new String[]{ | ||
"-o", | ||
"-j:" + db.getJdbcUrl(), | ||
"-u:" + db.getUsername(), | ||
"-p:" + db.getPassword(), | ||
"-s:" + expectedArchive.getPathToArchiveFile(), | ||
"schema1", "editedSchema1", | ||
"schema2", "editedSchema2" | ||
}); | ||
SiardFromDb siardFromDb = new SiardFromDb(new String[]{ | ||
"-o", | ||
"-j:" + db.getJdbcUrl(), | ||
"-u:" + db.getUsername(), | ||
"-p:" + db.getPassword(), | ||
"-s:" + actualArchive.getPathToArchiveFile() | ||
}); | ||
|
||
// then | ||
Assert.assertEquals(SiardToDb.iRETURN_OK, siardToDb.getReturn()); | ||
Assert.assertEquals(SiardFromDb.iRETURN_OK, siardFromDb.getReturn()); | ||
|
||
val metadataExplorer = actualArchive.exploreMetadata(); | ||
|
||
Assertions.assertThat(metadataExplorer.tryFindByTableId(QualifiedTableId.builder() | ||
.schemaId(Id.of("editedSchema1")) | ||
.tableId(Id.of("table1")) | ||
.build())) | ||
.isPresent(); | ||
|
||
Assertions.assertThat(metadataExplorer.tryFindByTableId(QualifiedTableId.builder() | ||
.schemaId(Id.of("editedSchema1")) | ||
.tableId(Id.of("table2")) | ||
.build())) | ||
.isPresent(); | ||
|
||
Assertions.assertThat(metadataExplorer.tryFindByTableId(QualifiedTableId.builder() | ||
.schemaId(Id.of("editedSchema2")) | ||
.tableId(Id.of("table3")) | ||
.build())) | ||
.isPresent(); | ||
|
||
Assertions.assertThat(metadataExplorer.tryFindByTableId(QualifiedTableId.builder() | ||
.schemaId(Id.of("editedSchema2")) | ||
.tableId(Id.of("table4")) | ||
.build())) | ||
.isPresent(); | ||
|
||
// TODO: Extend for types... | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
...esources/usecases/schemamapping/create-multiple-schemas-with-multiple-tables_postgres.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
-- Create Schema1 | ||
CREATE SCHEMA Schema1; | ||
|
||
-- Create tables in Schema1 | ||
CREATE TABLE Schema1.Table1 | ||
( | ||
ID SERIAL PRIMARY KEY, | ||
Name VARCHAR(50) | ||
); | ||
|
||
CREATE TABLE Schema1.Table2 | ||
( | ||
ID SERIAL PRIMARY KEY, | ||
Description TEXT | ||
); | ||
|
||
-- Insert data into Schema1.Table1 | ||
INSERT INTO Schema1.Table1 (Name) | ||
VALUES ('John Doe'), | ||
('Jane Smith'), | ||
('Bob Johnson'); | ||
|
||
-- Insert data into Schema1.Table2 | ||
INSERT INTO Schema1.Table2 (Description) | ||
VALUES ('Sample description 1'), | ||
('Sample description 2'), | ||
('Sample description 3'); | ||
|
||
|
||
-- Create Schema2 | ||
CREATE SCHEMA Schema2; | ||
|
||
-- Create tables in Schema2 | ||
CREATE TABLE Schema2.Table3 | ||
( | ||
ID SERIAL PRIMARY KEY, | ||
Category VARCHAR(50) | ||
); | ||
|
||
CREATE TABLE Schema2.Table4 | ||
( | ||
ID SERIAL PRIMARY KEY, | ||
Quantity INT | ||
); | ||
|
||
-- Insert data into Schema2.Table3 | ||
INSERT INTO Schema2.Table3 (Category) | ||
VALUES ('Category A'), | ||
('Category B'), | ||
('Category C'); | ||
|
||
-- Insert data into Schema2.Table4 | ||
INSERT INTO Schema2.Table4 (Quantity) | ||
VALUES (10), | ||
(20), | ||
(30); | ||
|
||
-- Additional comments | ||
COMMENT ON TABLE Schema1.Table1 IS 'This is Table1 in Schema1.'; | ||
COMMENT ON COLUMN Schema1.Table1.ID IS 'Primary key for Table1.'; | ||
|
||
COMMENT ON TABLE Schema2.Table3 IS 'This is Table3 in Schema2.'; | ||
COMMENT ON COLUMN Schema2.Table3.ID IS 'Primary key for Table3.'; |
Binary file added
BIN
+16.2 KB
...egrationTest/resources/usecases/schemamapping/multiple-schemas-with-multiple-tables.siard
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
src/main/java/ch/admin/bar/siard2/cmd/sql/TableDependantStatementGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package ch.admin.bar.siard2.cmd.sql; | ||
|
||
import ch.admin.bar.siard2.api.MetaForeignKey; | ||
import ch.admin.bar.siard2.cmd.ArchiveMapping; | ||
import ch.admin.bar.siard2.cmd.SchemaMapping; | ||
import ch.admin.bar.siard2.cmd.TableMapping; | ||
import ch.admin.bar.siard2.cmd.utils.ListAssembler; | ||
import lombok.Builder; | ||
import lombok.NonNull; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.Value; | ||
import lombok.extern.slf4j.Slf4j; | ||
import lombok.val; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
public class TableDependantStatementGenerator { | ||
|
||
private final String schemaName; | ||
private final String tableName; | ||
|
||
private final ArchiveMapping archiveMapping; | ||
|
||
// String createForeignKeyQuery = "ALTER TABLE deine_tabelle " | ||
// + "ADD CONSTRAINT fk_foreign_key_name " | ||
// + "FOREIGN KEY (spalte_in_deiner_tabelle) " | ||
// + "REFERENCES referenzierte_tabelle (referenzierte_spalte) " | ||
// + "ON DELETE CASCADE " | ||
// + "ON UPDATE CASCADE"; | ||
private String createConstraintStatement(final MetaForeignKey foreignKeyMetaData) { | ||
if (foreignKeyMetaData.getReferences() == 0) { | ||
return ""; | ||
} | ||
|
||
val references = resolveReferences(foreignKeyMetaData); | ||
|
||
val referencedTable = references.stream() | ||
.map(foreignKeyReference -> String.format( | ||
"%s.%s", | ||
foreignKeyReference.getReferenced().getSchema(), | ||
foreignKeyReference.getReferenced().getTable())) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalStateException("No references found")); | ||
|
||
val sb = new StringBuilder("ADD CONSTRAINT ").append(foreignKeyMetaData.getName()) | ||
.append(" FOREIGN KEY(") | ||
.append(references.stream() | ||
.map(foreignKeyReference -> foreignKeyReference.getColumn().getColumn()) | ||
.collect(Collectors.joining(", "))) | ||
.append(")") | ||
.append("REFERENCES ") | ||
.append(referencedTable) | ||
.append(" (") | ||
.append(references.stream() | ||
.map(foreignKeyReference -> foreignKeyReference.getReferenced().getColumn()) | ||
.collect(Collectors.joining(", "))) | ||
.append(")"); | ||
|
||
// actions | ||
Optional.ofNullable(foreignKeyMetaData.getDeleteAction()) | ||
.ifPresent(action -> sb.append(" ON DELETE ").append(action)); | ||
|
||
Optional.ofNullable(foreignKeyMetaData.getUpdateAction()) | ||
.ifPresent(action -> sb.append(" ON UPDATE ").append(action)); | ||
|
||
return sb.toString(); | ||
} | ||
|
||
private List<ForeignKeyReference> resolveReferences(final MetaForeignKey foreignKeyMetaData) { | ||
val referencedColumns = ListAssembler.assemble( | ||
foreignKeyMetaData.getReferences(), | ||
index -> { | ||
val referenced = QualifiedColumnId.builder() | ||
.schema(foreignKeyMetaData.getReferencedSchema()) | ||
.table(foreignKeyMetaData.getReferencedTable()) | ||
.column(foreignKeyMetaData.getReferenced(index)) | ||
.build(); | ||
|
||
val column = QualifiedColumnId.builder() | ||
.schema(schemaName) | ||
.table(tableName) | ||
.column(foreignKeyMetaData.getColumn(index)) | ||
.build(); | ||
|
||
return ForeignKeyReference.builder() | ||
.referenced(referenced) | ||
.column(column) | ||
.build(); | ||
}); | ||
|
||
return referencedColumns.stream() | ||
.map(this::resolveMappings) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private ForeignKeyReference resolveMappings(ForeignKeyReference origForeignKeyReference) { | ||
return origForeignKeyReference.toBuilder() | ||
.column(resolveMappings(origForeignKeyReference.getColumn())) | ||
.referenced(resolveMappings(origForeignKeyReference.getReferenced())) | ||
.build(); | ||
} | ||
|
||
private QualifiedColumnId resolveMappings(QualifiedColumnId origQualifiedColumnId) { | ||
final SchemaMapping sm = archiveMapping.getSchemaMapping(origQualifiedColumnId.getSchema()); // TODO FIXME can return null | ||
final TableMapping tm = sm.getTableMapping(origQualifiedColumnId.getTable()); // TODO FIXME can return null | ||
|
||
return origQualifiedColumnId.toBuilder() | ||
.schema(sm.getMappedSchemaName()) | ||
.table(tm.getMappedTableName()) | ||
.column(tm.getMappedColumnName(origQualifiedColumnId.getColumn())) // TODO FIXME can return null | ||
.build(); | ||
} | ||
|
||
@Value | ||
@Builder(toBuilder = true) | ||
private static class ForeignKeyReference { | ||
@NonNull QualifiedColumnId column; | ||
@NonNull QualifiedColumnId referenced; | ||
} | ||
|
||
@Value | ||
@Builder(toBuilder = true) | ||
private static class QualifiedColumnId { | ||
@NonNull String schema; | ||
@NonNull String table; | ||
@NonNull String column; | ||
} | ||
} |