Skip to content

Commit 24f12a4

Browse files
committed
Adapted version, clean ups
1 parent 7705d96 commit 24f12a4

File tree

6 files changed

+97
-60
lines changed

6 files changed

+97
-60
lines changed

JsonExport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
///usr/bin/env jbang "$0" "$@" ; exit $?
2-
//REPOS local=file:///Users/phil/mavenrepo
3-
//DEPS org.oser.tools.jdbc:linked-db-rows:0.12-SNAPSHOT
2+
////REPOS local=file:///Users/phil/mavenrepo
3+
//DEPS org.oser.tools.jdbc:linked-db-rows:0.13
44
//DEPS info.picocli:picocli:4.7.6
55
//DEPS ch.qos.logback:logback-classic:1.5.8
66
//DEPS guru.nidi:graphviz-java:0.18.1

JsonImport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
///usr/bin/env jbang "$0" "$@" ; exit $?
2-
//REPOS local=file:///Users/phil/mavenrepo
3-
//DEPS org.oser.tools.jdbc:linked-db-rows:0.12-SNAPSHOT
2+
////REPOS local=file:///Users/phil/mavenrepo
3+
//DEPS org.oser.tools.jdbc:linked-db-rows:0.13
44
//DEPS info.picocli:picocli:4.7.6
55
//DEPS ch.qos.logback:logback-classic:1.5.8
66
import static java.lang.System.*;

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Maven dependency:
4242
<dependency>
4343
<groupId>org.oser.tools.jdbc</groupId>
4444
<artifactId>linked-db-rows</artifactId>
45-
<version>0.11</version>
45+
<version>0.13</version>
4646
</dependency>
4747
```
4848

src/main/java/org/oser/tools/jdbc/Fk.java

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@
2525
import static java.util.stream.Collectors.toList;
2626
import static org.oser.tools.jdbc.JdbcHelpers.adaptCaseForDb;
2727

28-
/** Represents one foreign key constraint in JDBC. In JDBC <em>one</em> db constraint between table 1 and table 2 has <em>two</em> representations: the link from
29-
* table 1 to table 2 and vice versa. One of the 2 constraints is <em>reverted</em>. */
28+
/**
29+
* Represents one foreign key constraint in JDBC. <a>
30+
* <p>
31+
* In JDBC <em>one</em> fk constraint between table 1 and table 2 has <em>two</em> representations: the link from
32+
* table 1 to table 2 and vice versa. One of the 2 constraints is <em>inverted</em>, refer to the field <code>inverted</code>.
33+
* <a>
34+
* Supports virtual foreign keys (that do not exist in the db).
35+
*/
3036
@Getter
3137
public class Fk {
3238
private String pktable;
@@ -39,41 +45,53 @@ public class Fk {
3945

4046
private final String keySeq;
4147
private final String fkName;
42-
/** excluded in equals! */
48+
49+
/**
50+
* The same as JDBC calls exported or imported. <br/>
51+
* inverted = false: the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table) <br/>
52+
* inverted = true: the primary key columns that are referenced by the given table's foreign key columns (the primary keys imported by a table). <br/>
53+
* <p>
54+
* Is excluded in equals.
55+
*/
4356
private boolean inverted;
4457

45-
public Fk(){ // todo rm again
58+
public Fk() { // todo rm again
4659
keySeq = "";
4760
fkName = "";
4861
}
4962

5063

51-
/** Constructor taking single values only */
64+
/**
65+
* Constructor taking single values only
66+
*/
5267
public Fk(String pktable, String pkcolumn, String fktable, String fkcolumn, String keySeq, String fkName, boolean inverted) {
5368
this.pktable = pktable;
54-
this.pkcolumn = new String[]{ pkcolumn };
69+
this.pkcolumn = new String[]{pkcolumn};
5570
this.fktable = fktable;
56-
this.fkcolumn = new String[]{ fkcolumn };
71+
this.fkcolumn = new String[]{fkcolumn};
5772
this.keySeq = keySeq;
5873
this.fkName = fkName;
5974
this.inverted = inverted;
6075
}
6176

6277
public Fk(String pktable, String[] pkcolumnArray, String fktable, String[] fkcolumnArray, String keySeq, String fkName, boolean inverted) {
6378
this.pktable = pktable;
64-
this.pkcolumn = pkcolumnArray ;
79+
this.pkcolumn = pkcolumnArray;
6580
this.fktable = fktable;
66-
this.fkcolumn = fkcolumnArray ;
81+
this.fkcolumn = fkcolumnArray;
6782
this.keySeq = keySeq;
6883
this.fkName = fkName;
6984
this.inverted = inverted;
7085
}
7186

7287

73-
88+
/**
89+
* Refer to {@link #getFksOfTable(Connection, String)}
90+
* Uses a cache.
91+
*/
7492
public static List<Fk> getFksOfTable(Connection connection, String table, Cache<String, List<Fk>> cache) throws SQLException {
7593
List<Fk> result = cache.getIfPresent(table);
76-
if (result == null){
94+
if (result == null) {
7795
result = getFksOfTable(connection, table);
7896
}
7997
cache.put(table, result);
@@ -85,10 +103,10 @@ public static boolean hasSelfLink(List<Fk> fks) {
85103
}
86104

87105
/**
88-
* get FK metadata of one table (both direction of metadata, exported and imported FKs)
89-
*
106+
* Get FK metadata of one table (both direction of metadata, exported and imported FKs)
107+
* <p>
90108
* If the tableName has a schema prefix (e.g. mySchema.) it adds it to the table names
91-
* of the returned FKs.
109+
* of the returned FKs.
92110
*/
93111
public static List<Fk> getFksOfTable(Connection connection, String tableName) throws SQLException {
94112
List<Fk> fks = new CopyOnWriteArrayList<>();
@@ -111,14 +129,16 @@ public static List<Fk> getFksOfTable(Connection connection, String tableName) th
111129
return unifyFks(fks);
112130
}
113131

114-
/** One Fk can contain multiple columns, we need to merge those that form the same fk */
132+
/**
133+
* One Fk can contain multiple columns, we need to merge those that form the same Fk
134+
*/
115135
public static List<Fk> unifyFks(List<Fk> input) {
116136
Map<String, List<Fk>> fkNameToFk = new HashMap<>();
117137
input.forEach(f -> fkNameToFk.computeIfAbsent(f.getFkName(), l -> new ArrayList<>()).add(f));
118138

119139
List<Map.Entry<String, List<Fk>>> toMerge =
120140
fkNameToFk.entrySet().stream().filter(e -> e.getValue().size() > 1 && !hasSelfLink(e.getValue().get(0))).collect(toList());
121-
for (Map.Entry<String, List<Fk>> e : toMerge){
141+
for (Map.Entry<String, List<Fk>> e : toMerge) {
122142
e.getValue().sort(Comparator.comparing(Fk::getKeySeq));
123143

124144
e.getValue().get(0).setFkcolumn(e.getValue().stream().map(fk -> fk.getFkcolumn()[0]).collect(toList()).toArray(new String[]{}));
@@ -130,18 +150,20 @@ public static List<Fk> unifyFks(List<Fk> input) {
130150
return input;
131151
}
132152

133-
/** check for link to self (e.g. table N having a FK to itself */
153+
/**
154+
* check for link to self (e.g. table N having a FK to itself
155+
*/
134156
public static boolean hasSelfLink(Fk e) {
135157
return e.getFktable().equals(e.getPktable());
136158
}
137159

138160
private static void addFks(List<Fk> fks, ResultSet rs, boolean inverted, JdbcHelpers.Table table) throws SQLException {
139161
String optionalPrefix = table.isHasSchemaPrefix() ? table.getSchema() + "." : "";
140162
while (rs.next()) {
141-
Fk fk = new Fk(optionalPrefix + getStringFromResultSet(rs,"pktable_name"),
142-
getStringFromResultSet(rs,"pkcolumn_name"),
143-
optionalPrefix + getStringFromResultSet(rs,"fktable_name"),
144-
getStringFromResultSet(rs,"fkcolumn_name"),
163+
Fk fk = new Fk(optionalPrefix + getStringFromResultSet(rs, "pktable_name"),
164+
getStringFromResultSet(rs, "pkcolumn_name"),
165+
optionalPrefix + getStringFromResultSet(rs, "fktable_name"),
166+
getStringFromResultSet(rs, "fkcolumn_name"),
145167
getStringFromResultSet(rs, "KEY_SEQ"),
146168
getStringFromResultSet(rs, "fk_name"), inverted);
147169

@@ -161,7 +183,7 @@ private static String getStringFromResultSet(ResultSet rs, String columnName) th
161183

162184
// to remove " that mysql puts
163185
static String removeOptionalQuotes(String string) {
164-
if (string != null && string.startsWith("\"") && string.endsWith("\"")){
186+
if (string != null && string.startsWith("\"") && string.endsWith("\"")) {
165187
string = string.substring(1, string.length() - 1);
166188
}
167189
return string;
@@ -204,10 +226,10 @@ public int hashCode() {
204226

205227
/**
206228
* mysql does not return the indirekt FKs with {@link DatabaseMetaData#getExportedKeys(String, String, String)}
207-
* (it only shows the direct links via {@link DatabaseMetaData#getImportedKeys(String, String, String)})
208-
* - so we fake it here and add these indirect keys to the cache
229+
* (it only shows the direct links via {@link DatabaseMetaData#getImportedKeys(String, String, String)})
230+
* - so we fake it here and add these indirect keys to the cache
209231
* (goes through all database tables for this)
210-
*
232+
* <p>
211233
* does only take the current schema into account
212234
*/
213235
public static void initFkCacheForMysql(Cache<String, List<Fk>> fkCache, Connection connection) throws SQLException {
@@ -222,13 +244,15 @@ public static void initFkCacheForMysql(Cache<String, List<Fk>> fkCache, Connecti
222244
List<Fk> current = fkCache.getIfPresent(fk.pktable);
223245
current = (current == null) ? new CopyOnWriteArrayList<>() : current;
224246
// todo: is keyseq ok?
225-
current.add(new Fk(fk.pktable, fk.pkcolumn, fk.fktable, fk.fkcolumn, fk.keySeq, fk.fkName +"inv" , false));
247+
current.add(new Fk(fk.pktable, fk.pkcolumn, fk.fktable, fk.fkcolumn, fk.keySeq, fk.fkName + "inv", false));
226248
fkCache.put(fk.pktable, current);
227249
}
228250
}
229251
}
230252

231-
/** Like {@link #initFkCacheForMysql(Cache, Connection)} but logs exceptions to stdout */
253+
/**
254+
* Like {@link #initFkCacheForMysql(Cache, Connection)} but logs exceptions to stdout
255+
*/
232256
public static void initFkCacheForMysql_LogException(Connection demo, Cache<String, List<Fk>> fkCache) {
233257
try {
234258
Fk.initFkCacheForMysql(fkCache, demo);
@@ -237,9 +261,11 @@ public static void initFkCacheForMysql_LogException(Connection demo, Cache<Strin
237261
}
238262
}
239263

240-
/** Add a virtualForeignKey to the foreign key cache "importerOrExporter".
241-
* (needs to be done once for the DbImporter AND the DbExporter).
242-
* This requires 2 internal foreign keys, one of which is reverted */
264+
/**
265+
* Add a virtualForeignKey to the foreign key cache contained in "importerOrExporter".
266+
* (needs to be done once for the DbImporter AND the DbExporter).
267+
* This requires 2 internal foreign keys, one of which is inverted
268+
*/
243269
public static void addVirtualForeignKey(Connection dbConnection,
244270
FkCacheAccessor importerOrExporter,
245271
String tableOne,
@@ -258,34 +284,38 @@ public static void addVirtualForeignKey(Connection dbConnection,
258284
importerOrExporter.getFkCache().put(tableTwo, fks2);
259285
}
260286

261-
/** Add a virtualForeignKey to the foreign key cache "importerOrExporter".
262-
* (needs to be done once for the DbImporter AND the DbExporter).
263-
* This requires 2 internal foreign keys, one of which is reverted */
287+
/**
288+
* Add a virtualForeignKey to the foreign key cache "importerOrExporter".
289+
* (needs to be done once for the DbImporter AND the DbExporter).
290+
* This requires 2 internal foreign keys, one of which is reverted
291+
*/
264292
public static void addVirtualForeignKey(Connection dbConnection,
265293
FkCacheAccessor importerOrExporter,
266294
String tableOne,
267295
String tableOneColumn,
268296
String tableTwo,
269297
String tableTwoColumn) throws SQLException {
270-
addVirtualForeignKey(dbConnection, importerOrExporter, tableOne, new String[] {tableOneColumn},
271-
tableTwo, new String[] {tableTwoColumn});
298+
addVirtualForeignKey(dbConnection, importerOrExporter, tableOne, new String[]{tableOneColumn},
299+
tableTwo, new String[]{tableTwoColumn});
272300
}
273301

274-
/// Helper
302+
/// Helper
275303

276304
public static Map<String, List<Fk>> fksByColumnName(List<Fk> fksOfTable) {
277305
Map<String, List<Fk>> fksByColumnName = new HashMap<>();
278306

279-
for (Fk fk : fksOfTable){
307+
for (Fk fk : fksOfTable) {
280308
String[] names = fk.inverted ? fk.getFkcolumn() : fk.getPkcolumn();
281309
Stream.of(names).forEach(name -> fksByColumnName.computeIfAbsent(name.toLowerCase(), l -> new ArrayList<>()).add(fk));
282310
}
283311
return fksByColumnName;
284312
}
285313

286-
/** register virtualFK via String
287-
* experimental string config of a virtual foreing key
288-
* table1(field1,field2)-table2(field3,field4) */
314+
/**
315+
* register virtualFK via String
316+
* experimental string config of a virtual foreing key
317+
* table1(field1,field2)-table2(field3,field4)
318+
*/
289319
public static void addOneVirtualForeignKeyAsString(Connection dbConnection, FkCacheAccessor importerOrExporter, String asString) throws SQLException {
290320
FkMatchedFields fkMatchedFields = new FkMatchedFields(asString).parse();
291321
String table1 = fkMatchedFields.getTable1();
@@ -296,8 +326,11 @@ public static void addOneVirtualForeignKeyAsString(Connection dbConnection, FkCa
296326
addVirtualForeignKey(dbConnection, importerOrExporter, table1, fields1AsString.split(","), table2, fields2AsString.split(","));
297327
}
298328

329+
/**
330+
* Same as {@link #addOneVirtualForeignKeyAsString(Connection, FkCacheAccessor, String) } but one can add multiples, separated by ; }
331+
*/
299332
public static void addVirtualForeignKeyAsString(Connection dbConnection, FkCacheAccessor importerOrExporter, String asString) throws SQLException {
300-
if (asString.contains(";")){
333+
if (asString.contains(";")) {
301334
String[] split = asString.split(";");
302335
for (String one : split) {
303336
addOneVirtualForeignKeyAsString(dbConnection, importerOrExporter, one);
@@ -307,6 +340,7 @@ public static void addVirtualForeignKeyAsString(Connection dbConnection, FkCache
307340
}
308341
}
309342

343+
/** To parse String FKs */
310344
@Getter
311345
static class FkMatchedFields {
312346
private String asString;
@@ -323,8 +357,8 @@ public FkMatchedFields parse() {
323357
String regex = "([A-Za-z0-9_.]*)\\(([A-Za-z0-9,_]*)\\)-([A-Za-z0-9_.]*)\\(([A-Za-z0-9,_]*)\\)";
324358
Pattern pattern = Pattern.compile(regex);
325359
Matcher matcher = pattern.matcher(asString);
326-
if ( !matcher.find()){
327-
throw new IllegalArgumentException("Wrong pattern '"+asString+"'. Not matched.");
360+
if (!matcher.find()) {
361+
throw new IllegalArgumentException("Wrong pattern '" + asString + "'. Not matched.");
328362
}
329363

330364
table1 = matcher.group(1);
@@ -345,20 +379,24 @@ public static String getSubtableName(Fk fk, String databaseProductName) {
345379
return subTableName;
346380
}
347381

348-
/** Do the table1 and table2 have a FK relationship? */
382+
/**
383+
* Do the table1 and table2 have a FK relationship?
384+
*/
349385
public static Optional<Fk> getFkOfTwoTables(Connection connection, String table1, String table2, Cache<String, List<Fk>> cache) throws SQLException {
350386
List<Fk> fksOfTable = Fk.getFksOfTable(connection, table1, cache);
351387

352388
for (Fk fk : fksOfTable) {
353389
if ((fk.getPktable().equalsIgnoreCase(table1) && fk.getFktable().equalsIgnoreCase(table2)) ||
354-
(fk.getPktable().equalsIgnoreCase(table2) && fk.getFktable().equalsIgnoreCase(table1))){
390+
(fk.getPktable().equalsIgnoreCase(table2) && fk.getFktable().equalsIgnoreCase(table1))) {
355391
return Optional.of(fk);
356392
}
357393
}
358394
return Optional.empty();
359395
}
360396

361-
/** Do the table1 and table2 have a FK relationship? */
397+
/**
398+
* Do the table1 and table2 have a FK relationship?
399+
*/
362400
public static Optional<Fk> getFkOfTwoTables(Connection connection, String table1, String table2) throws SQLException {
363401
Cache<String, List<Fk>> cache = Caffeine.newBuilder().maximumSize(10_000).build();
364402
return getFkOfTwoTables(connection, table1, table2, cache);

src/main/java/org/oser/tools/jdbc/RowLink.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.oser.tools.jdbc;
22

33
import lombok.Getter;
4+
import lombok.Setter;
45

56
import java.sql.DatabaseMetaData;
67
import java.util.Arrays;
@@ -9,7 +10,7 @@
910
import java.util.stream.Stream;
1011

1112
/**
12-
* A table and a list of concrete primary keys (uniquely identifies a row in a db)<p>
13+
* A table and a list of concrete primary keys, which uniquely identify a row in a db.<p>
1314
* What is the order of the pks? As we get it from the database metadata.
1415
* E.g. via {@link JdbcHelpers#getPrimaryKeys(DatabaseMetaData, String)} <br/>
1516
*
@@ -62,6 +63,7 @@ private Object parseOneKey(String rest) {
6263
}
6364

6465
private String tableName;
66+
@Setter
6567
private Object[] pks;
6668

6769
@Override
@@ -90,7 +92,4 @@ public void setTableName(String tableName) {
9092
this.tableName = tableName.toLowerCase();
9193
}
9294

93-
public void setPks(Object[] pks) {
94-
this.pks = pks;
95-
}
9695
}

0 commit comments

Comments
 (0)