Skip to content

Commit 5f13842

Browse files
committed
Recursive sql templates (just experimental, little tested).
1 parent b856088 commit 5f13842

17 files changed

+811
-29
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,4 @@ Further Ideas
261261
* Extension ideas
262262
- Do more unification of Datatype handling. E.g. oracle treats DATE different from Postgres (so at the moment
263263
we need to adapt it in the JSON/ DbRecord). Refer e.g. to DbExporterBasicTests#datatypesTest().
264+
* Oracle testcontainer does not run on Arm osx. To try things out: https://dbfiddle.uk/Wh4zpMKJ

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Optional;
2626
import java.util.Set;
2727
import java.util.SortedMap;
28+
import java.util.concurrent.ConcurrentMap;
2829
import java.util.stream.Collectors;
2930
import java.util.stream.Stream;
3031

@@ -479,4 +480,28 @@ public Map<String, FieldExporter> getTypeFieldExporters() {
479480
public void setOrderResults(boolean orderResults) {
480481
this.orderResults = orderResults;
481482
}
483+
484+
485+
/**
486+
* Get only the cache entries that are excluded by the stopTablesExcluded
487+
*/
488+
public Cache<String, List<Fk>> getFilteredFkCache() {
489+
ConcurrentMap<String, List<Fk>> map = fkCache.asMap();
490+
List<Map.Entry<String, List<Fk>>> removedKeys = map.entrySet().stream().filter(e -> !stopTablesExcluded.contains(e.getKey())).toList();
491+
492+
Cache<String, List<Fk>> fkCacheSubset1 = Caffeine.newBuilder()
493+
.maximumSize(1000).build();
494+
removedKeys.stream().map(e -> filterEntry(e, stopTablesExcluded)).forEach(e -> fkCacheSubset1.put(e.key(), e.fks()));
495+
Cache<String, List<Fk>> fkCacheSubset = fkCacheSubset1;
496+
return fkCacheSubset;
497+
}
498+
499+
private static KeyAndFkList filterEntry(Map.Entry<String, List<Fk>> e, Set<String> stopTablesExcluded) {
500+
List<Fk> list = e.getValue().stream().filter(fk -> !(stopTablesExcluded.contains(fk.getPktable()) || stopTablesExcluded.contains(fk.getFktable()))).toList();
501+
return new KeyAndFkList(e.getKey(), list);
502+
}
503+
504+
record KeyAndFkList(String key, List<Fk> fks) {
505+
}
506+
482507
}

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

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
* <p>
3131
* In JDBC <em>one</em> fk constraint between table 1 and table 2 has <em>two</em> representations: the link from
3232
* 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).
33+
* <a>
34+
* Supports virtual foreign keys (that do not exist in the db).
3535
*/
3636
@Getter
3737
public class Fk {
@@ -84,6 +84,25 @@ public Fk(String pktable, String[] pkcolumnArray, String fktable, String[] fkcol
8484
this.inverted = inverted;
8585
}
8686

87+
// convenience accessors: they check the inverted flag to either return the 1st or the 2nd entry
88+
// todo can we simplify code with these methods?
89+
90+
public String getFirstTable() {
91+
return inverted ? pktable : fktable;
92+
}
93+
94+
public String getSecondTable() {
95+
return inverted ? fktable : pktable;
96+
}
97+
98+
public String[] getFirstColumn() {
99+
return inverted ? pkcolumn : fkcolumn;
100+
}
101+
102+
public String[] getSecondColumn() {
103+
return inverted ? fkcolumn : pkcolumn;
104+
}
105+
87106

88107
/**
89108
* Refer to {@link #getFksOfTable(Connection, String)}
@@ -340,7 +359,30 @@ public static void addVirtualForeignKeyAsString(Connection dbConnection, FkCache
340359
}
341360
}
342361

343-
/** To parse String FKs */
362+
/**
363+
* Same as #addOneVirtualForeignKeyAsString but only fills the cache (without a connection)
364+
*/
365+
public static void addOneVirtualForeignKeyAsString(FkCacheAccessor importerOrExporter, String asString) {
366+
FkMatchedFields fkMatchedFields = new FkMatchedFields(asString).parse();
367+
String table1 = fkMatchedFields.getTable1();
368+
String fields1AsString = fkMatchedFields.getFields1AsString();
369+
String table2 = fkMatchedFields.getTable2();
370+
String fields2AsString = fkMatchedFields.getFields2AsString();
371+
372+
List<Fk> table1fks = importerOrExporter.getFkCache().getIfPresent(table1);
373+
table1fks = table1fks == null ? new ArrayList<>() : table1fks;
374+
table1fks.add(new Fk(table1, fields1AsString.split(","), table2, fields2AsString.split(","), "1", table1 + fields1AsString.split(",")[0], false));
375+
importerOrExporter.getFkCache().put(table1, table1fks);
376+
377+
List<Fk> table2fks = importerOrExporter.getFkCache().getIfPresent(table2);
378+
table2fks = table2fks == null ? new ArrayList<>() : table2fks;
379+
table2fks.add(new Fk(table1, fields1AsString.split(","), table2, fields2AsString.split(","), "1", table1 + fields1AsString.split(",")[0], true));
380+
importerOrExporter.getFkCache().put(table2, table2fks);
381+
}
382+
383+
/**
384+
* o parse String FKs
385+
*/
344386
@Getter
345387
static class FkMatchedFields {
346388
private String asString;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public static class Pair<A,B> {
8686
* @param treated init treated to Set with all entries
8787
* @param exceptionWithCycles whether we should throw an exception if there are cycles
8888
* @return the sorted list of entries
89+
* @throws IllegalStateException in case of cycles if exceptionWithCycles is true
8990
* */
9091
public static <T> List<T> topologicalSort(Map<T, Set<T>> dependencyGraph, Set<T> treated, boolean exceptionWithCycles) {
9192
List<T> orderedTables = new ArrayList<>();

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

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,37 @@
1515
import java.util.Set;
1616
import java.util.stream.Collectors;
1717

18-
/** Global logging convenience abstraction (to globally enable certain details in logs, such as all select statements or all insert/update statements).
19-
* Just uses Slf4j. In case logback is configured, sets the log levels in logback (users of other log implementations need to set their log levels themselves). */
18+
/**
19+
* Global logging convenience abstraction (to globally enable certain details in logs, such as all select statements or all insert/update statements).
20+
* Just uses Slf4j. In case logback is configured, sets the log levels in logback (users of other log implementations need to set their log levels themselves).
21+
*/
2022
public enum Loggers {
2123

22-
/** SQL select statements */
23-
SELECT,
24-
/** SQL update and insert statements */
25-
CHANGE,
26-
/** SQL delete statements */
27-
DELETE,
28-
WARNING,
29-
INFO,
30-
/** meta Logger to mean all db operations */
31-
DB_OPERATIONS,
32-
/** meta Logger means all Loggers */
33-
ALL;
34-
35-
36-
static final Set<Loggers> CONCRETE_LOGGERS = EnumSet.of(Loggers.SELECT, Loggers.CHANGE, Loggers.DELETE, Loggers.WARNING, Loggers.INFO);
24+
/**
25+
* SQL select statements
26+
*/
27+
SELECT,
28+
/**
29+
* SQL update and insert statements
30+
*/
31+
CHANGE,
32+
/**
33+
* SQL delete statements
34+
*/
35+
DELETE,
36+
WARNING,
37+
INFO,
38+
/**
39+
* meta Logger to mean all db operations
40+
*/
41+
DB_OPERATIONS,
42+
/**
43+
* meta Logger means all Loggers
44+
*/
45+
ALL;
46+
47+
48+
static final Set<Loggers> CONCRETE_LOGGERS = EnumSet.of(Loggers.SELECT, Loggers.CHANGE, Loggers.DELETE, Loggers.WARNING, Loggers.INFO);
3749
static final Set<Loggers> CONCRETE_DB_OPERATIONS = EnumSet.of(Loggers.SELECT, Loggers.CHANGE, Loggers.DELETE);
3850
static final Set<Loggers> ALL_LOGGERS = CONCRETE_LOGGERS;
3951

@@ -45,12 +57,16 @@ public enum Loggers {
4557

4658
static boolean missingLoggerSignalled = false;
4759

48-
/** Convenience method to enable what you would like to see in the logs */
60+
/**
61+
* Convenience method to enable what you would like to see in the logs
62+
*/
4963
public static void enableLoggers(Set<Loggers> loggers) {
5064
setLoggerLevel(loggers, Level.INFO);
5165
}
5266

53-
/** Convenience method to enable what you would like to see in the logs */
67+
/**
68+
* Convenience method to enable what you would like to see in the logs
69+
*/
5470
public static void enableLoggers(Loggers... loggers) {
5571
setLoggerLevel(new HashSet(Arrays.asList(loggers)), Level.INFO);
5672
}
@@ -86,17 +102,19 @@ static void setLoggerLevel(Set<Loggers> loggers, Level newLevel) {
86102
disableDefaultLogs();
87103
}
88104

89-
/** Convenience method to only show warning logs */
105+
/**
106+
* Convenience method to only show warning logs
107+
*/
90108
public static void disableDefaultLogs() {
91109
setLoggerLevel(CONCRETE_LOGGERS, Level.WARN);
92110
}
93111

94112

95-
public static Set<Loggers> stringListToLoggerSet(List<String> logs){
113+
public static Set<Loggers> stringListToLoggerSet(List<String> logs) {
96114
return logs.stream().map(String::toUpperCase).map(n -> optionalGetLogger(n)).flatMap(Optional::stream).collect(Collectors.toSet());
97115
}
98116

99-
private static Optional<Loggers> optionalGetLogger(String logger){
117+
private static Optional<Loggers> optionalGetLogger(String logger) {
100118
try {
101119
return Optional.of(Loggers.valueOf(logger));
102120
} catch (IllegalArgumentException e) {

src/main/java/org/oser/tools/jdbc/cli/ExecuteDbScriptFiles.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ public static void executeDbScriptFiles(String sqlDirectory, Connection connecti
2929
.map(Path::toString).sorted().collect(toList());
3030

3131
for (String fileName : sqlFiles) {
32-
executeSqlFile(connection, fileName, placeholders);
32+
try {
33+
executeSqlFile(connection, fileName, placeholders);
34+
} catch (Exception e) {
35+
e.printStackTrace();
36+
}
3337
}
3438
}
3539
}

0 commit comments

Comments
 (0)