77import io .github .ngbsn .model .Table ;
88import io .github .ngbsn .model .annotations .field .*;
99import io .github .ngbsn .util .Util ;
10- import org .apache .commons .text .WordUtils ;
1110
1211import java .util .ArrayList ;
1312import java .util .HashSet ;
1413import java .util .List ;
1514import java .util .Optional ;
16- import java .util .stream .Collectors ;
1715import java .util .stream .Stream ;
1816
1917/**
@@ -111,12 +109,19 @@ private static void handleSingleForeignKey(final Table table, final ForeignKeyCo
111109 private static void handleCompositeForeignKey (final Table table , final Table parentTable , final ForeignKeyConstraint foreignKeyConstraint ,
112110 final Column parentTableField , final EmbeddableClass embeddableId , final List <Column > allPrimaryKeyColumns ) {
113111 List <Column > listOfForeignKeyColumns = listOfForeignKeys (table , foreignKeyConstraint );
114- //Case: Shared Composite Primary Key
115- //If composite foreign key is inside the composite primary key, don't remove them from table.
116- //This case assumes there is a primary composite key
117- //Add a @MapsId annotation to the referenced table field
118- if (embeddableId != null && new HashSet <>(allPrimaryKeyColumns ).containsAll (listOfForeignKeyColumns )) {
119- handleCompositeForeignKeyInsideCompositePrimaryKey (table , parentTable , parentTableField , embeddableId , listOfForeignKeyColumns );
112+ if (embeddableId != null && new HashSet <>(allPrimaryKeyColumns ).equals (new HashSet <>(listOfForeignKeyColumns ))){
113+ //Case: Shared Composite Primary Key
114+ //This case assumes there is a primary composite key
115+ //If composite foreign key has same columns as composite primary key, don't remove them from table.
116+ //Add a @MapsId annotation to the referenced table field
117+ handleCompositeForeignKeySameAsCompositePrimaryKey (table , parentTable , parentTableField );
118+ }
119+ else if (embeddableId != null && new HashSet <>(allPrimaryKeyColumns ).containsAll (listOfForeignKeyColumns )) {
120+ //Case: Shared Composite Primary Key
121+ //This case assumes there is a primary composite key
122+ //If composite foreign key is inside the composite primary key, don't remove them from table.
123+ //Add a @MapsId annotation to the referenced table field
124+ handleCompositeForeignKeyInsideCompositePrimaryKey (parentTable , parentTableField , embeddableId , listOfForeignKeyColumns );
120125 } else {
121126 //Case1: There is no Composite primary key
122127 //TODO can part of Composite foreign key be a primary key. Is this applicable only to self referencing cases?
@@ -136,38 +141,40 @@ private static void handleCompositeForeignKey(final Table table, final Table par
136141 parentTableField .getAnnotations ().add (JoinColumnsAnnotation .builder ().joinColumns (joinColumns ).build ().toString ());
137142 }
138143
139- private static void handleCompositeForeignKeyInsideCompositePrimaryKey (final Table table , final Table parentTable , final Column parentTableField ,
144+ private static void handleCompositeForeignKeySameAsCompositePrimaryKey (final Table table , final Table parentTable , final Column parentTableField ) {
145+ //Reuse the parent table embeddedId class to create a field for the shared primary key
146+ EmbeddableClass parentEmbeddedId = parentTable .getEmbeddedId ();
147+ Column parentEmbeddedIdColumn = new Column ();
148+ parentEmbeddedIdColumn .setType (parentTable .getClassName () + "." + parentEmbeddedId .getClassName ());
149+ parentEmbeddedIdColumn .setFieldName (parentEmbeddedId .getFieldName ());
150+ parentEmbeddedIdColumn .setEmbeddedId (true );
151+ table .getColumns ().add (parentEmbeddedIdColumn );
152+ //Remove EmbeddedID from child table
153+ table .setEmbeddedId (null );
154+
155+ //Add @MapsId annotation, as the shared primary key is not set explicitly in this table, rather managed through parent primary key
156+ parentTableField .getAnnotations ().add (MapsIdAnnotation .builder ().fieldName (parentEmbeddedIdColumn .getFieldName ()).build ().toString ());
157+ }
158+
159+ private static void handleCompositeForeignKeyInsideCompositePrimaryKey (final Table parentTable , final Column parentTableField ,
140160 final EmbeddableClass embeddableId , final List <Column > listOfForeignKeyColumns ) {
161+ //remove all foreign key columns as they are tracked by the EmbeddedID field of parent
162+ listOfForeignKeyColumns .forEach (column ->
163+ embeddableId .getColumns ().remove (column )
164+ );
165+
166+ //Reuse the parent table embeddedId class to create a field for the shared primary key
167+ EmbeddableClass parentEmbeddedId = parentTable .getEmbeddedId ();
168+ Column parentEmbeddedIdColumn = new Column ();
169+ parentEmbeddedIdColumn .setType (parentTable .getClassName () + "." + parentEmbeddedId .getClassName ());
170+ parentEmbeddedIdColumn .setFieldName (parentEmbeddedId .getFieldName ());
171+ embeddableId .getColumns ().add (parentEmbeddedIdColumn );
141172
142- EmbeddableClass foreignCompositeKeyEmbedded = new EmbeddableClass (); //Create a new embeddable for this foreign composite key
143- String embeddableName = listOfForeignKeyColumns .stream ().map (Column ::getFieldName ).collect (Collectors .joining ());
144- foreignCompositeKeyEmbedded .setClassName (WordUtils .capitalize (embeddableName ));
145- foreignCompositeKeyEmbedded .setFieldName (embeddableName );
146- table .getEmbeddableClasses ().add (foreignCompositeKeyEmbedded ); //add new embeddable to the Table list of Embeddables
147- listOfForeignKeyColumns .forEach (column -> {
148- //Remove existing column annotations and add again with updatable=false, insertable=false.
149- //This is necessary as the column is inserted/updated through foreign key
150- column .getAnnotations ().removeIf (s -> s .contains ("@Column" ));
151- column .getAnnotations ().add (ColumnAnnotation .builder ()
152- .columnName (column .getColumnName ())
153- .updatable (false )
154- .insertable (false )
155- .build ().toString ());
156-
157- //add the individual foreign keys columns to the newly created embeddable
158- foreignCompositeKeyEmbedded .getColumns ().add (column );
159- //Remove the individual foreign keys from EmbeddedId and add the newly created embeddable into EmbeddedId
160- embeddableId .getColumns ().remove (column );
161- });
162- Column foreignCompositeField = new Column ();
163- foreignCompositeField .setType (foreignCompositeKeyEmbedded .getClassName ());
164- foreignCompositeField .setFieldName (foreignCompositeKeyEmbedded .getFieldName ());
165- embeddableId .getColumns ().add (foreignCompositeField );
166-
167- if (embeddableId .getFieldName () != null )
168- parentTableField .getAnnotations ().add (MapsIdAnnotation .builder ().fieldName (foreignCompositeField .getFieldName ()).build ().toString ());
173+ //Add @MapsId annotation, as the shared primary key is not set explicitly in this table, rather managed through parent primary key
174+ parentTableField .getAnnotations ().add (MapsIdAnnotation .builder ().fieldName (parentEmbeddedIdColumn .getFieldName ()).build ().toString ());
169175 }
170176
177+
171178 /**
172179 * Convert column names in foreignKeyConstraint to List of Column models
173180 * @param table table
0 commit comments