Skip to content

Commit 135636d

Browse files
committed
feat: generate safe deterministic Java identifiers
1 parent fa99090 commit 135636d

10 files changed

Lines changed: 1286 additions & 118 deletions

File tree

‎src/main/java/dev/sqlcj/analysis/QueryAnalyzer.java‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ private QueryModel analyzeSelect(Query query, Select select, Schema schema) {
7474
return new QueryModel(
7575
query.name(),
7676
query.type(),
77-
table.getName(),
77+
table.getUnquotedName(),
7878
toExecutableSql(query.sql()),
7979
bindingParameterIndexes,
8080
columns,
@@ -104,7 +104,7 @@ private List<QueryParameter> resolveBindingParameters(PlainSelect plainSelect, S
104104
return List.of();
105105
}
106106

107-
dev.sqlcj.schema.Table schemaTable = findTable(schema, table.getName());
107+
dev.sqlcj.schema.Table schemaTable = findTable(schema, table.getUnquotedName());
108108

109109
List<QueryParameter> parameters = new ArrayList<>();
110110

@@ -165,7 +165,7 @@ private void resolveInExpression(InExpression in, dev.sqlcj.schema.Table table,
165165
return;
166166
}
167167

168-
dev.sqlcj.schema.Column schemaColumn = findColumn(table, column.getColumnName());
168+
dev.sqlcj.schema.Column schemaColumn = findColumn(table, column.getUnquotedColumnName());
169169

170170
Expression rightExpression = in.getRightExpression();
171171

@@ -261,7 +261,7 @@ private void resolveParameterComparison(
261261
) {
262262
addParameter(
263263
parameter,
264-
column.getColumnName(),
264+
column.getUnquotedColumnName(),
265265
table,
266266
parameters
267267
);
@@ -274,7 +274,7 @@ private void resolveParameterComparison(
274274
) {
275275
addParameter(
276276
parameter,
277-
column.getColumnName(),
277+
column.getUnquotedColumnName(),
278278
table,
279279
parameters
280280
);
@@ -313,7 +313,7 @@ private void addParameter(
313313
}
314314

315315
private List<QueryColumn> resolveColumns(PlainSelect plainSelect, Schema schema, Table table) {
316-
dev.sqlcj.schema.Table schemaTable = findTable(schema, table.getName());
316+
dev.sqlcj.schema.Table schemaTable = findTable(schema, table.getUnquotedName());
317317

318318
List<QueryColumn> columns = new ArrayList<>();
319319

@@ -324,7 +324,7 @@ private List<QueryColumn> resolveColumns(PlainSelect plainSelect, Schema schema,
324324
}
325325

326326
if (selectItem.getExpression() instanceof net.sf.jsqlparser.schema.Column column) {
327-
dev.sqlcj.schema.Column schemaColumn = findColumn(schemaTable, column.getColumnName());
327+
dev.sqlcj.schema.Column schemaColumn = findColumn(schemaTable, column.getUnquotedColumnName());
328328

329329
columns.add(
330330
new QueryColumn(

‎src/main/java/dev/sqlcj/compiler/SqlcjCompiler.java‎

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
import java.io.IOException;
1818
import java.io.UncheckedIOException;
1919
import java.nio.file.Path;
20-
import java.util.HashSet;
20+
import java.util.HashMap;
2121
import java.util.List;
22-
import java.util.Set;
22+
import java.util.Locale;
23+
import java.util.Map;
2324

2425
public final class SqlcjCompiler {
2526

@@ -36,7 +37,7 @@ public void compile(Config config) {
3637

3738
Path outputDirectory = Path.of(config.java().out());
3839

39-
Set<Path> generatedPaths = new HashSet<>();
40+
Map<String, GeneratedQuery> generatedQueries = new HashMap<>();
4041

4142
for (Source source : sources) {
4243
Schema schema = schemaParser.parse(source.schema());
@@ -47,7 +48,7 @@ public void compile(Config config) {
4748
schema,
4849
codeGenerator,
4950
outputDirectory,
50-
generatedPaths
51+
generatedQueries
5152
);
5253
}
5354
}
@@ -58,19 +59,57 @@ private void compileQuery(
5859
Schema schema,
5960
CodeGenerator codeGenerator,
6061
Path outputDirectory,
61-
Set<Path> generatedPaths
62+
Map<String, GeneratedQuery> generatedQueries
6263
) {
6364
Statement statement = sqlParser.parse(query.sql());
6465
QueryModel model = queryAnalyzer.analyze(query, statement, schema);
6566
GeneratedFile file = codeGenerator.generate(model);
6667

67-
if (!generatedPaths.add(file.path())) {
68+
checkGeneratedPath(query, file, generatedQueries);
69+
70+
write(file, outputDirectory);
71+
}
72+
73+
/**
74+
* Rejects a generated path that repeats, or differs only by case from, an
75+
* already generated path before the earlier file can be overwritten.
76+
*/
77+
private void checkGeneratedPath(
78+
Query query,
79+
GeneratedFile file,
80+
Map<String, GeneratedQuery> generatedQueries
81+
) {
82+
String portabilityKey = file.path()
83+
.toString()
84+
.toLowerCase(Locale.ROOT);
85+
86+
GeneratedQuery generated = generatedQueries.get(portabilityKey);
87+
88+
if (generated == null) {
89+
generatedQueries.put(
90+
portabilityKey,
91+
new GeneratedQuery(query.name(), file.path())
92+
);
93+
94+
return;
95+
}
96+
97+
if (generated.path().equals(file.path())) {
6898
throw new CompilationException(
69-
"Duplicate generated file: " + file.path()
99+
"Duplicate generated file for queries '%s' and '%s': %s"
100+
.formatted(generated.queryName(), query.name(), file.path())
70101
);
71102
}
72103

73-
write(file, outputDirectory);
104+
throw new CompilationException(
105+
"Generated file paths for queries '%s' and '%s' differ only by case: %s and %s"
106+
.formatted(
107+
generated.queryName(),
108+
query.name(),
109+
generated.path(),
110+
file.path()
111+
)
112+
);
74113
}
75114

76115
private void write(GeneratedFile file, Path outputDirectory) {
@@ -80,4 +119,7 @@ private void write(GeneratedFile file, Path outputDirectory) {
80119
throw new UncheckedIOException(e);
81120
}
82121
}
122+
123+
private record GeneratedQuery(String queryName, Path path) {
124+
}
83125
}

0 commit comments

Comments
 (0)