From 13b47ae75ac52a1b67e9b90a6fbd153943802495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20=C3=87engel?= Date: Thu, 17 Sep 2026 00:11:22 +0300 Subject: [PATCH 1/2] build: enforce Java formatting with Spotless --- config/eclipse-java-formatter.xml | 528 +++++++ pom.xml | 31 + .../dev/sqlcj/analysis/QueryAnalyzer.java | 307 ++-- .../java/dev/sqlcj/analysis/QueryColumn.java | 6 +- .../java/dev/sqlcj/analysis/QueryModel.java | 14 +- .../dev/sqlcj/analysis/QueryParameter.java | 6 +- src/main/java/dev/sqlcj/cli/SqlcjCommand.java | 18 +- .../sqlcj/cli/command/GenerateCommand.java | 17 +- .../dev/sqlcj/cli/command/VersionCommand.java | 8 +- .../sqlcj/compiler/CompilationException.java | 5 +- .../sqlcj/compiler/DefaultSourceLoader.java | 22 +- src/main/java/dev/sqlcj/compiler/Source.java | 4 +- .../dev/sqlcj/compiler/SqlcjCompiler.java | 30 +- src/main/java/dev/sqlcj/config/Config.java | 16 +- .../dev/sqlcj/config/ConfigValidator.java | 45 +- .../sqlcj/config/ConfigurationException.java | 5 +- .../java/dev/sqlcj/config/JavaConfig.java | 6 +- src/main/java/dev/sqlcj/config/SqlConfig.java | 4 +- .../dev/sqlcj/config/YamlConfigLoader.java | 90 +- .../dev/sqlcj/generator/GeneratedFile.java | 4 +- .../sqlcj/generator/JavaCodeGenerator.java | 215 +-- .../dev/sqlcj/io/GeneratedFileWriter.java | 13 +- .../dev/sqlcj/parser/DefaultQueryParser.java | 20 +- src/main/java/dev/sqlcj/parser/Query.java | 6 +- .../java/dev/sqlcj/parser/QueryHeader.java | 4 +- .../dev/sqlcj/runtime/JdbcQueryExecutor.java | 35 +- .../java/dev/sqlcj/runtime/QueryExecutor.java | 12 +- src/main/java/dev/sqlcj/schema/Column.java | 6 +- .../java/dev/sqlcj/schema/Constraint.java | 4 +- src/main/java/dev/sqlcj/schema/Schema.java | 2 +- src/main/java/dev/sqlcj/schema/Table.java | 6 +- .../schema/parser/DefaultSchemaParser.java | 55 +- .../dev/sqlcj/analysis/QueryAnalyzerTest.java | 458 +++--- .../cli/command/GenerateCommandTest.java | 80 +- .../compiler/DefaultSourceLoaderTest.java | 231 ++- .../SqlcjCompilerIntegrationTest.java | 810 +++++----- .../sqlcj/config/YamlConfigLoaderTest.java | 406 +++-- .../generator/JavaCodeGeneratorTest.java | 1345 +++++++++-------- .../dev/sqlcj/io/GeneratedFileWriterTest.java | 22 +- .../sqlcj/parser/DefaultQueryParserTest.java | 124 +- .../sqlcj/runtime/JdbcQueryExecutorTest.java | 134 +- .../parser/DefaultSchemaParserTest.java | 48 +- 42 files changed, 2819 insertions(+), 2383 deletions(-) create mode 100644 config/eclipse-java-formatter.xml diff --git a/config/eclipse-java-formatter.xml b/config/eclipse-java-formatter.xml new file mode 100644 index 0000000..fa39f02 --- /dev/null +++ b/config/eclipse-java-formatter.xml @@ -0,0 +1,528 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 5f859c4..5354a50 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,8 @@ 21 UTF-8 + 3.10.2 + 4.40 @@ -48,6 +50,35 @@ + + com.diffplug.spotless + spotless-maven-plugin + ${spotless.plugin.version} + + + + ${spotless.eclipse.version} + ${project.basedir}/config/eclipse-java-formatter.xml + + + + module |,jakarta|javax|java,\# + + + + + + + + + spotless-check + validate + + check + + + + org.apache.maven.plugins maven-jar-plugin diff --git a/src/main/java/dev/sqlcj/analysis/QueryAnalyzer.java b/src/main/java/dev/sqlcj/analysis/QueryAnalyzer.java index e5c1a8c..a836b11 100644 --- a/src/main/java/dev/sqlcj/analysis/QueryAnalyzer.java +++ b/src/main/java/dev/sqlcj/analysis/QueryAnalyzer.java @@ -47,43 +47,38 @@ public QueryModel analyze(Query query, Statement statement, Schema schema) { } throw new UnsupportedOperationException( - statement.getClass().getSimpleName() + statement.getClass().getSimpleName() ); } - private QueryModel analyzeSelect( - Query query, - Select select, - Schema schema - ) { + private QueryModel analyzeSelect(Query query, Select select, Schema schema) { PlainSelect plainSelect = select.getPlainSelect(); Table table = getTable(plainSelect); List columns = resolveColumns( - plainSelect, - schema, - table + plainSelect, + schema, + table ); - List bindingParameters = - resolveBindingParameters(plainSelect, schema, table); + List bindingParameters = resolveBindingParameters(plainSelect, schema, table); List bindingParameterIndexes = bindingParameters.stream() - .map(QueryParameter::index) - .toList(); + .map(QueryParameter::index) + .toList(); List parameters = bindingParameters.stream() - .sorted(Comparator.comparingInt(QueryParameter::index)) - .toList(); + .sorted(Comparator.comparingInt(QueryParameter::index)) + .toList(); return new QueryModel( - query.name(), - query.type(), - table.getName(), - toExecutableSql(query.sql()), - bindingParameterIndexes, - columns, - parameters + query.name(), + query.type(), + table.getName(), + toExecutableSql(query.sql()), + bindingParameterIndexes, + columns, + parameters ); } @@ -104,33 +99,28 @@ private Table getTable(PlainSelect plainSelect) { * encountered, which is the JDBC binding order of the generated {@code ?} * positions. */ - private List resolveBindingParameters( - PlainSelect plainSelect, - Schema schema, - Table table - ) { + private List resolveBindingParameters(PlainSelect plainSelect, Schema schema, Table table) { if (plainSelect.getWhere() == null) { return List.of(); } - dev.sqlcj.schema.Table schemaTable = - findTable(schema, table.getName()); + dev.sqlcj.schema.Table schemaTable = findTable(schema, table.getName()); List parameters = new ArrayList<>(); resolveParameters( - plainSelect.getWhere(), - schemaTable, - parameters + plainSelect.getWhere(), + schemaTable, + parameters ); return parameters; } private void resolveParameters( - Expression expression, - dev.sqlcj.schema.Table table, - List parameters + Expression expression, + dev.sqlcj.schema.Table table, + List parameters ) { if (expression instanceof AndExpression and) { resolveParameters(and.getLeftExpression(), table, parameters); @@ -147,9 +137,9 @@ private void resolveParameters( if (expression instanceof ParenthesedExpressionList parentheses) { for (Expression nestedExpression : parentheses) { resolveParameters( - nestedExpression, - table, - parameters + nestedExpression, + table, + parameters ); } return; @@ -162,26 +152,20 @@ private void resolveParameters( if (expression instanceof ComparisonOperator comparison) { resolveParameterComparison( - comparison.getLeftExpression(), - comparison.getRightExpression(), - table, - parameters + comparison.getLeftExpression(), + comparison.getRightExpression(), + table, + parameters ); } } - private void resolveInExpression( - InExpression in, - dev.sqlcj.schema.Table table, - List parameters - ) { - if (!(in.getLeftExpression() - instanceof net.sf.jsqlparser.schema.Column column)) { + private void resolveInExpression(InExpression in, dev.sqlcj.schema.Table table, List parameters) { + if (!(in.getLeftExpression() instanceof net.sf.jsqlparser.schema.Column column)) { return; } - dev.sqlcj.schema.Column schemaColumn = - findColumn(table, column.getColumnName()); + dev.sqlcj.schema.Column schemaColumn = findColumn(table, column.getColumnName()); Expression rightExpression = in.getRightExpression(); @@ -196,18 +180,18 @@ private void resolveInExpression( } resolveInExpression( - rightExpression, - schemaColumn, - table, - parameters + rightExpression, + schemaColumn, + table, + parameters ); } private void resolveInExpression( - Expression expression, - dev.sqlcj.schema.Column schemaColumn, - dev.sqlcj.schema.Table table, - List parameters + Expression expression, + dev.sqlcj.schema.Column schemaColumn, + dev.sqlcj.schema.Table table, + List parameters ) { if (expression instanceof JdbcParameter parameter) { addParameter(parameter, schemaColumn, parameters); @@ -216,17 +200,17 @@ private void resolveInExpression( if (expression instanceof AndExpression and) { resolveInExpression( - and.getLeftExpression(), - schemaColumn, - table, - parameters + and.getLeftExpression(), + schemaColumn, + table, + parameters ); resolveInExpression( - and.getRightExpression(), - schemaColumn, - table, - parameters + and.getRightExpression(), + schemaColumn, + table, + parameters ); return; @@ -234,17 +218,17 @@ private void resolveInExpression( if (expression instanceof OrExpression or) { resolveInExpression( - or.getLeftExpression(), - schemaColumn, - table, - parameters + or.getLeftExpression(), + schemaColumn, + table, + parameters ); resolveInExpression( - or.getRightExpression(), - schemaColumn, - table, - parameters + or.getRightExpression(), + schemaColumn, + table, + parameters ); return; @@ -256,9 +240,9 @@ private void resolveInExpression( addParameter(parameter, schemaColumn, parameters); } else { resolveParameters( - nestedExpression, - table, - parameters + nestedExpression, + table, + parameters ); } } @@ -266,74 +250,70 @@ private void resolveInExpression( } private void resolveParameterComparison( - Expression left, - Expression right, - dev.sqlcj.schema.Table table, - List parameters + Expression left, + Expression right, + dev.sqlcj.schema.Table table, + List parameters ) { - if (left instanceof net.sf.jsqlparser.schema.Column column - && right instanceof JdbcParameter parameter) { - + if ( + left instanceof net.sf.jsqlparser.schema.Column column + && right instanceof JdbcParameter parameter + ) { addParameter( - parameter, - column.getColumnName(), - table, - parameters + parameter, + column.getColumnName(), + table, + parameters ); return; } - if (left instanceof JdbcParameter parameter - && right instanceof net.sf.jsqlparser.schema.Column column) { - + if ( + left instanceof JdbcParameter parameter + && right instanceof net.sf.jsqlparser.schema.Column column + ) { addParameter( - parameter, - column.getColumnName(), - table, - parameters + parameter, + column.getColumnName(), + table, + parameters ); } } private void addParameter( - JdbcParameter parameter, - String columnName, - dev.sqlcj.schema.Table table, - List parameters + JdbcParameter parameter, + String columnName, + dev.sqlcj.schema.Table table, + List parameters ) { - dev.sqlcj.schema.Column column = - findColumn(table, columnName); + dev.sqlcj.schema.Column column = findColumn(table, columnName); parameters.add( - new QueryParameter( - parameter.getIndex(), - column.name(), - column.type() - ) + new QueryParameter( + parameter.getIndex(), + column.name(), + column.type() + ) ); } private void addParameter( - JdbcParameter parameter, - dev.sqlcj.schema.Column column, - List parameters + JdbcParameter parameter, + dev.sqlcj.schema.Column column, + List parameters ) { parameters.add( - new QueryParameter( - parameter.getIndex(), - column.name(), - column.type() - ) + new QueryParameter( + parameter.getIndex(), + column.name(), + column.type() + ) ); } - private List resolveColumns( - PlainSelect plainSelect, - Schema schema, - Table table - ) { - dev.sqlcj.schema.Table schemaTable = - findTable(schema, table.getName()); + private List resolveColumns(PlainSelect plainSelect, Schema schema, Table table) { + dev.sqlcj.schema.Table schemaTable = findTable(schema, table.getName()); List columns = new ArrayList<>(); @@ -343,72 +323,63 @@ private List resolveColumns( continue; } - if (selectItem.getExpression() - instanceof net.sf.jsqlparser.schema.Column column) { - - dev.sqlcj.schema.Column schemaColumn = - findColumn(schemaTable, column.getColumnName()); + if (selectItem.getExpression() instanceof net.sf.jsqlparser.schema.Column column) { + dev.sqlcj.schema.Column schemaColumn = findColumn(schemaTable, column.getColumnName()); columns.add( - new QueryColumn( - schemaColumn.name(), - schemaColumn.type(), - schemaColumn.nullable() - ) + new QueryColumn( + schemaColumn.name(), + schemaColumn.type(), + schemaColumn.nullable() + ) ); continue; } throw new UnsupportedOperationException( - "Unsupported SELECT expression: " - + selectItem.getExpression().getClass().getSimpleName() + "Unsupported SELECT expression: " + + selectItem.getExpression().getClass().getSimpleName() ); } return columns; } - private dev.sqlcj.schema.Table findTable( - Schema schema, - String tableName - ) { + private dev.sqlcj.schema.Table findTable(Schema schema, String tableName) { return schema.tables().stream() - .filter(table -> table.name().equalsIgnoreCase(tableName)) - .findFirst() - .orElseThrow(() -> - new IllegalArgumentException( - "Table not found in schema: " + tableName - ) - ); + .filter(table -> table.name().equalsIgnoreCase(tableName)) + .findFirst() + .orElseThrow( + () -> new IllegalArgumentException( + "Table not found in schema: " + tableName + ) + ); } - private List resolveAllColumns( - dev.sqlcj.schema.Table table - ) { + private List resolveAllColumns(dev.sqlcj.schema.Table table) { return table.columns().stream() - .map(column -> new QueryColumn( - column.name(), - column.type(), - column.nullable() - )) - .toList(); + .map( + column -> new QueryColumn( + column.name(), + column.type(), + column.nullable() + ) + ) + .toList(); } - private dev.sqlcj.schema.Column findColumn( - dev.sqlcj.schema.Table table, - String columnName - ) { + private dev.sqlcj.schema.Column findColumn(dev.sqlcj.schema.Table table, String columnName) { return table.columns().stream() - .filter(column -> column.name().equalsIgnoreCase(columnName)) - .findFirst() - .orElseThrow(() -> - new IllegalArgumentException( - "Column not found in table " - + table.name() - + ": " - + columnName - ) - ); + .filter(column -> column.name().equalsIgnoreCase(columnName)) + .findFirst() + .orElseThrow( + () -> new IllegalArgumentException( + "Column not found in table " + + table.name() + + ": " + + columnName + ) + ); } } diff --git a/src/main/java/dev/sqlcj/analysis/QueryColumn.java b/src/main/java/dev/sqlcj/analysis/QueryColumn.java index ecbbc16..c4279fe 100644 --- a/src/main/java/dev/sqlcj/analysis/QueryColumn.java +++ b/src/main/java/dev/sqlcj/analysis/QueryColumn.java @@ -3,8 +3,8 @@ import dev.sqlcj.schema.ColumnType; public record QueryColumn( - String name, - ColumnType type, - boolean nullable + String name, + ColumnType type, + boolean nullable ) { } diff --git a/src/main/java/dev/sqlcj/analysis/QueryModel.java b/src/main/java/dev/sqlcj/analysis/QueryModel.java index 3133bf4..1ba9fbc 100644 --- a/src/main/java/dev/sqlcj/analysis/QueryModel.java +++ b/src/main/java/dev/sqlcj/analysis/QueryModel.java @@ -14,12 +14,12 @@ * @param parameters query parameters in logical placeholder-index order */ public record QueryModel( - String name, - QueryType type, - String table, - String executableSql, - List bindingParameterIndexes, - List columns, - List parameters + String name, + QueryType type, + String table, + String executableSql, + List bindingParameterIndexes, + List columns, + List parameters ) { } diff --git a/src/main/java/dev/sqlcj/analysis/QueryParameter.java b/src/main/java/dev/sqlcj/analysis/QueryParameter.java index f4a3183..6db0090 100644 --- a/src/main/java/dev/sqlcj/analysis/QueryParameter.java +++ b/src/main/java/dev/sqlcj/analysis/QueryParameter.java @@ -3,8 +3,8 @@ import dev.sqlcj.schema.ColumnType; public record QueryParameter( - int index, - String name, - ColumnType type + int index, + String name, + ColumnType type ) { } diff --git a/src/main/java/dev/sqlcj/cli/SqlcjCommand.java b/src/main/java/dev/sqlcj/cli/SqlcjCommand.java index 4104e4d..9d734db 100644 --- a/src/main/java/dev/sqlcj/cli/SqlcjCommand.java +++ b/src/main/java/dev/sqlcj/cli/SqlcjCommand.java @@ -2,16 +2,16 @@ import dev.sqlcj.cli.command.GenerateCommand; import dev.sqlcj.cli.command.VersionCommand; -import picocli.CommandLine; +import picocli.CommandLine.Command; -@CommandLine.Command( - name = "sqlcj", - mixinStandardHelpOptions = true, - description = "SQL compiler and type-safe code generator for Java", - subcommands = { - VersionCommand.class, - GenerateCommand.class - } +@Command( + name = "sqlcj", + mixinStandardHelpOptions = true, + description = "SQL compiler and type-safe code generator for Java", + subcommands = { + VersionCommand.class, + GenerateCommand.class + } ) public class SqlcjCommand implements Runnable { diff --git a/src/main/java/dev/sqlcj/cli/command/GenerateCommand.java b/src/main/java/dev/sqlcj/cli/command/GenerateCommand.java index 1f580a0..7a2af0f 100644 --- a/src/main/java/dev/sqlcj/cli/command/GenerateCommand.java +++ b/src/main/java/dev/sqlcj/cli/command/GenerateCommand.java @@ -7,13 +7,16 @@ import dev.sqlcj.config.ConfigurationException; import dev.sqlcj.config.YamlConfigLoader; import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Spec; import java.nio.file.Path; import java.util.concurrent.Callable; -@CommandLine.Command( - name = "generate", - description = "Generate Java sources from SQL queries" +@Command( + name = "generate", + description = "Generate Java sources from SQL queries" ) public class GenerateCommand implements Callable { @@ -21,8 +24,8 @@ public class GenerateCommand implements Callable { private final ConfigLoader configLoader = new YamlConfigLoader(); - @CommandLine.Spec - CommandLine.Model.CommandSpec spec; + @Spec + CommandSpec spec; @Override public Integer call() { @@ -33,8 +36,8 @@ public Integer call() { return CommandLine.ExitCode.OK; } catch (ConfigurationException | CompilationException e) { spec.commandLine() - .getErr() - .println("sqlcj: " + e.getMessage()); + .getErr() + .println("sqlcj: " + e.getMessage()); return CommandLine.ExitCode.SOFTWARE; } diff --git a/src/main/java/dev/sqlcj/cli/command/VersionCommand.java b/src/main/java/dev/sqlcj/cli/command/VersionCommand.java index 8574f5f..24b6179 100644 --- a/src/main/java/dev/sqlcj/cli/command/VersionCommand.java +++ b/src/main/java/dev/sqlcj/cli/command/VersionCommand.java @@ -1,11 +1,11 @@ package dev.sqlcj.cli.command; import dev.sqlcj.Main; -import picocli.CommandLine; +import picocli.CommandLine.Command; -@CommandLine.Command( - name = "version", - description = "Print SQLCJ version" +@Command( + name = "version", + description = "Print SQLCJ version" ) public class VersionCommand implements Runnable { diff --git a/src/main/java/dev/sqlcj/compiler/CompilationException.java b/src/main/java/dev/sqlcj/compiler/CompilationException.java index dc6b733..9b318ab 100644 --- a/src/main/java/dev/sqlcj/compiler/CompilationException.java +++ b/src/main/java/dev/sqlcj/compiler/CompilationException.java @@ -9,10 +9,7 @@ public CompilationException(String message) { super(message); } - public CompilationException( - String message, - Throwable cause - ) { + public CompilationException(String message, Throwable cause) { super(message, cause); } } diff --git a/src/main/java/dev/sqlcj/compiler/DefaultSourceLoader.java b/src/main/java/dev/sqlcj/compiler/DefaultSourceLoader.java index 9c226d9..e85dfff 100644 --- a/src/main/java/dev/sqlcj/compiler/DefaultSourceLoader.java +++ b/src/main/java/dev/sqlcj/compiler/DefaultSourceLoader.java @@ -35,8 +35,8 @@ public List load(Config config) { for (Query query : queries) { if (!queryNames.add(query.name())) { throw new CompilationException( - "Duplicate query name '%s' in query source: %s" - .formatted(query.name(), queriesPath) + "Duplicate query name '%s' in query source: %s" + .formatted(query.name(), queriesPath) ); } } @@ -47,30 +47,24 @@ public List load(Config config) { return sources; } - private String read( - Path path, - String kind - ) { + private String read(Path path, String kind) { try { return fileLoader.read(path); } catch (IOException e) { throw new CompilationException( - "Cannot read %s source: %s".formatted(kind, path), - e + "Cannot read %s source: %s".formatted(kind, path), + e ); } } - private List parse( - String querySource, - Path queriesPath - ) { + private List parse(String querySource, Path queriesPath) { try { return queryParser.parse(querySource); } catch (IllegalArgumentException e) { throw new CompilationException( - "Invalid query source %s: %s".formatted(queriesPath, e.getMessage()), - e + "Invalid query source %s: %s".formatted(queriesPath, e.getMessage()), + e ); } } diff --git a/src/main/java/dev/sqlcj/compiler/Source.java b/src/main/java/dev/sqlcj/compiler/Source.java index 796fd79..5883fe0 100644 --- a/src/main/java/dev/sqlcj/compiler/Source.java +++ b/src/main/java/dev/sqlcj/compiler/Source.java @@ -5,7 +5,7 @@ import java.util.List; public record Source( - String schema, - List queries + String schema, + List queries ) { } diff --git a/src/main/java/dev/sqlcj/compiler/SqlcjCompiler.java b/src/main/java/dev/sqlcj/compiler/SqlcjCompiler.java index 950871c..ddc95bb 100644 --- a/src/main/java/dev/sqlcj/compiler/SqlcjCompiler.java +++ b/src/main/java/dev/sqlcj/compiler/SqlcjCompiler.java @@ -32,8 +32,7 @@ public final class SqlcjCompiler { public void compile(Config config) { List sources = sourceLoader.load(config); - CodeGenerator codeGenerator = - new JavaCodeGenerator(config.java().packageName()); + CodeGenerator codeGenerator = new JavaCodeGenerator(config.java().packageName()); Path outputDirectory = Path.of(config.java().out()); @@ -44,22 +43,22 @@ public void compile(Config config) { for (Query query : source.queries()) { compileQuery( - query, - schema, - codeGenerator, - outputDirectory, - generatedPaths + query, + schema, + codeGenerator, + outputDirectory, + generatedPaths ); } } } private void compileQuery( - Query query, - Schema schema, - CodeGenerator codeGenerator, - Path outputDirectory, - Set generatedPaths + Query query, + Schema schema, + CodeGenerator codeGenerator, + Path outputDirectory, + Set generatedPaths ) { Statement statement = sqlParser.parse(query.sql()); QueryModel model = queryAnalyzer.analyze(query, statement, schema); @@ -67,17 +66,14 @@ private void compileQuery( if (!generatedPaths.add(file.path())) { throw new CompilationException( - "Duplicate generated file: " + file.path() + "Duplicate generated file: " + file.path() ); } write(file, outputDirectory); } - private void write( - GeneratedFile file, - Path outputDirectory - ) { + private void write(GeneratedFile file, Path outputDirectory) { try { generatedFileWriter.write(file, outputDirectory); } catch (IOException e) { diff --git a/src/main/java/dev/sqlcj/config/Config.java b/src/main/java/dev/sqlcj/config/Config.java index 76d28bb..6003907 100644 --- a/src/main/java/dev/sqlcj/config/Config.java +++ b/src/main/java/dev/sqlcj/config/Config.java @@ -3,17 +3,21 @@ import java.util.List; public record Config( - String version, - List sql, - JavaConfig java + String version, + List sql, + JavaConfig java ) { public static final String VERSION_1 = "1"; public Config( - List sql, - JavaConfig java + List sql, + JavaConfig java ) { - this(VERSION_1, sql, java); + this( + VERSION_1, + sql, + java + ); } } diff --git a/src/main/java/dev/sqlcj/config/ConfigValidator.java b/src/main/java/dev/sqlcj/config/ConfigValidator.java index 0522c82..cd66fee 100644 --- a/src/main/java/dev/sqlcj/config/ConfigValidator.java +++ b/src/main/java/dev/sqlcj/config/ConfigValidator.java @@ -10,34 +10,25 @@ */ final class ConfigValidator { - void validate( - Config config, - Path configFile - ) { + void validate(Config config, Path configFile) { validateVersion(config.version(), configFile); validateSql(config.sql(), configFile); validateJava(config.java(), configFile); } - private void validateVersion( - String version, - Path configFile - ) { + private void validateVersion(String version, Path configFile) { requireValue(version, "version", configFile); if (!Config.VERSION_1.equals(version)) { throw invalid( - configFile, - "unsupported 'version' value '%s', expected '%s'" - .formatted(version, Config.VERSION_1) + configFile, + "unsupported 'version' value '%s', expected '%s'" + .formatted(version, Config.VERSION_1) ); } } - private void validateSql( - List sql, - Path configFile - ) { + private void validateSql(List sql, Path configFile) { if (sql == null) { throw invalid(configFile, "'sql' is required"); } @@ -58,10 +49,7 @@ private void validateSql( } } - private void validateJava( - JavaConfig java, - Path configFile - ) { + private void validateJava(JavaConfig java, Path configFile) { if (java == null) { throw invalid(configFile, "'java' is required"); } @@ -71,18 +59,14 @@ private void validateJava( if (!SourceVersion.isName(java.packageName())) { throw invalid( - configFile, - "'java.package' value '%s' is not a valid Java package name" - .formatted(java.packageName()) + configFile, + "'java.package' value '%s' is not a valid Java package name" + .formatted(java.packageName()) ); } } - private void requireValue( - String value, - String field, - Path configFile - ) { + private void requireValue(String value, String field, Path configFile) { if (value == null) { throw invalid(configFile, "'%s' is required".formatted(field)); } @@ -92,12 +76,9 @@ private void requireValue( } } - private ConfigurationException invalid( - Path configFile, - String detail - ) { + private ConfigurationException invalid(Path configFile, String detail) { return new ConfigurationException( - "Invalid configuration in %s: %s".formatted(configFile, detail) + "Invalid configuration in %s: %s".formatted(configFile, detail) ); } } diff --git a/src/main/java/dev/sqlcj/config/ConfigurationException.java b/src/main/java/dev/sqlcj/config/ConfigurationException.java index 0f81153..5dff6b0 100644 --- a/src/main/java/dev/sqlcj/config/ConfigurationException.java +++ b/src/main/java/dev/sqlcj/config/ConfigurationException.java @@ -10,10 +10,7 @@ public ConfigurationException(String message) { super(message); } - public ConfigurationException( - String message, - Throwable cause - ) { + public ConfigurationException(String message, Throwable cause) { super(message, cause); } } diff --git a/src/main/java/dev/sqlcj/config/JavaConfig.java b/src/main/java/dev/sqlcj/config/JavaConfig.java index 8950823..9607e46 100644 --- a/src/main/java/dev/sqlcj/config/JavaConfig.java +++ b/src/main/java/dev/sqlcj/config/JavaConfig.java @@ -3,8 +3,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; public record JavaConfig( - String out, - @JsonProperty("package") - String packageName + String out, + @JsonProperty("package") + String packageName ) { } diff --git a/src/main/java/dev/sqlcj/config/SqlConfig.java b/src/main/java/dev/sqlcj/config/SqlConfig.java index e57e47c..e9c0a68 100644 --- a/src/main/java/dev/sqlcj/config/SqlConfig.java +++ b/src/main/java/dev/sqlcj/config/SqlConfig.java @@ -1,7 +1,7 @@ package dev.sqlcj.config; public record SqlConfig( - String schema, - String queries + String schema, + String queries ) { } diff --git a/src/main/java/dev/sqlcj/config/YamlConfigLoader.java b/src/main/java/dev/sqlcj/config/YamlConfigLoader.java index cedf0b6..96fadbf 100644 --- a/src/main/java/dev/sqlcj/config/YamlConfigLoader.java +++ b/src/main/java/dev/sqlcj/config/YamlConfigLoader.java @@ -21,25 +21,25 @@ public class YamlConfigLoader implements ConfigLoader { private static final ObjectMapper OBJECT_MAPPER = YAMLMapper.builder() - .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) - .withCoercionConfig( - LogicalType.Textual, - coercion -> { - coercion.setCoercion( - CoercionInputShape.Integer, - CoercionAction.Fail - ); - coercion.setCoercion( - CoercionInputShape.Float, - CoercionAction.Fail - ); - coercion.setCoercion( - CoercionInputShape.Boolean, - CoercionAction.Fail - ); - } - ) - .build(); + .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .withCoercionConfig( + LogicalType.Textual, + coercion -> { + coercion.setCoercion( + CoercionInputShape.Integer, + CoercionAction.Fail + ); + coercion.setCoercion( + CoercionInputShape.Float, + CoercionAction.Fail + ); + coercion.setCoercion( + CoercionInputShape.Boolean, + CoercionAction.Fail + ); + } + ) + .build(); private final ConfigValidator validator = new ConfigValidator(); @@ -57,7 +57,7 @@ public Config load(Path path) { private Config read(Path configFile) { if (!Files.isReadable(configFile)) { throw new ConfigurationException( - "Cannot read configuration file: " + configFile + "Cannot read configuration file: " + configFile ); } @@ -67,22 +67,22 @@ private Config read(Path configFile) { config = OBJECT_MAPPER.readValue(configFile.toFile(), Config.class); } catch (UnrecognizedPropertyException e) { throw new ConfigurationException( - "Invalid configuration in %s: unknown field '%s'" - .formatted(configFile, e.getPropertyName()), - e + "Invalid configuration in %s: unknown field '%s'" + .formatted(configFile, e.getPropertyName()), + e ); } catch (MismatchedInputException e) { throw invalidValue(configFile, e); } catch (JacksonException e) { throw new ConfigurationException( - "Malformed configuration file: " + configFile, - e + "Malformed configuration file: " + configFile, + e ); } if (config == null) { throw new ConfigurationException( - "Configuration file is empty: " + configFile + "Configuration file is empty: " + configFile ); } @@ -94,10 +94,7 @@ private Config read(Path configFile) { * naming the configuration file, the offending property path, and the * offending value or type as far as Jackson reports them. */ - private ConfigurationException invalidValue( - Path configFile, - MismatchedInputException e - ) { + private ConfigurationException invalidValue(Path configFile, MismatchedInputException e) { StringBuilder detail = new StringBuilder("invalid "); String property = propertyPath(e); @@ -108,8 +105,7 @@ private ConfigurationException invalidValue( detail.append("value"); - if (e instanceof InvalidFormatException format - && format.getValue() != null) { + if (e instanceof InvalidFormatException format && format.getValue() != null) { detail.append(" '").append(format.getValue()).append("'"); } @@ -126,8 +122,8 @@ private ConfigurationException invalidValue( } return new ConfigurationException( - "Invalid configuration in %s: %s".formatted(configFile, detail), - e + "Invalid configuration in %s: %s".formatted(configFile, detail), + e ); } @@ -185,29 +181,25 @@ private String describeExpectedType(Class targetType) { return "a value of type " + targetType.getSimpleName(); } - private Config resolvePaths( - Config config, - Path baseDirectory - ) { + private Config resolvePaths(Config config, Path baseDirectory) { List sql = config.sql().stream() - .map(entry -> new SqlConfig( - resolvePath(entry.schema(), baseDirectory), - resolvePath(entry.queries(), baseDirectory) - )) - .toList(); + .map( + entry -> new SqlConfig( + resolvePath(entry.schema(), baseDirectory), + resolvePath(entry.queries(), baseDirectory) + ) + ) + .toList(); JavaConfig java = new JavaConfig( - resolvePath(config.java().out(), baseDirectory), - config.java().packageName() + resolvePath(config.java().out(), baseDirectory), + config.java().packageName() ); return new Config(config.version(), sql, java); } - private String resolvePath( - String value, - Path baseDirectory - ) { + private String resolvePath(String value, Path baseDirectory) { Path path = Path.of(value); if (path.isAbsolute()) { diff --git a/src/main/java/dev/sqlcj/generator/GeneratedFile.java b/src/main/java/dev/sqlcj/generator/GeneratedFile.java index 6baf9af..1b0eec8 100644 --- a/src/main/java/dev/sqlcj/generator/GeneratedFile.java +++ b/src/main/java/dev/sqlcj/generator/GeneratedFile.java @@ -3,7 +3,7 @@ import java.nio.file.Path; public record GeneratedFile( - Path path, - String content + Path path, + String content ) { } diff --git a/src/main/java/dev/sqlcj/generator/JavaCodeGenerator.java b/src/main/java/dev/sqlcj/generator/JavaCodeGenerator.java index 0ccd971..c61bfe5 100644 --- a/src/main/java/dev/sqlcj/generator/JavaCodeGenerator.java +++ b/src/main/java/dev/sqlcj/generator/JavaCodeGenerator.java @@ -38,8 +38,8 @@ public JavaCodeGenerator(String packageName) { @Override public GeneratedFile generate(QueryModel query) { return new GeneratedFile( - buildPath(query), - generateSource(query) + buildPath(query), + generateSource(query) ); } @@ -51,26 +51,27 @@ private Path packageDirectory() { String[] segments = packageName.split("\\."); return Path.of( - segments[0], - Arrays.copyOfRange(segments, 1, segments.length) + segments[0], + Arrays.copyOfRange(segments, 1, segments.length) ); } private String generateSource(QueryModel query) { return """ - %s + %s + + %s - %s + %s - %s - - %s - """.formatted( + %s + """ + .formatted( generatePackage(), generateImports(query), generateJavaDoc(query), generateClass(query) - ); + ); } private String generatePackage() { @@ -88,25 +89,25 @@ private String generateImports(QueryModel query) { } query.columns().stream() - .map(QueryColumn::type) - .map(this::resolveImport) - .filter(Objects::nonNull) - .forEach(imports::add); + .map(QueryColumn::type) + .map(this::resolveImport) + .filter(Objects::nonNull) + .forEach(imports::add); query.parameters().stream() - .map(QueryParameter::type) - .map(this::resolveImport) - .filter(Objects::nonNull) - .forEach(imports::add); + .map(QueryParameter::type) + .map(this::resolveImport) + .filter(Objects::nonNull) + .forEach(imports::add); return imports.stream() - .map(type -> "import " + type + ";") - .collect(Collectors.joining("\n")); + .map(type -> "import " + type + ";") + .collect(Collectors.joining("\n")); } private boolean hasResult(QueryModel query) { return query.type() == QueryType.ONE - || query.type() == QueryType.MANY; + || query.type() == QueryType.MANY; } private String resolveImport(ColumnType type) { @@ -120,24 +121,25 @@ private String resolveImport(ColumnType type) { private String generateJavaDoc(QueryModel query) { return """ - /** - * Generated by sqlcj. - * - * Query: %s - * Table: %s - * Type: %s - */ - """.formatted( + /** + * Generated by sqlcj. + * + * Query: %s + * Table: %s + * Type: %s + */ + """ + .formatted( query.name(), query.table(), query.type() - ); + ); } private String generateClass(QueryModel query) { String rowMapper = hasResult(query) - ? indent(generateRowMapper(query)) - : ""; + ? indent(generateRowMapper(query)) + : ""; return """ public final class %s { @@ -152,14 +154,15 @@ public final class %s { %s } - """.formatted( + """ + .formatted( query.name(), indent(generateExecutorField()), indent(generateConstructor(query)), indent(generateResultType(query)), rowMapper, indent(generateMethod(query)) - ); + ); } private String indent(String text) { @@ -168,69 +171,75 @@ private String indent(String text) { private String generateResultType(QueryModel query) { return """ - public record %s( - %s - ) { - } - """.formatted( + public record %s( + %s + ) { + } + """ + .formatted( generateResultTypeName(query), generateResultComponents(query) - ); + ); } private String generateResultComponents(QueryModel query) { return query.columns().stream() - .map(this::generateResultComponent) - .collect(Collectors.joining(",\n")); + .map(this::generateResultComponent) + .collect(Collectors.joining(",\n")); } private String generateResultComponent(QueryColumn column) { - return "%s %s".formatted( + return "%s %s" + .formatted( typeResolver.resolve(column.type()), column.name() - ).indent(4).stripTrailing(); + ) + .indent(4) + .stripTrailing(); } private String generateMethodParameters(QueryModel query) { List names = generateParameterNames(query); return IntStream.range(0, query.parameters().size()) - .mapToObj(i -> { - QueryParameter parameter = query.parameters().get(i); + .mapToObj(i -> { + QueryParameter parameter = query.parameters().get(i); - return typeResolver.resolve(parameter.type()) - + " " - + names.get(i); - }) - .collect(Collectors.joining(", ")); + return typeResolver.resolve(parameter.type()) + + " " + + names.get(i); + }) + .collect(Collectors.joining(", ")); } private List generateParameterNames(QueryModel query) { Map occurrences = query.parameters().stream() - .collect(Collectors.groupingBy( - QueryParameter::name, - Collectors.counting() - )); + .collect( + Collectors.groupingBy( + QueryParameter::name, + Collectors.counting() + ) + ); Map indexes = new HashMap<>(); return query.parameters().stream() - .map(parameter -> { - String name = parameter.name(); + .map(parameter -> { + String name = parameter.name(); - if (occurrences.get(name) > 1) { - int occurrence = indexes.merge( - name, - 1, - Integer::sum - ); + if (occurrences.get(name) > 1) { + int occurrence = indexes.merge( + name, + 1, + Integer::sum + ); - name += occurrence; - } + name += occurrence; + } - return name; - }) - .toList(); + return name; + }) + .toList(); } private String generateMethod(QueryModel query) { @@ -242,33 +251,35 @@ private String generateMethod(QueryModel query) { private String generateQueryMethod(QueryModel query) { return """ - public %s %s(%s) { - return executor.%s( - %s, - %s, - ROW_MAPPER - ); - } - """.formatted( + public %s %s(%s) { + return executor.%s( + %s, + %s, + ROW_MAPPER + ); + } + """ + .formatted( generateReturnType(query), generateMethodName(query), generateMethodParameters(query), generateExecutorMethod(query), generateSql(query), generateParameterList(query) - ); + ); } private String generateUnsupportedMethod(QueryModel query) { return """ - public %s %s(%s) { - throw new UnsupportedOperationException("Not implemented"); - } - """.formatted( + public %s %s(%s) { + throw new UnsupportedOperationException("Not implemented"); + } + """ + .formatted( generateReturnType(query), generateMethodName(query), generateMethodParameters(query) - ); + ); } private String generateExecutorMethod(QueryModel query) { @@ -276,15 +287,15 @@ private String generateExecutorMethod(QueryModel query) { case ONE -> "query"; case MANY -> "queryMany"; default -> throw new IllegalStateException( - "Query type does not produce a result: " + query.type() + "Query type does not produce a result: " + query.type() ); }; } private String generateSql(QueryModel query) { return "\"\"\"\n" - + query.executableSql() - + "\"\"\""; + + query.executableSql() + + "\"\"\""; } /** @@ -295,8 +306,8 @@ private String generateParameterList(QueryModel query) { Map namesByIndex = generateParameterNamesByIndex(query); return query.bindingParameterIndexes().stream() - .map(namesByIndex::get) - .collect(Collectors.joining(", ", "List.of(", ")")); + .map(namesByIndex::get) + .collect(Collectors.joining(", ", "List.of(", ")")); } private Map generateParameterNamesByIndex(QueryModel query) { @@ -306,8 +317,8 @@ private Map generateParameterNamesByIndex(QueryModel query) { for (int i = 0; i < query.parameters().size(); i++) { namesByIndex.put( - query.parameters().get(i).index(), - names.get(i) + query.parameters().get(i).index(), + names.get(i) ); } @@ -340,29 +351,30 @@ private String generateRowMapper(QueryModel query) { resultSet -> new %s( %s ); - """.formatted( + """ + .formatted( generateResultTypeName(query), generateResultTypeName(query), generateResultMappings(query) - ); + ); } private String generateResultMappings(QueryModel query) { return query.columns().stream() - .map(this::generateResultMapping) - .collect(Collectors.joining(",\n")); + .map(this::generateResultMapping) + .collect(Collectors.joining(",\n")); } private String generateResultMapping(QueryColumn column) { String javaType = typeResolver.resolve(column.type()); return "resultSet.getObject(\"%s\", %s.class)" - .formatted( - column.name(), - javaType - ) - .indent(8) - .stripTrailing(); + .formatted( + column.name(), + javaType + ) + .indent(8) + .stripTrailing(); } private String generateExecutorField() { @@ -376,6 +388,7 @@ private String generateConstructor(QueryModel query) { public %s(QueryExecutor executor) { this.executor = executor; } - """.formatted(query.name()); + """ + .formatted(query.name()); } } diff --git a/src/main/java/dev/sqlcj/io/GeneratedFileWriter.java b/src/main/java/dev/sqlcj/io/GeneratedFileWriter.java index 7f096b2..10e0afb 100644 --- a/src/main/java/dev/sqlcj/io/GeneratedFileWriter.java +++ b/src/main/java/dev/sqlcj/io/GeneratedFileWriter.java @@ -9,10 +9,7 @@ public final class GeneratedFileWriter { - public void write( - GeneratedFile file, - Path outputDirectory - ) throws IOException { + public void write(GeneratedFile file, Path outputDirectory) throws IOException { Path outputFile = outputDirectory.resolve(file.path()); Path parent = outputFile.getParent(); @@ -22,10 +19,10 @@ public void write( } Files.writeString( - outputFile, - file.content(), - StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING + outputFile, + file.content(), + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING ); } } diff --git a/src/main/java/dev/sqlcj/parser/DefaultQueryParser.java b/src/main/java/dev/sqlcj/parser/DefaultQueryParser.java index 5cf7b88..535d976 100644 --- a/src/main/java/dev/sqlcj/parser/DefaultQueryParser.java +++ b/src/main/java/dev/sqlcj/parser/DefaultQueryParser.java @@ -18,15 +18,12 @@ public List parse(String source) { StringBuilder builder = new StringBuilder(); for (String line : source.lines().toList()) { - if (line.startsWith(HEADER_PREFIX)) { - if (currentName != null) { queries.add(buildQuery(builder, currentName, currentType)); } QueryHeader header = parseHeader(line); - currentName = header.name(); currentType = header.type(); @@ -35,8 +32,9 @@ public List parse(String source) { } if (currentName != null) { - builder.append(line) - .append(System.lineSeparator()); + builder + .append(line) + .append(System.lineSeparator()); } } @@ -48,7 +46,7 @@ public List parse(String source) { for (Query query : queries) { if (!names.add(query.name())) { throw new IllegalArgumentException( - "Duplicate query: " + query.name() + "Duplicate query: " + query.name() ); } } @@ -61,14 +59,14 @@ private Query buildQuery(StringBuilder builder, String currentName, QueryType cu if (sql.isBlank()) { throw new IllegalArgumentException( - "Query '" + currentName + "' has no SQL" + "Query '" + currentName + "' has no SQL" ); } return new Query( - currentName, - currentType, - sql + currentName, + currentType, + sql ); } @@ -78,7 +76,7 @@ private QueryHeader parseHeader(String line) { if (parts.length != 2) { throw new IllegalArgumentException( - "Invalid query header: " + line + "Invalid query header: " + line ); } diff --git a/src/main/java/dev/sqlcj/parser/Query.java b/src/main/java/dev/sqlcj/parser/Query.java index 081c46a..a6d754a 100644 --- a/src/main/java/dev/sqlcj/parser/Query.java +++ b/src/main/java/dev/sqlcj/parser/Query.java @@ -1,8 +1,8 @@ package dev.sqlcj.parser; public record Query( - String name, - QueryType type, - String sql + String name, + QueryType type, + String sql ) { } diff --git a/src/main/java/dev/sqlcj/parser/QueryHeader.java b/src/main/java/dev/sqlcj/parser/QueryHeader.java index 85297e9..bc34dee 100644 --- a/src/main/java/dev/sqlcj/parser/QueryHeader.java +++ b/src/main/java/dev/sqlcj/parser/QueryHeader.java @@ -1,7 +1,7 @@ package dev.sqlcj.parser; public record QueryHeader( - String name, - QueryType type + String name, + QueryType type ) { } diff --git a/src/main/java/dev/sqlcj/runtime/JdbcQueryExecutor.java b/src/main/java/dev/sqlcj/runtime/JdbcQueryExecutor.java index 23bdcac..95eb55a 100644 --- a/src/main/java/dev/sqlcj/runtime/JdbcQueryExecutor.java +++ b/src/main/java/dev/sqlcj/runtime/JdbcQueryExecutor.java @@ -17,15 +17,10 @@ public JdbcQueryExecutor(DataSource dataSource) { } @Override - public T query( - String sql, - List parameters, - RowMapper mapper - ) { + public T query(String sql, List parameters, RowMapper mapper) { try ( - Connection connection = dataSource.getConnection(); - PreparedStatement statement = - connection.prepareStatement(sql) + Connection connection = dataSource.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql) ) { bindParameters(statement, parameters); @@ -38,22 +33,17 @@ public T query( } } catch (SQLException e) { throw new QueryExecutionException( - "Failed to execute query", - e + "Failed to execute query", + e ); } } @Override - public List queryMany( - String sql, - List parameters, - RowMapper mapper - ) { + public List queryMany(String sql, List parameters, RowMapper mapper) { try ( - Connection connection = dataSource.getConnection(); - PreparedStatement statement = - connection.prepareStatement(sql) + Connection connection = dataSource.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql) ) { bindParameters(statement, parameters); @@ -68,16 +58,13 @@ public List queryMany( } } catch (SQLException e) { throw new QueryExecutionException( - "Failed to execute query", - e + "Failed to execute query", + e ); } } - private void bindParameters( - PreparedStatement statement, - List parameters - ) throws SQLException { + private void bindParameters(PreparedStatement statement, List parameters) throws SQLException { for (int i = 0; i < parameters.size(); i++) { statement.setObject(i + 1, parameters.get(i)); } diff --git a/src/main/java/dev/sqlcj/runtime/QueryExecutor.java b/src/main/java/dev/sqlcj/runtime/QueryExecutor.java index a89c615..7448615 100644 --- a/src/main/java/dev/sqlcj/runtime/QueryExecutor.java +++ b/src/main/java/dev/sqlcj/runtime/QueryExecutor.java @@ -4,15 +4,7 @@ public interface QueryExecutor { - T query( - String sql, - List parameters, - RowMapper mapper - ); + T query(String sql, List parameters, RowMapper mapper); - List queryMany( - String sql, - List parameters, - RowMapper mapper - ); + List queryMany(String sql, List parameters, RowMapper mapper); } diff --git a/src/main/java/dev/sqlcj/schema/Column.java b/src/main/java/dev/sqlcj/schema/Column.java index f3dc5f7..5e672cf 100644 --- a/src/main/java/dev/sqlcj/schema/Column.java +++ b/src/main/java/dev/sqlcj/schema/Column.java @@ -1,8 +1,8 @@ package dev.sqlcj.schema; public record Column( - String name, - ColumnType type, - boolean nullable + String name, + ColumnType type, + boolean nullable ) { } diff --git a/src/main/java/dev/sqlcj/schema/Constraint.java b/src/main/java/dev/sqlcj/schema/Constraint.java index 0413394..862ebfc 100644 --- a/src/main/java/dev/sqlcj/schema/Constraint.java +++ b/src/main/java/dev/sqlcj/schema/Constraint.java @@ -3,8 +3,8 @@ import java.util.List; public record Constraint( - ConstraintType type, - List columns + ConstraintType type, + List columns ) { public Constraint { diff --git a/src/main/java/dev/sqlcj/schema/Schema.java b/src/main/java/dev/sqlcj/schema/Schema.java index 9656af2..57b9000 100644 --- a/src/main/java/dev/sqlcj/schema/Schema.java +++ b/src/main/java/dev/sqlcj/schema/Schema.java @@ -3,7 +3,7 @@ import java.util.List; public record Schema( - List tables + List
tables ) { public Schema { diff --git a/src/main/java/dev/sqlcj/schema/Table.java b/src/main/java/dev/sqlcj/schema/Table.java index 2ac8534..8029c45 100644 --- a/src/main/java/dev/sqlcj/schema/Table.java +++ b/src/main/java/dev/sqlcj/schema/Table.java @@ -3,9 +3,9 @@ import java.util.List; public record Table( - String name, - List columns, - List constraints + String name, + List columns, + List constraints ) { public Table { diff --git a/src/main/java/dev/sqlcj/schema/parser/DefaultSchemaParser.java b/src/main/java/dev/sqlcj/schema/parser/DefaultSchemaParser.java index a4d91e1..00ccbfa 100644 --- a/src/main/java/dev/sqlcj/schema/parser/DefaultSchemaParser.java +++ b/src/main/java/dev/sqlcj/schema/parser/DefaultSchemaParser.java @@ -30,8 +30,8 @@ public Schema parse(String sql) { for (Statement statement : statements) { if (!(statement instanceof CreateTable createTable)) { throw new UnsupportedOperationException( - "Unsupported schema statement: " - + statement.getClass().getSimpleName() + "Unsupported schema statement: " + + statement.getClass().getSimpleName() ); } @@ -58,9 +58,9 @@ private Table parseTable(CreateTable createTable) { constraints.addAll(parseTableConstraints(createTable)); return new Table( - tableName, - columns, - constraints + tableName, + columns, + constraints ); } @@ -70,16 +70,16 @@ private Column parseColumn(ColumnDefinition definition) { boolean nullable = isNullable(definition); return new Column( - name, - type, - nullable + name, + type, + nullable ); } private ColumnType parseColumnType(ColumnDefinition definition) { String typeName = definition.getColDataType() - .getDataType() - .toUpperCase(Locale.ROOT); + .getDataType() + .toUpperCase(Locale.ROOT); int parenthesisIndex = typeName.indexOf('('); @@ -98,7 +98,7 @@ private ColumnType parseColumnType(ColumnDefinition definition) { case "TIMESTAMP" -> ColumnType.TIMESTAMP; case "DECIMAL", "NUMERIC" -> ColumnType.DECIMAL; default -> throw new UnsupportedOperationException( - "Unsupported SQL column type: " + typeName + "Unsupported SQL column type: " + typeName ); }; } @@ -111,8 +111,7 @@ private boolean isNullable(ColumnDefinition definition) { } for (int i = 0; i < specs.size() - 1; i++) { - if ("NOT".equalsIgnoreCase(specs.get(i)) - && "NULL".equalsIgnoreCase(specs.get(i + 1))) { + if ("NOT".equalsIgnoreCase(specs.get(i)) && "NULL".equalsIgnoreCase(specs.get(i + 1))) { return false; } } @@ -132,24 +131,22 @@ private List parseColumnConstraints(ColumnDefinition definition) { for (int i = 0; i < specs.size(); i++) { String spec = specs.get(i); - if ("PRIMARY".equalsIgnoreCase(spec) - && i + 1 < specs.size() - && "KEY".equalsIgnoreCase(specs.get(i + 1))) { + if ("PRIMARY".equalsIgnoreCase(spec) && i + 1 < specs.size() && "KEY".equalsIgnoreCase(specs.get(i + 1))) { constraints.add( - new Constraint( - ConstraintType.PRIMARY_KEY, - List.of(definition.getColumnName()) - ) + new Constraint( + ConstraintType.PRIMARY_KEY, + List.of(definition.getColumnName()) + ) ); } if ("UNIQUE".equalsIgnoreCase(spec)) { constraints.add( - new Constraint( - ConstraintType.UNIQUE, - List.of(definition.getColumnName()) - ) + new Constraint( + ConstraintType.UNIQUE, + List.of(definition.getColumnName()) + ) ); } } @@ -173,15 +170,15 @@ private List parseTableConstraints(CreateTable createTable) { case "PRIMARY KEY" -> ConstraintType.PRIMARY_KEY; case "UNIQUE" -> ConstraintType.UNIQUE; default -> throw new UnsupportedOperationException( - "Unsupported table constraint: " + indexType + "Unsupported table constraint: " + indexType ); }; constraints.add( - new Constraint( - type, - index.getColumnsNames() - ) + new Constraint( + type, + index.getColumnsNames() + ) ); } diff --git a/src/test/java/dev/sqlcj/analysis/QueryAnalyzerTest.java b/src/test/java/dev/sqlcj/analysis/QueryAnalyzerTest.java index 4b01951..ccbf1db 100644 --- a/src/test/java/dev/sqlcj/analysis/QueryAnalyzerTest.java +++ b/src/test/java/dev/sqlcj/analysis/QueryAnalyzerTest.java @@ -21,17 +21,17 @@ class QueryAnalyzerTest { private static final Schema schema = new Schema( - List.of( - new Table( - "users", - List.of( - new Column("id", ColumnType.BIGINT, false), - new Column("name", ColumnType.VARCHAR, true), - new Column("active", ColumnType.BOOLEAN, true) - ), - List.of() - ) + List.of( + new Table( + "users", + List.of( + new Column("id", ColumnType.BIGINT, false), + new Column("name", ColumnType.VARCHAR, true), + new Column("active", ColumnType.BOOLEAN, true) + ), + List.of() ) + ) ); private final SqlParser parser = new SqlParser(); @@ -40,9 +40,9 @@ class QueryAnalyzerTest { @Test void shouldAnalyzeSelectWithoutParameters() { Query query = new Query( - "ListUsers", - QueryType.MANY, - """ + "ListUsers", + QueryType.MANY, + """ SELECT * FROM users; """ @@ -60,9 +60,9 @@ void shouldAnalyzeSelectWithoutParameters() { @Test void shouldAnalyzeSelectWithSingleParameter() { Query query = new Query( - "GetUser", - QueryType.ONE, - """ + "GetUser", + QueryType.ONE, + """ SELECT * FROM users WHERE id = $1; @@ -74,19 +74,19 @@ void shouldAnalyzeSelectWithSingleParameter() { assertEquals("users", model.table()); assertEquals( - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ), - model.parameters() + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) + ), + model.parameters() ); } @Test void shouldAnalyzeSelectWithMultipleParameters() { Query query = new Query( - "ListUsersByIdAndName", - QueryType.MANY, - """ + "ListUsersByIdAndName", + QueryType.MANY, + """ SELECT * FROM users WHERE id = $1 @@ -99,20 +99,20 @@ void shouldAnalyzeSelectWithMultipleParameters() { assertEquals("users", model.table()); assertEquals( - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "name", ColumnType.VARCHAR) - ), - model.parameters() + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "name", ColumnType.VARCHAR) + ), + model.parameters() ); } @Test void shouldRejectInsertStatements() { Query query = new Query( - "InsertUser", - QueryType.EXEC, - """ + "InsertUser", + QueryType.EXEC, + """ INSERT INTO users(id) VALUES ($1); """ @@ -120,24 +120,23 @@ INSERT INTO users(id) Statement statement = parser.parse(query.sql()); - UnsupportedOperationException exception = - assertThrows( - UnsupportedOperationException.class, - () -> analyzer.analyze(query, statement, schema) - ); + UnsupportedOperationException exception = assertThrows( + UnsupportedOperationException.class, + () -> analyzer.analyze(query, statement, schema) + ); assertEquals( - "INSERT is not supported yet", - exception.getMessage() + "INSERT is not supported yet", + exception.getMessage() ); } @Test void shouldRejectUpdateStatements() { Query query = new Query( - "UpdateUser", - QueryType.EXEC, - """ + "UpdateUser", + QueryType.EXEC, + """ UPDATE users SET username = $2 WHERE id = $1; @@ -146,24 +145,23 @@ void shouldRejectUpdateStatements() { Statement statement = parser.parse(query.sql()); - UnsupportedOperationException exception = - assertThrows( - UnsupportedOperationException.class, - () -> analyzer.analyze(query, statement, schema) - ); + UnsupportedOperationException exception = assertThrows( + UnsupportedOperationException.class, + () -> analyzer.analyze(query, statement, schema) + ); assertEquals( - "UPDATE is not supported yet", - exception.getMessage() + "UPDATE is not supported yet", + exception.getMessage() ); } @Test void shouldRejectDeleteStatements() { Query query = new Query( - "DeleteUser", - QueryType.EXEC, - """ + "DeleteUser", + QueryType.EXEC, + """ DELETE users WHERE id = $1; """ @@ -171,32 +169,31 @@ void shouldRejectDeleteStatements() { Statement statement = parser.parse(query.sql()); - UnsupportedOperationException exception = - assertThrows( - UnsupportedOperationException.class, - () -> analyzer.analyze(query, statement, schema) - ); + UnsupportedOperationException exception = assertThrows( + UnsupportedOperationException.class, + () -> analyzer.analyze(query, statement, schema) + ); assertEquals( - "DELETE is not supported yet", - exception.getMessage() + "DELETE is not supported yet", + exception.getMessage() ); } @Test void shouldAnalyzeSelectWithExplicitColumns() { Query query = new Query( - "GetUser", - QueryType.ONE, - "SELECT id, name FROM users WHERE id = $1" + "GetUser", + QueryType.ONE, + "SELECT id, name FROM users WHERE id = $1" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals("GetUser", model.name()); @@ -204,37 +201,37 @@ void shouldAnalyzeSelectWithExplicitColumns() { assertEquals("users", model.table()); assertEquals( - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - model.columns() + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + model.columns() ); } @Test void shouldResolveAllColumns() { Query query = new Query( - "ListUsers", - QueryType.MANY, - "SELECT * FROM users" + "ListUsers", + QueryType.MANY, + "SELECT * FROM users" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals( - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true), - new QueryColumn("active", ColumnType.BOOLEAN, true) - ), - model.columns() + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true), + new QueryColumn("active", ColumnType.BOOLEAN, true) + ), + model.columns() ); assertTrue(model.parameters().isEmpty()); @@ -243,71 +240,71 @@ void shouldResolveAllColumns() { @Test void shouldResolveParameterTypeFromColumn() { Query query = new Query( - "GetUser", - QueryType.ONE, - "SELECT * FROM users WHERE id = $1" + "GetUser", + QueryType.ONE, + "SELECT * FROM users WHERE id = $1" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals( - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ), - model.parameters() + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) + ), + model.parameters() ); } @Test void shouldResolveMultipleParameters() { Query query = new Query( - "ListUsersByIdAndName", - QueryType.MANY, + "ListUsersByIdAndName", + QueryType.MANY, + """ + SELECT * + FROM users + WHERE id = $1 + AND name = $2 """ - SELECT * - FROM users - WHERE id = $1 - AND name = $2 - """ ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals( - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "name", ColumnType.VARCHAR) - ), - model.parameters() + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "name", ColumnType.VARCHAR) + ), + model.parameters() ); } @Test void shouldNotCreateParametersForLiteralExpressions() { Query query = new Query( - "ListUsers", - QueryType.MANY, - "SELECT * FROM users WHERE 1 = 1" + "ListUsers", + QueryType.MANY, + "SELECT * FROM users WHERE 1 = 1" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertTrue(model.parameters().isEmpty()); @@ -316,49 +313,49 @@ void shouldNotCreateParametersForLiteralExpressions() { @Test void shouldThrowWhenTableDoesNotExist() { Query query = new Query( - "GetOrder", - QueryType.ONE, - "SELECT * FROM orders" + "GetOrder", + QueryType.ONE, + "SELECT * FROM orders" ); Statement statement = parser.parse(query.sql()); assertThrows( - IllegalArgumentException.class, - () -> analyzer.analyze(query, statement, schema) + IllegalArgumentException.class, + () -> analyzer.analyze(query, statement, schema) ); } @Test void shouldThrowWhenColumnDoesNotExist() { Query query = new Query( - "GetUser", - QueryType.ONE, - "SELECT username FROM users" + "GetUser", + QueryType.ONE, + "SELECT username FROM users" ); Statement statement = parser.parse(query.sql()); assertThrows( - IllegalArgumentException.class, - () -> analyzer.analyze(query, statement, schema) + IllegalArgumentException.class, + () -> analyzer.analyze(query, statement, schema) ); } @Test void shouldResolveQueryParameterFromReferencedColumn() { Query query = new Query( - "GetUser", - QueryType.ONE, - "SELECT * FROM users WHERE id = $1" + "GetUser", + QueryType.ONE, + "SELECT * FROM users WHERE id = $1" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(1, model.parameters().size()); @@ -373,17 +370,17 @@ void shouldResolveQueryParameterFromReferencedColumn() { @Test void shouldResolveMultipleQueryParameters() { Query query = new Query( - "FindUsers", - QueryType.MANY, - "SELECT * FROM users WHERE id = $1 AND active = $2" + "FindUsers", + QueryType.MANY, + "SELECT * FROM users WHERE id = $1 AND active = $2" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(2, model.parameters().size()); @@ -402,17 +399,17 @@ void shouldResolveMultipleQueryParameters() { @Test void shouldResolveMultipleParametersForSameColumn() { Query query = new Query( - "FindUsers", - QueryType.MANY, - "SELECT * FROM users WHERE id = $1 AND id = $2" + "FindUsers", + QueryType.MANY, + "SELECT * FROM users WHERE id = $1 AND id = $2" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(2, model.parameters().size()); @@ -431,17 +428,17 @@ void shouldResolveMultipleParametersForSameColumn() { @Test void shouldResolveQueryParametersInIndexOrder() { Query query = new Query( - "FindUser", - QueryType.ONE, - "SELECT * FROM users WHERE active = $2 AND id = $1" + "FindUser", + QueryType.ONE, + "SELECT * FROM users WHERE active = $2 AND id = $1" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(2, model.parameters().size()); @@ -460,17 +457,17 @@ void shouldResolveQueryParametersInIndexOrder() { @Test void shouldResolveQueryParametersInsideOrExpression() { Query query = new Query( - "FindUsers", - QueryType.MANY, - "SELECT * FROM users WHERE id = $1 OR active = $2" + "FindUsers", + QueryType.MANY, + "SELECT * FROM users WHERE id = $1 OR active = $2" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(2, model.parameters().size()); @@ -489,9 +486,9 @@ void shouldResolveQueryParametersInsideOrExpression() { @Test void shouldResolveQueryParametersInsideNestedAndOrExpressions() { Query query = new Query( - "FindUsers", - QueryType.MANY, - """ + "FindUsers", + QueryType.MANY, + """ SELECT * FROM users WHERE id = $1 @@ -502,9 +499,9 @@ void shouldResolveQueryParametersInsideNestedAndOrExpressions() { Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(3, model.parameters().size()); @@ -528,9 +525,9 @@ void shouldResolveQueryParametersInsideNestedAndOrExpressions() { @Test void shouldResolveQueryParametersForComparisonOperators() { Query query = new Query( - "FindUsers", - QueryType.MANY, - """ + "FindUsers", + QueryType.MANY, + """ SELECT * FROM users WHERE id > $1 @@ -541,9 +538,9 @@ void shouldResolveQueryParametersForComparisonOperators() { Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(2, model.parameters().size()); @@ -560,33 +557,36 @@ void shouldResolveQueryParametersForComparisonOperators() { } @ParameterizedTest - @ValueSource(strings = { + @ValueSource( + strings = { "=", "<>", ">", ">=", "<", "<=" - }) + } + ) void shouldResolveQueryParameterForComparisonOperator( - String operator + String operator ) { Query query = new Query( - "FindUser", - QueryType.ONE, - """ + "FindUser", + QueryType.ONE, + """ SELECT * FROM users WHERE id %s $1 - """.formatted(operator) + """ + .formatted(operator) ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(1, model.parameters().size()); @@ -601,17 +601,17 @@ void shouldResolveQueryParameterForComparisonOperator( @Test void shouldResolveQueryParameterWhenParameterIsOnLeftSide() { Query query = new Query( - "FindUser", - QueryType.ONE, - "SELECT * FROM users WHERE $1 = id" + "FindUser", + QueryType.ONE, + "SELECT * FROM users WHERE $1 = id" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(1, model.parameters().size()); @@ -626,17 +626,17 @@ void shouldResolveQueryParameterWhenParameterIsOnLeftSide() { @Test void shouldResolveQueryParametersInsideInExpression() { Query query = new Query( - "FindUsers", - QueryType.MANY, - "SELECT * FROM users WHERE id IN ($1, $2, $3)" + "FindUsers", + QueryType.MANY, + "SELECT * FROM users WHERE id IN ($1, $2, $3)" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(3, model.parameters().size()); @@ -660,17 +660,17 @@ void shouldResolveQueryParametersInsideInExpression() { @Test void shouldResolveQueryParametersInsideInExpressionInIndexOrder() { Query query = new Query( - "FindUsers", - QueryType.MANY, - "SELECT * FROM users WHERE id IN ($3, $1, $2)" + "FindUsers", + QueryType.MANY, + "SELECT * FROM users WHERE id IN ($3, $1, $2)" ); Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(3, model.parameters().size()); @@ -694,9 +694,9 @@ void shouldResolveQueryParametersInsideInExpressionInIndexOrder() { @Test void shouldResolveQueryParametersFromCombinedExpressions() { Query query = new Query( - "FindUsers", - QueryType.MANY, - """ + "FindUsers", + QueryType.MANY, + """ SELECT * FROM users WHERE id IN ($1, $2) @@ -707,9 +707,9 @@ WHERE id IN ($1, $2) Statement statement = parser.parse(query.sql()); QueryModel model = analyzer.analyze( - query, - statement, - schema + query, + statement, + schema ); assertEquals(4, model.parameters().size()); @@ -744,29 +744,29 @@ void shouldProduceExecutableSql() { """; Query query = new Query( - "GetUser", - QueryType.ONE, - sql + "GetUser", + QueryType.ONE, + sql ); QueryModel model = analyzer.analyze( - query, - parser.parse(sql), - schema + query, + parser.parse(sql), + schema ); assertEquals( - """ + """ SELECT id, name FROM users WHERE id = ? """, - model.executableSql() + model.executableSql() ); assertEquals( - List.of(1), - model.bindingParameterIndexes() + List.of(1), + model.bindingParameterIndexes() ); } @@ -780,38 +780,38 @@ void shouldResolveBindingIndexesInTextualOrder() { """; Query query = new Query( - "FindUser", - QueryType.ONE, - sql + "FindUser", + QueryType.ONE, + sql ); QueryModel model = analyzer.analyze( - query, - parser.parse(sql), - schema + query, + parser.parse(sql), + schema ); assertEquals( - """ + """ SELECT id, name FROM users WHERE active = ? AND id = ? """, - model.executableSql() + model.executableSql() ); assertEquals( - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "active", ColumnType.BOOLEAN) - ), - model.parameters() + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "active", ColumnType.BOOLEAN) + ), + model.parameters() ); assertEquals( - List.of(2, 1), - model.bindingParameterIndexes() + List.of(2, 1), + model.bindingParameterIndexes() ); } @@ -823,15 +823,15 @@ void shouldResolveEmptyBindingIndexesWithoutParameters() { """; Query query = new Query( - "ListUsers", - QueryType.MANY, - sql + "ListUsers", + QueryType.MANY, + sql ); QueryModel model = analyzer.analyze( - query, - parser.parse(sql), - schema + query, + parser.parse(sql), + schema ); assertTrue(model.bindingParameterIndexes().isEmpty()); diff --git a/src/test/java/dev/sqlcj/cli/command/GenerateCommandTest.java b/src/test/java/dev/sqlcj/cli/command/GenerateCommandTest.java index a756eae..e106af8 100644 --- a/src/test/java/dev/sqlcj/cli/command/GenerateCommandTest.java +++ b/src/test/java/dev/sqlcj/cli/command/GenerateCommandTest.java @@ -19,19 +19,19 @@ class GenerateCommandTest { private static final String SCHEMA = """ - CREATE TABLE users - ( - id BIGINT NOT NULL, - name VARCHAR(255) - ); - """; + CREATE TABLE users + ( + id BIGINT NOT NULL, + name VARCHAR(255) + ); + """; private static final String QUERIES = """ - -- name: GetUser :one - SELECT id, name - FROM users - WHERE id = $1; - """; + -- name: GetUser :one + SELECT id, name + FROM users + WHERE id = $1; + """; @TempDir Path workingDirectory; @@ -41,8 +41,8 @@ void shouldGenerateFromConfigurationInWorkingDirectory() throws Exception { Files.writeString(workingDirectory.resolve("schema.sql"), SCHEMA); Files.writeString(workingDirectory.resolve("queries.sql"), QUERIES); Files.writeString( - workingDirectory.resolve("sqlcj.yaml"), - """ + workingDirectory.resolve("sqlcj.yaml"), + """ version: "1" sql: - schema: schema.sql @@ -57,25 +57,21 @@ void shouldGenerateFromConfigurationInWorkingDirectory() throws Exception { assertEquals(0, result.exitCode(), result.error()); - Path generated = workingDirectory.resolve( - "generated/dev/example/generated/GetUser.java" - ); + Path generated = workingDirectory.resolve("generated/dev/example/generated/GetUser.java"); assertTrue(Files.exists(generated), result.error()); assertTrue( - Files.readString(generated) - .startsWith("package dev.example.generated;") + Files.readString(generated) + .startsWith("package dev.example.generated;") ); } @Test - void shouldFailWithConciseDiagnosticForMalformedConfiguration() - throws Exception { - + void shouldFailWithConciseDiagnosticForMalformedConfiguration() throws Exception { Files.writeString( - workingDirectory.resolve("sqlcj.yaml"), - """ + workingDirectory.resolve("sqlcj.yaml"), + """ version: "1" sql: - schema: schema.sql @@ -95,13 +91,11 @@ void shouldFailWithConciseDiagnosticForMalformedConfiguration() } @Test - void shouldFailWithConciseDiagnosticForUnreadableSource() - throws Exception { - + void shouldFailWithConciseDiagnosticForUnreadableSource() throws Exception { Files.writeString(workingDirectory.resolve("schema.sql"), SCHEMA); Files.writeString( - workingDirectory.resolve("sqlcj.yaml"), - """ + workingDirectory.resolve("sqlcj.yaml"), + """ version: "1" sql: - schema: schema.sql @@ -117,9 +111,9 @@ void shouldFailWithConciseDiagnosticForUnreadableSource() assertEquals(1, result.exitCode(), result.error()); assertTrue(result.error().contains("sqlcj: Cannot read queries source")); assertTrue( - result.error().contains( - workingDirectory.resolve("missing.sql").toString() - ) + result.error().contains( + workingDirectory.resolve("missing.sql").toString() + ) ); assertFalse(result.error().contains("\tat ")); assertFalse(Files.exists(workingDirectory.resolve("generated"))); @@ -129,30 +123,30 @@ private Result runGenerate() throws IOException, InterruptedException { Path java = Path.of(System.getProperty("java.home"), "bin", "java"); Process process = new ProcessBuilder( - java.toString(), - "-classpath", - System.getProperty("java.class.path"), - "dev.sqlcj.Main", - "generate" + java.toString(), + "-classpath", + System.getProperty("java.class.path"), + "dev.sqlcj.Main", + "generate" ) - .directory(workingDirectory.toFile()) - .start(); + .directory(workingDirectory.toFile()) + .start(); String output = new String(process.getInputStream().readAllBytes()); String error = new String(process.getErrorStream().readAllBytes()); assertTrue( - process.waitFor(60, TimeUnit.SECONDS), - "sqlcj generate did not terminate" + process.waitFor(60, TimeUnit.SECONDS), + "sqlcj generate did not terminate" ); return new Result(process.exitValue(), output, error); } private record Result( - int exitCode, - String output, - String error + int exitCode, + String output, + String error ) { } } diff --git a/src/test/java/dev/sqlcj/compiler/DefaultSourceLoaderTest.java b/src/test/java/dev/sqlcj/compiler/DefaultSourceLoaderTest.java index 431fd05..590ec92 100644 --- a/src/test/java/dev/sqlcj/compiler/DefaultSourceLoaderTest.java +++ b/src/test/java/dev/sqlcj/compiler/DefaultSourceLoaderTest.java @@ -26,42 +26,42 @@ class DefaultSourceLoaderTest { @Test void shouldLoadEntriesInDeclaredOrder() throws IOException { Path userSchema = write("users-schema.sql", """ - CREATE TABLE users - ( - id BIGINT NOT NULL - ); - """); + CREATE TABLE users + ( + id BIGINT NOT NULL + ); + """); Path userQueries = write("users-queries.sql", """ - -- name: GetUser :one - SELECT id - FROM users - WHERE id = $1; + -- name: GetUser :one + SELECT id + FROM users + WHERE id = $1; - -- name: ListUsers :many - SELECT id - FROM users; - """); + -- name: ListUsers :many + SELECT id + FROM users; + """); Path orderSchema = write("orders-schema.sql", """ - CREATE TABLE orders - ( - id BIGINT NOT NULL - ); - """); + CREATE TABLE orders + ( + id BIGINT NOT NULL + ); + """); Path orderQueries = write("orders-queries.sql", """ - -- name: GetOrder :one - SELECT id - FROM orders - WHERE id = $1; - """); + -- name: GetOrder :one + SELECT id + FROM orders + WHERE id = $1; + """); List sources = sourceLoader.load( - config( - new SqlConfig(userSchema.toString(), userQueries.toString()), - new SqlConfig(orderSchema.toString(), orderQueries.toString()) - ) + config( + new SqlConfig(userSchema.toString(), userQueries.toString()), + new SqlConfig(orderSchema.toString(), orderQueries.toString()) + ) ); assertEquals(2, sources.size()); @@ -70,80 +70,80 @@ void shouldLoadEntriesInDeclaredOrder() throws IOException { assertTrue(sources.get(1).schema().contains("CREATE TABLE orders")); assertEquals( - List.of("GetUser", "ListUsers"), - names(sources.getFirst()) + List.of("GetUser", "ListUsers"), + names(sources.getFirst()) ); assertEquals( - List.of("GetOrder"), - names(sources.get(1)) + List.of("GetOrder"), + names(sources.get(1)) ); } @Test void shouldRejectDuplicateQueryNameAcrossEntries() throws IOException { Path schema = write("schema.sql", """ - CREATE TABLE users - ( - id BIGINT NOT NULL - ); - """); + CREATE TABLE users + ( + id BIGINT NOT NULL + ); + """); Path firstQueries = write("first.sql", """ - -- name: GetUser :one - SELECT id - FROM users - WHERE id = $1; - """); + -- name: GetUser :one + SELECT id + FROM users + WHERE id = $1; + """); Path secondQueries = write("second.sql", """ - -- name: GetUser :many - SELECT id - FROM users; - """); + -- name: GetUser :many + SELECT id + FROM users; + """); CompilationException exception = assertThrows( - CompilationException.class, - () -> sourceLoader.load( - config( - new SqlConfig(schema.toString(), firstQueries.toString()), - new SqlConfig(schema.toString(), secondQueries.toString()) - ) + CompilationException.class, + () -> sourceLoader.load( + config( + new SqlConfig(schema.toString(), firstQueries.toString()), + new SqlConfig(schema.toString(), secondQueries.toString()) ) + ) ); assertEquals( - "Duplicate query name 'GetUser' in query source: " + secondQueries, - exception.getMessage() + "Duplicate query name 'GetUser' in query source: " + secondQueries, + exception.getMessage() ); } @Test void shouldRejectUnreadableQueriesSource() throws IOException { Path schema = write("schema.sql", """ - CREATE TABLE users - ( - id BIGINT NOT NULL - ); - """); + CREATE TABLE users + ( + id BIGINT NOT NULL + ); + """); Path missingQueries = tempDir.resolve("missing.sql"); CompilationException exception = assertThrows( - CompilationException.class, - () -> sourceLoader.load( - config( - new SqlConfig( - schema.toString(), - missingQueries.toString() - ) - ) + CompilationException.class, + () -> sourceLoader.load( + config( + new SqlConfig( + schema.toString(), + missingQueries.toString() + ) ) + ) ); assertEquals( - "Cannot read queries source: " + missingQueries, - exception.getMessage() + "Cannot read queries source: " + missingQueries, + exception.getMessage() ); } @@ -152,67 +152,67 @@ void shouldRejectUnreadableSchemaSource() throws IOException { Path missingSchema = tempDir.resolve("missing.sql"); Path queries = write("queries.sql", """ - -- name: GetUser :one - SELECT id - FROM users - WHERE id = $1; - """); + -- name: GetUser :one + SELECT id + FROM users + WHERE id = $1; + """); CompilationException exception = assertThrows( - CompilationException.class, - () -> sourceLoader.load( - config( - new SqlConfig( - missingSchema.toString(), - queries.toString() - ) - ) + CompilationException.class, + () -> sourceLoader.load( + config( + new SqlConfig( + missingSchema.toString(), + queries.toString() + ) ) + ) ); assertEquals( - "Cannot read schema source: " + missingSchema, - exception.getMessage() + "Cannot read schema source: " + missingSchema, + exception.getMessage() ); } @Test void shouldReportInvalidQuerySourceWithItsPath() throws IOException { Path schema = write("schema.sql", """ - CREATE TABLE users - ( - id BIGINT NOT NULL - ); - """); + CREATE TABLE users + ( + id BIGINT NOT NULL + ); + """); Path queries = write("queries.sql", """ - -- name: GetUser :one - SELECT id - FROM users - WHERE id = $1; + -- name: GetUser :one + SELECT id + FROM users + WHERE id = $1; - -- name: GetUser :one - SELECT id - FROM users; - """); + -- name: GetUser :one + SELECT id + FROM users; + """); CompilationException exception = assertThrows( - CompilationException.class, - () -> sourceLoader.load( - config( - new SqlConfig( - schema.toString(), - queries.toString() - ) - ) + CompilationException.class, + () -> sourceLoader.load( + config( + new SqlConfig( + schema.toString(), + queries.toString() + ) ) + ) ); assertTrue( - exception.getMessage().startsWith( - "Invalid query source " + queries + ":" - ), - exception.getMessage() + exception.getMessage().startsWith( + "Invalid query source " + queries + ":" + ), + exception.getMessage() ); } @@ -222,18 +222,15 @@ private List names(Source source) { private Config config(SqlConfig... entries) { return new Config( - List.of(entries), - new JavaConfig( - tempDir.resolve("generated").toString(), - "dev.example.generated" - ) + List.of(entries), + new JavaConfig( + tempDir.resolve("generated").toString(), + "dev.example.generated" + ) ); } - private Path write( - String name, - String content - ) throws IOException { + private Path write(String name, String content) throws IOException { Path file = tempDir.resolve(name); Files.writeString(file, content); diff --git a/src/test/java/dev/sqlcj/compiler/SqlcjCompilerIntegrationTest.java b/src/test/java/dev/sqlcj/compiler/SqlcjCompilerIntegrationTest.java index a4e026f..aa2601d 100644 --- a/src/test/java/dev/sqlcj/compiler/SqlcjCompilerIntegrationTest.java +++ b/src/test/java/dev/sqlcj/compiler/SqlcjCompilerIntegrationTest.java @@ -44,23 +44,23 @@ void shouldGenerateCompilableJavaFiles() throws IOException { Path classesDirectory = tempDir.resolve("classes"); Files.writeString( - schemaFile, + schemaFile, + """ + CREATE TABLE users + ( + id BIGINT NOT NULL, + name VARCHAR(255), + active BOOLEAN, + birth_date DATE, + created_at TIMESTAMP, + balance DECIMAL(10, 2) + ); """ - CREATE TABLE users - ( - id BIGINT NOT NULL, - name VARCHAR(255), - active BOOLEAN, - birth_date DATE, - created_at TIMESTAMP, - balance DECIMAL(10, 2) - ); - """ ); Files.writeString( - queriesFile, - """ + queriesFile, + """ -- name: GetUser :one SELECT * FROM users @@ -80,30 +80,27 @@ WHERE id IN ($1, $2) ); Config config = new Config( - List.of( - new SqlConfig( - schemaFile.toString(), - queriesFile.toString() - ) - ), - new JavaConfig( - generatedDirectory.toString(), - "generated" + List.of( + new SqlConfig( + schemaFile.toString(), + queriesFile.toString() ) + ), + new JavaConfig( + generatedDirectory.toString(), + "generated" + ) ); SqlcjCompiler compiler = new SqlcjCompiler(); compiler.compile(config); - Path getUserFile = - generatedDirectory.resolve("generated/GetUser.java"); + Path getUserFile = generatedDirectory.resolve("generated/GetUser.java"); - Path listUsersFile = - generatedDirectory.resolve("generated/ListUsers.java"); + Path listUsersFile = generatedDirectory.resolve("generated/ListUsers.java"); - Path findUsersFile = - generatedDirectory.resolve("generated/FindUsers.java"); + Path findUsersFile = generatedDirectory.resolve("generated/FindUsers.java"); assertTrue(Files.exists(getUserFile)); assertTrue(Files.exists(listUsersFile)); @@ -113,35 +110,19 @@ WHERE id IN ($1, $2) assertTrue(getUser.contains("import java.time.LocalDate;")); assertTrue(getUser.contains("import java.time.LocalDateTime;")); assertTrue(getUser.contains("import java.math.BigDecimal;")); - assertTrue(getUser.contains( - "public GetUserResult getUser(LocalDateTime created_at)" - )); + assertTrue(getUser.contains("public GetUserResult getUser(LocalDateTime created_at)")); assertTrue(getUser.contains("Long id")); assertTrue(getUser.contains("String name")); assertTrue(getUser.contains("LocalDate birth_date")); assertTrue(getUser.contains("LocalDateTime created_at")); assertTrue(getUser.contains("BigDecimal balance")); - assertTrue(getUser.contains( - "private static final RowMapper ROW_MAPPER" - )); - assertTrue(getUser.contains( - "resultSet.getObject(\"id\", Long.class)" - )); - assertTrue(getUser.contains( - "resultSet.getObject(\"name\", String.class)" - )); - assertTrue(getUser.contains( - "resultSet.getObject(\"active\", Boolean.class)" - )); - assertTrue(getUser.contains( - "resultSet.getObject(\"birth_date\", LocalDate.class)" - )); - assertTrue(getUser.contains( - "resultSet.getObject(\"created_at\", LocalDateTime.class)" - )); - assertTrue(getUser.contains( - "resultSet.getObject(\"balance\", BigDecimal.class)" - )); + assertTrue(getUser.contains("private static final RowMapper ROW_MAPPER")); + assertTrue(getUser.contains("resultSet.getObject(\"id\", Long.class)")); + assertTrue(getUser.contains("resultSet.getObject(\"name\", String.class)")); + assertTrue(getUser.contains("resultSet.getObject(\"active\", Boolean.class)")); + assertTrue(getUser.contains("resultSet.getObject(\"birth_date\", LocalDate.class)")); + assertTrue(getUser.contains("resultSet.getObject(\"created_at\", LocalDateTime.class)")); + assertTrue(getUser.contains("resultSet.getObject(\"balance\", BigDecimal.class)")); String listUsers = Files.readString(listUsersFile); assertTrue(listUsers.contains("public final class ListUsers")); @@ -149,22 +130,16 @@ WHERE id IN ($1, $2) assertTrue(listUsers.contains("import java.time.LocalDate;")); assertTrue(listUsers.contains("import java.time.LocalDateTime;")); assertTrue(listUsers.contains("import java.math.BigDecimal;")); - assertTrue(listUsers.contains( - "public List listUsers(LocalDateTime created_at)" - )); + assertTrue(listUsers.contains("public List listUsers(LocalDateTime created_at)")); String findUsers = Files.readString(findUsersFile); assertTrue(findUsers.contains("public final class FindUsers")); assertTrue(findUsers.contains("import java.util.List;")); - - assertTrue(findUsers.contains( - "public List findUsers(Long id1, Long id2, Boolean active, String name)" - )); - - assertTrue(findUsers.contains( - "public record FindUsersResult(" - )); - + assertTrue( + findUsers + .contains("public List findUsers(Long id1, Long id2, Boolean active, String name)") + ); + assertTrue(findUsers.contains("public record FindUsersResult(")); assertTrue(findUsers.contains("Long id")); assertTrue(findUsers.contains("String name")); @@ -177,36 +152,36 @@ WHERE id IN ($1, $2) String classpath = System.getProperty("java.class.path"); int result = compilerApi.run( - null, - null, - null, - "-classpath", - classpath, - "-d", - classesDirectory.toString(), - getUserFile.toString(), - listUsersFile.toString(), - findUsersFile.toString() + null, + null, + null, + "-classpath", + classpath, + "-d", + classesDirectory.toString(), + getUserFile.toString(), + listUsersFile.toString(), + findUsersFile.toString() ); assertEquals(0, result); assertTrue( - Files.exists( - classesDirectory.resolve("generated/GetUser.class") - ) + Files.exists( + classesDirectory.resolve("generated/GetUser.class") + ) ); assertTrue( - Files.exists( - classesDirectory.resolve("generated/ListUsers.class") - ) + Files.exists( + classesDirectory.resolve("generated/ListUsers.class") + ) ); assertTrue( - Files.exists( - classesDirectory.resolve("generated/FindUsers.class") - ) + Files.exists( + classesDirectory.resolve("generated/FindUsers.class") + ) ); } @@ -218,23 +193,23 @@ void shouldExecuteGeneratedQuery() throws Exception { Path classesDirectory = tempDir.resolve("classes"); Files.writeString( - schemaFile, + schemaFile, + """ + CREATE TABLE users + ( + id BIGINT NOT NULL, + name VARCHAR(255), + active BOOLEAN, + birth_date DATE, + created_at TIMESTAMP, + balance DECIMAL(10, 2) + ); """ - CREATE TABLE users - ( - id BIGINT NOT NULL, - name VARCHAR(255), - active BOOLEAN, - birth_date DATE, - created_at TIMESTAMP, - balance DECIMAL(10, 2) - ); - """ ); Files.writeString( - queriesFile, - """ + queriesFile, + """ -- name: GetUser :one SELECT * FROM users @@ -243,16 +218,16 @@ balance DECIMAL(10, 2) ); Config config = new Config( - List.of( - new SqlConfig( - schemaFile.toString(), - queriesFile.toString() - ) - ), - new JavaConfig( - generatedDirectory.toString(), - "generated" + List.of( + new SqlConfig( + schemaFile.toString(), + queriesFile.toString() ) + ), + new JavaConfig( + generatedDirectory.toString(), + "generated" + ) ); SqlcjCompiler compiler = new SqlcjCompiler(); @@ -272,14 +247,14 @@ balance DECIMAL(10, 2) String classpath = System.getProperty("java.class.path"); int compilationResult = compilerApi.run( - null, - null, - null, - "-classpath", - classpath, - "-d", - classesDirectory.toString(), - getUserFile.toString() + null, + null, + null, + "-classpath", + classpath, + "-d", + classesDirectory.toString(), + getUserFile.toString() ); assertEquals(0, compilationResult); @@ -287,13 +262,13 @@ balance DECIMAL(10, 2) JdbcDataSource dataSource = new JdbcDataSource(); dataSource.setURL( - "jdbc:h2:mem:" + UUID.randomUUID() - + ";DB_CLOSE_DELAY=-1" + "jdbc:h2:mem:" + UUID.randomUUID() + + ";DB_CLOSE_DELAY=-1" ); try ( - Connection connection = dataSource.getConnection(); - Statement statement = connection.createStatement() + Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement() ) { statement.execute(""" CREATE TABLE users ( @@ -318,58 +293,53 @@ balance DECIMAL(10, 2) QueryExecutor executor = new JdbcQueryExecutor(dataSource); URL[] classpathUrls = { - classesDirectory.toUri().toURL() + classesDirectory.toUri().toURL() }; try (URLClassLoader classLoader = new URLClassLoader(classpathUrls, getClass().getClassLoader())) { - Class generatedClass = - Class.forName( - "generated.GetUser", - true, - classLoader - ); - - Constructor constructor = - generatedClass.getConstructor( - QueryExecutor.class - ); - - Object generatedQuery = - constructor.newInstance(executor); - - Method method = - generatedClass.getMethod( - "getUser", - LocalDateTime.class - ); - - Object result = - method.invoke( - generatedQuery, - LocalDateTime.of( - 2026, - 1, - 1, - 10, - 0 - ) - ); + Class generatedClass = Class.forName( + "generated.GetUser", + true, + classLoader + ); + + Constructor constructor = generatedClass.getConstructor( + QueryExecutor.class + ); + + Object generatedQuery = constructor.newInstance(executor); + + Method method = generatedClass.getMethod( + "getUser", + LocalDateTime.class + ); + + Object result = method.invoke( + generatedQuery, + LocalDateTime.of( + 2026, + 1, + 1, + 10, + 0 + ) + ); assertNotNull(result); assertEquals( - 1L, - getRecordComponent(result, "id") + 1L, + getRecordComponent(result, "id") ); assertEquals( - "Alice", - getRecordComponent(result, "name") + "Alice", + getRecordComponent(result, "name") ); assertEquals( - true, - getRecordComponent(result, "active") + true, + getRecordComponent(result, "active") ); } } @@ -382,23 +352,23 @@ void shouldExecuteGeneratedManyQuery() throws Exception { Path classesDirectory = tempDir.resolve("classes"); Files.writeString( - schemaFile, + schemaFile, + """ + CREATE TABLE users + ( + id BIGINT NOT NULL, + name VARCHAR(255), + active BOOLEAN, + birth_date DATE, + created_at TIMESTAMP, + balance DECIMAL(10, 2) + ); """ - CREATE TABLE users - ( - id BIGINT NOT NULL, - name VARCHAR(255), - active BOOLEAN, - birth_date DATE, - created_at TIMESTAMP, - balance DECIMAL(10, 2) - ); - """ ); Files.writeString( - queriesFile, - """ + queriesFile, + """ -- name: ListActiveUsers :many SELECT id, name, active FROM users @@ -408,46 +378,43 @@ balance DECIMAL(10, 2) ); Config config = new Config( - List.of( - new SqlConfig( - schemaFile.toString(), - queriesFile.toString() - ) - ), - new JavaConfig( - generatedDirectory.toString(), - "generated" + List.of( + new SqlConfig( + schemaFile.toString(), + queriesFile.toString() ) + ), + new JavaConfig( + generatedDirectory.toString(), + "generated" + ) ); SqlcjCompiler compiler = new SqlcjCompiler(); compiler.compile(config); - Path listActiveUsersFile = - generatedDirectory.resolve("generated/ListActiveUsers.java"); + Path listActiveUsersFile = generatedDirectory.resolve("generated/ListActiveUsers.java"); assertTrue(Files.exists(listActiveUsersFile)); Files.createDirectories(classesDirectory); - JavaCompiler compilerApi = - ToolProvider.getSystemJavaCompiler(); + JavaCompiler compilerApi = ToolProvider.getSystemJavaCompiler(); assertNotNull(compilerApi); - String classpath = - System.getProperty("java.class.path"); + String classpath = System.getProperty("java.class.path"); int compilationResult = compilerApi.run( - null, - null, - null, - "-classpath", - classpath, - "-d", - classesDirectory.toString(), - listActiveUsersFile.toString() + null, + null, + null, + "-classpath", + classpath, + "-d", + classesDirectory.toString(), + listActiveUsersFile.toString() ); assertEquals(0, compilationResult); @@ -455,13 +422,13 @@ balance DECIMAL(10, 2) JdbcDataSource dataSource = new JdbcDataSource(); dataSource.setURL( - "jdbc:h2:mem:" + UUID.randomUUID() - + ";DB_CLOSE_DELAY=-1" + "jdbc:h2:mem:" + UUID.randomUUID() + + ";DB_CLOSE_DELAY=-1" ); try ( - Connection connection = dataSource.getConnection(); - Statement statement = connection.createStatement() + Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement() ) { statement.execute(""" CREATE TABLE users ( @@ -487,45 +454,39 @@ balance DECIMAL(10, 2) """); } - QueryExecutor executor = - new JdbcQueryExecutor(dataSource); + QueryExecutor executor = new JdbcQueryExecutor(dataSource); URL[] classpathUrls = { - classesDirectory.toUri().toURL() + classesDirectory.toUri().toURL() }; - try (URLClassLoader classLoader = - new URLClassLoader( - classpathUrls, - getClass().getClassLoader() - )) { - - Class generatedClass = - Class.forName( - "generated.ListActiveUsers", - true, - classLoader - ); - - Constructor constructor = - generatedClass.getConstructor( - QueryExecutor.class - ); - - Object generatedQuery = - constructor.newInstance(executor); - - Method method = - generatedClass.getMethod( - "listActiveUsers", - Boolean.class - ); - - Object result = - method.invoke( - generatedQuery, - true - ); + try ( + URLClassLoader classLoader = new URLClassLoader( + classpathUrls, + getClass().getClassLoader() + ) + ) { + Class generatedClass = Class.forName( + "generated.ListActiveUsers", + true, + classLoader + ); + + Constructor constructor = generatedClass.getConstructor( + QueryExecutor.class + ); + + Object generatedQuery = constructor.newInstance(executor); + + Method method = generatedClass.getMethod( + "listActiveUsers", + Boolean.class + ); + + Object result = method.invoke( + generatedQuery, + true + ); assertNotNull(result); assertInstanceOf(List.class, result); @@ -538,59 +499,57 @@ balance DECIMAL(10, 2) Object second = users.get(1); assertEquals( - 1L, - getRecordComponent(first, "id") + 1L, + getRecordComponent(first, "id") ); assertEquals( - "Alice", - getRecordComponent(first, "name") + "Alice", + getRecordComponent(first, "name") ); assertEquals( - true, - getRecordComponent(first, "active") + true, + getRecordComponent(first, "active") ); assertEquals( - 3L, - getRecordComponent(second, "id") + 3L, + getRecordComponent(second, "id") ); assertEquals( - "Charlie", - getRecordComponent(second, "name") + "Charlie", + getRecordComponent(second, "name") ); assertEquals( - true, - getRecordComponent(second, "active") + true, + getRecordComponent(second, "active") ); } } @Test - void shouldExecuteGeneratedQueryWithOutOfOrderPlaceholders() - throws Exception { - + void shouldExecuteGeneratedQueryWithOutOfOrderPlaceholders() throws Exception { Path classesDirectory = generateAndCompile( - """ + """ -- name: FindUser :one SELECT id, name, active FROM users WHERE active = $2 AND id = $1; """, - "FindUser" + "FindUser" ); - String source = Files.readString( - tempDir.resolve("generated/generated/FindUser.java") - ); + String source = Files.readString(tempDir.resolve("generated/generated/FindUser.java")); - assertTrue(source.contains( + assertTrue( + source.contains( "public FindUserResult findUser(Long id, Boolean active)" - )); + ) + ); assertTrue(source.contains("List.of(active, id)")); @@ -598,19 +557,19 @@ void shouldExecuteGeneratedQueryWithOutOfOrderPlaceholders() try (URLClassLoader classLoader = classLoader(classesDirectory)) { Class generatedClass = Class.forName( - "generated.FindUser", - true, - classLoader + "generated.FindUser", + true, + classLoader ); Object generatedQuery = generatedClass - .getConstructor(QueryExecutor.class) - .newInstance(executor); + .getConstructor(QueryExecutor.class) + .newInstance(executor); Method method = generatedClass.getMethod( - "findUser", - Long.class, - Boolean.class + "findUser", + Long.class, + Boolean.class ); Object result = method.invoke(generatedQuery, 1L, true); @@ -626,22 +585,22 @@ void shouldExecuteGeneratedQueryWithOutOfOrderPlaceholders() @Test void shouldExecuteGeneratedQueryWithoutParameters() throws Exception { Path classesDirectory = generateAndCompile( - """ + """ -- name: GetFirstUser :one SELECT id, name FROM users ORDER BY id; """, - "GetFirstUser" + "GetFirstUser" ); - String source = Files.readString( - tempDir.resolve("generated/generated/GetFirstUser.java") - ); + String source = Files.readString(tempDir.resolve("generated/generated/GetFirstUser.java")); - assertTrue(source.contains( + assertTrue( + source.contains( "public GetFirstUserResult getFirstUser()" - )); + ) + ); assertTrue(source.contains("List.of()")); @@ -649,18 +608,18 @@ void shouldExecuteGeneratedQueryWithoutParameters() throws Exception { try (URLClassLoader classLoader = classLoader(classesDirectory)) { Class generatedClass = Class.forName( - "generated.GetFirstUser", - true, - classLoader + "generated.GetFirstUser", + true, + classLoader ); Object generatedQuery = generatedClass - .getConstructor(QueryExecutor.class) - .newInstance(executor); + .getConstructor(QueryExecutor.class) + .newInstance(executor); Object result = generatedClass - .getMethod("getFirstUser") - .invoke(generatedQuery); + .getMethod("getFirstUser") + .invoke(generatedQuery); assertNotNull(result); @@ -670,9 +629,7 @@ void shouldExecuteGeneratedQueryWithoutParameters() throws Exception { } @Test - void shouldCompileConfiguredEntriesWithConfiguredPackage() - throws IOException { - + void shouldCompileConfiguredEntriesWithConfiguredPackage() throws IOException { Path usersSchema = tempDir.resolve("users-schema.sql"); Path usersQueries = tempDir.resolve("users-queries.sql"); Path ordersSchema = tempDir.resolve("orders-schema.sql"); @@ -681,74 +638,70 @@ void shouldCompileConfiguredEntriesWithConfiguredPackage() Path classesDirectory = tempDir.resolve("classes"); Files.writeString( - usersSchema, + usersSchema, + """ + CREATE TABLE users + ( + id BIGINT NOT NULL, + name VARCHAR(255) + ); """ - CREATE TABLE users - ( - id BIGINT NOT NULL, - name VARCHAR(255) - ); - """ ); Files.writeString( - usersQueries, + usersQueries, + """ + -- name: GetUser :one + SELECT id, name + FROM users + WHERE id = $1; """ - -- name: GetUser :one - SELECT id, name - FROM users - WHERE id = $1; - """ ); Files.writeString( - ordersSchema, + ordersSchema, + """ + CREATE TABLE orders + ( + id BIGINT NOT NULL, + total DECIMAL(10, 2), + created_at TIMESTAMP + ); """ - CREATE TABLE orders - ( - id BIGINT NOT NULL, - total DECIMAL(10, 2), - created_at TIMESTAMP - ); - """ ); Files.writeString( - ordersQueries, + ordersQueries, + """ + -- name: ListOrders :many + SELECT id, total, created_at + FROM orders + WHERE created_at = $1; """ - -- name: ListOrders :many - SELECT id, total, created_at - FROM orders - WHERE created_at = $1; - """ ); Config config = new Config( - List.of( - new SqlConfig( - usersSchema.toString(), - usersQueries.toString() - ), - new SqlConfig( - ordersSchema.toString(), - ordersQueries.toString() - ) + List.of( + new SqlConfig( + usersSchema.toString(), + usersQueries.toString() ), - new JavaConfig( - generatedDirectory.toString(), - "dev.example.generated" + new SqlConfig( + ordersSchema.toString(), + ordersQueries.toString() ) + ), + new JavaConfig( + generatedDirectory.toString(), + "dev.example.generated" + ) ); new SqlcjCompiler().compile(config); - Path getUserFile = generatedDirectory.resolve( - "dev/example/generated/GetUser.java" - ); + Path getUserFile = generatedDirectory.resolve("dev/example/generated/GetUser.java"); - Path listOrdersFile = generatedDirectory.resolve( - "dev/example/generated/ListOrders.java" - ); + Path listOrdersFile = generatedDirectory.resolve("dev/example/generated/ListOrders.java"); assertTrue(Files.exists(getUserFile)); assertTrue(Files.exists(listOrdersFile)); @@ -756,16 +709,12 @@ total DECIMAL(10, 2), String getUser = Files.readString(getUserFile); assertTrue(getUser.startsWith("package dev.example.generated;")); - assertTrue(getUser.contains( - "public GetUserResult getUser(Long id)" - )); + assertTrue(getUser.contains("public GetUserResult getUser(Long id)")); String listOrders = Files.readString(listOrdersFile); assertTrue(listOrders.startsWith("package dev.example.generated;")); - assertTrue(listOrders.contains( - "public List listOrders(LocalDateTime created_at)" - )); + assertTrue(listOrders.contains("public List listOrders(LocalDateTime created_at)")); assertTrue(listOrders.contains("BigDecimal total")); Files.createDirectories(classesDirectory); @@ -775,40 +724,38 @@ total DECIMAL(10, 2), assertNotNull(compilerApi); int compilationResult = compilerApi.run( - null, - null, - null, - "-classpath", - System.getProperty("java.class.path"), - "-d", - classesDirectory.toString(), - getUserFile.toString(), - listOrdersFile.toString() + null, + null, + null, + "-classpath", + System.getProperty("java.class.path"), + "-d", + classesDirectory.toString(), + getUserFile.toString(), + listOrdersFile.toString() ); assertEquals(0, compilationResult); assertTrue( - Files.exists( - classesDirectory.resolve( - "dev/example/generated/GetUser.class" - ) + Files.exists( + classesDirectory.resolve( + "dev/example/generated/GetUser.class" ) + ) ); assertTrue( - Files.exists( - classesDirectory.resolve( - "dev/example/generated/ListOrders.class" - ) + Files.exists( + classesDirectory.resolve( + "dev/example/generated/ListOrders.class" ) + ) ); } @Test - void shouldRejectDuplicateQueryNameAcrossEntriesBeforeWriting() - throws IOException { - + void shouldRejectDuplicateQueryNameAcrossEntriesBeforeWriting() throws IOException { Path usersSchema = tempDir.resolve("users-schema.sql"); Path usersQueries = tempDir.resolve("users-queries.sql"); Path ordersSchema = tempDir.resolve("orders-schema.sql"); @@ -816,118 +763,114 @@ void shouldRejectDuplicateQueryNameAcrossEntriesBeforeWriting() Path generatedDirectory = tempDir.resolve("generated"); Files.writeString( - usersSchema, + usersSchema, + """ + CREATE TABLE users + ( + id BIGINT NOT NULL + ); """ - CREATE TABLE users - ( - id BIGINT NOT NULL - ); - """ ); Files.writeString( - usersQueries, + usersQueries, + """ + -- name: GetRecord :one + SELECT id + FROM users + WHERE id = $1; """ - -- name: GetRecord :one - SELECT id - FROM users - WHERE id = $1; - """ ); Files.writeString( - ordersSchema, + ordersSchema, + """ + CREATE TABLE orders + ( + id BIGINT NOT NULL + ); """ - CREATE TABLE orders - ( - id BIGINT NOT NULL - ); - """ ); Files.writeString( - ordersQueries, + ordersQueries, + """ + -- name: GetRecord :one + SELECT id + FROM orders + WHERE id = $1; """ - -- name: GetRecord :one - SELECT id - FROM orders - WHERE id = $1; - """ ); Config config = new Config( - List.of( - new SqlConfig( - usersSchema.toString(), - usersQueries.toString() - ), - new SqlConfig( - ordersSchema.toString(), - ordersQueries.toString() - ) + List.of( + new SqlConfig( + usersSchema.toString(), + usersQueries.toString() ), - new JavaConfig( - generatedDirectory.toString(), - "dev.example.generated" + new SqlConfig( + ordersSchema.toString(), + ordersQueries.toString() ) + ), + new JavaConfig( + generatedDirectory.toString(), + "dev.example.generated" + ) ); SqlcjCompiler compiler = new SqlcjCompiler(); CompilationException exception = assertThrows( - CompilationException.class, - () -> compiler.compile(config) + CompilationException.class, + () -> compiler.compile(config) ); assertEquals( - "Duplicate query name 'GetRecord' in query source: " - + ordersQueries, - exception.getMessage() + "Duplicate query name 'GetRecord' in query source: " + + ordersQueries, + exception.getMessage() ); assertFalse(Files.exists(generatedDirectory)); } - private Path generateAndCompile( - String queries, - String queryName - ) throws IOException { + private Path generateAndCompile(String queries, String queryName) throws IOException { Path schemaFile = tempDir.resolve("schema.sql"); Path queriesFile = tempDir.resolve("queries.sql"); Path generatedDirectory = tempDir.resolve("generated"); Path classesDirectory = tempDir.resolve("classes"); Files.writeString( - schemaFile, + schemaFile, + """ + CREATE TABLE users + ( + id BIGINT NOT NULL, + name VARCHAR(255), + active BOOLEAN + ); """ - CREATE TABLE users - ( - id BIGINT NOT NULL, - name VARCHAR(255), - active BOOLEAN - ); - """ ); Files.writeString(queriesFile, queries); Config config = new Config( - List.of( - new SqlConfig( - schemaFile.toString(), - queriesFile.toString() - ) - ), - new JavaConfig( - generatedDirectory.toString(), - "generated" + List.of( + new SqlConfig( + schemaFile.toString(), + queriesFile.toString() ) + ), + new JavaConfig( + generatedDirectory.toString(), + "generated" + ) ); new SqlcjCompiler().compile(config); - Path generatedFile = - generatedDirectory.resolve("generated").resolve(queryName + ".java"); + Path generatedFile = generatedDirectory.resolve("generated").resolve(queryName + ".java"); assertTrue(Files.exists(generatedFile)); @@ -938,14 +881,14 @@ name VARCHAR(255), assertNotNull(compilerApi); int compilationResult = compilerApi.run( - null, - null, - null, - "-classpath", - System.getProperty("java.class.path"), - "-d", - classesDirectory.toString(), - generatedFile.toString() + null, + null, + null, + "-classpath", + System.getProperty("java.class.path"), + "-d", + classesDirectory.toString(), + generatedFile.toString() ); assertEquals(0, compilationResult); @@ -953,12 +896,10 @@ name VARCHAR(255), return classesDirectory; } - private URLClassLoader classLoader(Path classesDirectory) - throws IOException { - + private URLClassLoader classLoader(Path classesDirectory) throws IOException { return new URLClassLoader( - new URL[]{classesDirectory.toUri().toURL()}, - getClass().getClassLoader() + new URL[] { classesDirectory.toUri().toURL() }, + getClass().getClassLoader() ); } @@ -966,12 +907,12 @@ private JdbcDataSource usersDataSource() throws Exception { JdbcDataSource dataSource = new JdbcDataSource(); dataSource.setURL( - "jdbc:h2:mem:" + UUID.randomUUID() + ";DB_CLOSE_DELAY=-1" + "jdbc:h2:mem:" + UUID.randomUUID() + ";DB_CLOSE_DELAY=-1" ); try ( - Connection connection = dataSource.getConnection(); - Statement statement = connection.createStatement() + Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement() ) { statement.execute(""" CREATE TABLE users ( @@ -992,13 +933,10 @@ INSERT INTO users (id, name, active) return dataSource; } - private Object getRecordComponent( - Object record, - String componentName - ) throws Exception { + private Object getRecordComponent(Object record, String componentName) throws Exception { return record - .getClass() - .getMethod(componentName) - .invoke(record); + .getClass() + .getMethod(componentName) + .invoke(record); } } diff --git a/src/test/java/dev/sqlcj/config/YamlConfigLoaderTest.java b/src/test/java/dev/sqlcj/config/YamlConfigLoaderTest.java index e366e09..1eeaf00 100644 --- a/src/test/java/dev/sqlcj/config/YamlConfigLoaderTest.java +++ b/src/test/java/dev/sqlcj/config/YamlConfigLoaderTest.java @@ -22,107 +22,105 @@ class YamlConfigLoaderTest { @Test void shouldMapVersionOneFields() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + out: generated + """); Config config = configLoader.load(configFile); assertEquals("1", config.version()); assertEquals(1, config.sql().size()); assertEquals( - tempDir.resolve("schema.sql").toString(), - config.sql().getFirst().schema() + tempDir.resolve("schema.sql").toString(), + config.sql().getFirst().schema() ); assertEquals( - tempDir.resolve("queries.sql").toString(), - config.sql().getFirst().queries() + tempDir.resolve("queries.sql").toString(), + config.sql().getFirst().queries() ); assertEquals( - "dev.example.generated", - config.java().packageName() + "dev.example.generated", + config.java().packageName() ); assertEquals( - tempDir.resolve("generated").toString(), - config.java().out() + tempDir.resolve("generated").toString(), + config.java().out() ); } @Test void shouldPreserveSqlEntryOrder() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: users.sql - queries: user-queries.sql - - schema: orders.sql - queries: order-queries.sql - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: + - schema: users.sql + queries: user-queries.sql + - schema: orders.sql + queries: order-queries.sql + java: + package: dev.example.generated + out: generated + """); Config config = configLoader.load(configFile); assertEquals( - List.of( - tempDir.resolve("users.sql").toString(), - tempDir.resolve("orders.sql").toString() - ), - config.sql().stream().map(SqlConfig::schema).toList() + List.of( + tempDir.resolve("users.sql").toString(), + tempDir.resolve("orders.sql").toString() + ), + config.sql().stream().map(SqlConfig::schema).toList() ); assertEquals( - List.of( - tempDir.resolve("user-queries.sql").toString(), - tempDir.resolve("order-queries.sql").toString() - ), - config.sql().stream().map(SqlConfig::queries).toList() + List.of( + tempDir.resolve("user-queries.sql").toString(), + tempDir.resolve("order-queries.sql").toString() + ), + config.sql().stream().map(SqlConfig::queries).toList() ); } @Test - void shouldResolveRelativePathsAgainstConfigurationDirectory() - throws IOException { - + void shouldResolveRelativePathsAgainstConfigurationDirectory() throws IOException { Path configDirectory = Files.createDirectories( - tempDir.resolve("project").resolve("config") + tempDir.resolve("project").resolve("config") ); Path configFile = configDirectory.resolve("sqlcj.yaml"); Files.writeString(configFile, """ - version: "1" - sql: - - schema: ../sql/schema.sql - queries: ./queries.sql - java: - package: dev.example.generated - out: ../target/generated - """); + version: "1" + sql: + - schema: ../sql/schema.sql + queries: ./queries.sql + java: + package: dev.example.generated + out: ../target/generated + """); Config config = configLoader.load( - Path.of(configFile.toString()) + Path.of(configFile.toString()) ); assertEquals( - tempDir.resolve("project/sql/schema.sql").toString(), - config.sql().getFirst().schema() + tempDir.resolve("project/sql/schema.sql").toString(), + config.sql().getFirst().schema() ); assertEquals( - configDirectory.resolve("queries.sql").toString(), - config.sql().getFirst().queries() + configDirectory.resolve("queries.sql").toString(), + config.sql().getFirst().queries() ); assertEquals( - tempDir.resolve("project/target/generated").toString(), - config.java().out() + tempDir.resolve("project/target/generated").toString(), + config.java().out() ); } @@ -132,7 +130,8 @@ void shouldKeepAbsolutePathsAbsolute() throws IOException { Path queriesFile = tempDir.resolve("absolute").resolve("queries.sql"); Path outputDirectory = tempDir.resolve("absolute").resolve("out"); - Path configFile = write(""" + Path configFile = write( + """ version: "1" sql: - schema: %s @@ -140,23 +139,25 @@ void shouldKeepAbsolutePathsAbsolute() throws IOException { java: package: dev.example.generated out: %s - """.formatted(schemaFile, queriesFile, outputDirectory)); + """ + .formatted(schemaFile, queriesFile, outputDirectory) + ); Config config = configLoader.load(configFile); assertEquals( - schemaFile.toString(), - config.sql().getFirst().schema() + schemaFile.toString(), + config.sql().getFirst().schema() ); assertEquals( - queriesFile.toString(), - config.sql().getFirst().queries() + queriesFile.toString(), + config.sql().getFirst().queries() ); assertEquals( - outputDirectory.toString(), - config.java().out() + outputDirectory.toString(), + config.java().out() ); } @@ -165,50 +166,50 @@ void shouldRejectMissingConfigurationFile() { Path configFile = tempDir.resolve("sqlcj.yaml"); ConfigurationException exception = assertThrows( - ConfigurationException.class, - () -> configLoader.load(configFile) + ConfigurationException.class, + () -> configLoader.load(configFile) ); assertTrue( - exception.getMessage().contains( - "Cannot read configuration file: " + configFile - ), - exception.getMessage() + exception.getMessage().contains( + "Cannot read configuration file: " + configFile + ), + exception.getMessage() ); } @Test void shouldRejectMalformedYaml() throws IOException { Path configFile = write(""" - version: "1" - sql: [ - """); + version: "1" + sql: [ + """); ConfigurationException exception = assertThrows( - ConfigurationException.class, - () -> configLoader.load(configFile) + ConfigurationException.class, + () -> configLoader.load(configFile) ); assertTrue( - exception.getMessage().contains( - "Malformed configuration file: " + configFile - ), - exception.getMessage() + exception.getMessage().contains( + "Malformed configuration file: " + configFile + ), + exception.getMessage() ); } @Test void shouldRejectUnknownField() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - out: generated - indent: 2 - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + out: generated + indent: 2 + """); assertInvalid(configFile, "unknown field 'indent'"); } @@ -216,86 +217,86 @@ void shouldRejectUnknownField() throws IOException { @Test void shouldRejectWrongTypedField() throws IOException { Path configFile = write(""" - version: "1" - sql: schema.sql - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: schema.sql + java: + package: dev.example.generated + out: generated + """); assertInvalid( - configFile, - "invalid 'sql' value of type string, expected a list" + configFile, + "invalid 'sql' value of type string, expected a list" ); } @Test void shouldRejectWrongTypedNestedField() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: 42 - queries: queries.sql - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: + - schema: 42 + queries: queries.sql + java: + package: dev.example.generated + out: generated + """); assertInvalid( - configFile, - "invalid 'sql[0].schema' value '42' of type number, " - + "expected a string" + configFile, + "invalid 'sql[0].schema' value '42' of type number, " + + "expected a string" ); } @Test void shouldRejectWrongTypedJavaOut() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - out: - - generated - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + out: + - generated + """); assertInvalid( - configFile, - "invalid 'java.out' value of type list, expected a string" + configFile, + "invalid 'java.out' value of type list, expected a string" ); } @Test void shouldRejectNumericVersion() throws IOException { Path configFile = write(""" - version: 1 - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - out: generated - """); + version: 1 + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + out: generated + """); assertInvalid( - configFile, - "invalid 'version' value '1' of type number, " - + "expected a string" + configFile, + "invalid 'version' value '1' of type number, " + + "expected a string" ); } @Test void shouldRejectMissingVersion() throws IOException { Path configFile = write(""" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - out: generated - """); + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + out: generated + """); assertInvalid(configFile, "'version' is required"); } @@ -303,29 +304,29 @@ void shouldRejectMissingVersion() throws IOException { @Test void shouldRejectUnsupportedVersion() throws IOException { Path configFile = write(""" - version: "2" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - out: generated - """); + version: "2" + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + out: generated + """); assertInvalid( - configFile, - "unsupported 'version' value '2', expected '1'" + configFile, + "unsupported 'version' value '2', expected '1'" ); } @Test void shouldRejectMissingSqlSection() throws IOException { Path configFile = write(""" - version: "1" - java: - package: dev.example.generated - out: generated - """); + version: "1" + java: + package: dev.example.generated + out: generated + """); assertInvalid(configFile, "'sql' is required"); } @@ -333,12 +334,12 @@ void shouldRejectMissingSqlSection() throws IOException { @Test void shouldRejectEmptySqlList() throws IOException { Path configFile = write(""" - version: "1" - sql: [] - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: [] + java: + package: dev.example.generated + out: generated + """); assertInvalid(configFile, "'sql' must contain at least one entry"); } @@ -346,15 +347,15 @@ void shouldRejectEmptySqlList() throws IOException { @Test void shouldRejectNullSqlEntry() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - - - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + - + java: + package: dev.example.generated + out: generated + """); assertInvalid(configFile, "'sql[1]' must not be null"); } @@ -362,14 +363,14 @@ void shouldRejectNullSqlEntry() throws IOException { @Test void shouldRejectBlankQueriesValue() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: " " - java: - package: dev.example.generated - out: generated - """); + version: "1" + sql: + - schema: schema.sql + queries: " " + java: + package: dev.example.generated + out: generated + """); assertInvalid(configFile, "'sql[0].queries' must not be blank"); } @@ -377,11 +378,11 @@ void shouldRejectBlankQueriesValue() throws IOException { @Test void shouldRejectMissingJavaSection() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + """); assertInvalid(configFile, "'java' is required"); } @@ -389,13 +390,13 @@ void shouldRejectMissingJavaSection() throws IOException { @Test void shouldRejectMissingJavaOut() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.example.generated - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.example.generated + """); assertInvalid(configFile, "'java.out' is required"); } @@ -403,34 +404,31 @@ void shouldRejectMissingJavaOut() throws IOException { @Test void shouldRejectInvalidJavaPackage() throws IOException { Path configFile = write(""" - version: "1" - sql: - - schema: schema.sql - queries: queries.sql - java: - package: dev.class.generated - out: generated - """); + version: "1" + sql: + - schema: schema.sql + queries: queries.sql + java: + package: dev.class.generated + out: generated + """); assertInvalid( - configFile, - "'java.package' value 'dev.class.generated' " - + "is not a valid Java package name" + configFile, + "'java.package' value 'dev.class.generated' " + + "is not a valid Java package name" ); } - private void assertInvalid( - Path configFile, - String detail - ) { + private void assertInvalid(Path configFile, String detail) { ConfigurationException exception = assertThrows( - ConfigurationException.class, - () -> configLoader.load(configFile) + ConfigurationException.class, + () -> configLoader.load(configFile) ); assertEquals( - "Invalid configuration in %s: %s".formatted(configFile, detail), - exception.getMessage() + "Invalid configuration in %s: %s".formatted(configFile, detail), + exception.getMessage() ); } diff --git a/src/test/java/dev/sqlcj/generator/JavaCodeGeneratorTest.java b/src/test/java/dev/sqlcj/generator/JavaCodeGeneratorTest.java index bb8f406..939e1ea 100644 --- a/src/test/java/dev/sqlcj/generator/JavaCodeGeneratorTest.java +++ b/src/test/java/dev/sqlcj/generator/JavaCodeGeneratorTest.java @@ -34,35 +34,35 @@ class JavaCodeGeneratorTest { @Test void shouldGenerateFilePath() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertEquals( - Path.of("generated", "GetUser.java"), - file.path() + Path.of("generated", "GetUser.java"), + file.path() ); } @Test void shouldGenerateClassName() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of(), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of(), + List.of() ); GeneratedFile file = codeGenerator.generate(query); @@ -70,17 +70,16 @@ void shouldGenerateClassName() { assertTrue(file.content().contains("public final class GetUser")); } - @Test void shouldGenerateMethodName() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of(), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of(), + List.of() ); GeneratedFile file = codeGenerator.generate(query); @@ -91,67 +90,67 @@ void shouldGenerateMethodName() { @Test void shouldGenerateSingleParameter() { GeneratedFile file = codeGenerator.generate( - query( - "GetUser", - QueryType.ONE, - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ) + query( + "GetUser", + QueryType.ONE, + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) ) + ) ); assertTrue( - file.content().contains("Long id") + file.content().contains("Long id") ); } @Test void shouldGenerateMultipleParameters() { GeneratedFile file = codeGenerator.generate( - query( - "ListUsersByIdAndName", - QueryType.MANY, - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "name", ColumnType.VARCHAR) - ) + query( + "ListUsersByIdAndName", + QueryType.MANY, + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "name", ColumnType.VARCHAR) ) + ) ); assertTrue( - file.content().contains( - "Long id, String name" - ) + file.content().contains( + "Long id, String name" + ) ); } @Test void shouldGenerateMethodWithoutParameters() { GeneratedFile file = codeGenerator.generate( - query( - "ListUsers", - QueryType.MANY, - List.of() - ) + query( + "ListUsers", + QueryType.MANY, + List.of() + ) ); assertTrue( - file.content().contains( - "public List listUsers()" - ) + file.content().contains( + "public List listUsers()" + ) ); } @Test void shouldGenerateJavaDoc() { GeneratedFile file = codeGenerator.generate( - query( - "GetUser", - QueryType.ONE, - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ) + query( + "GetUser", + QueryType.ONE, + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) ) + ) ); String source = file.content(); @@ -164,50 +163,47 @@ void shouldGenerateJavaDoc() { @Test void shouldGeneratePackageDeclaration() { GeneratedFile file = codeGenerator.generate( - query( - "GetUser", - QueryType.ONE, - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ) + query( + "GetUser", + QueryType.ONE, + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) ) + ) ); assertTrue( - file.content().startsWith("package generated;") + file.content().startsWith("package generated;") ); } @Test - void shouldGenerateConfiguredPackageDeclarationAndPath() - throws IOException { - - CodeGenerator generator = - new JavaCodeGenerator("dev.example.generated"); + void shouldGenerateConfiguredPackageDeclarationAndPath() throws IOException { + CodeGenerator generator = new JavaCodeGenerator("dev.example.generated"); QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ) + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) + ) ); GeneratedFile file = generator.generate(query); assertEquals( - Path.of("dev", "example", "generated", "GetUser.java"), - file.path() + Path.of("dev", "example", "generated", "GetUser.java"), + file.path() ); assertTrue( - file.content().startsWith("package dev.example.generated;") + file.content().startsWith("package dev.example.generated;") ); assertCompiles(file); @@ -216,17 +212,17 @@ void shouldGenerateConfiguredPackageDeclarationAndPath() @Test void shouldGenerateResultRecord() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true), - new QueryColumn("active", ColumnType.BOOLEAN, true) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true), + new QueryColumn("active", ColumnType.BOOLEAN, true) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); @@ -243,39 +239,39 @@ void shouldGenerateResultRecord() { @Test void shouldGenerateSingleResultReturnType() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "public GetUserResult getUser()" - ) + file.content().contains( + "public GetUserResult getUser()" + ) ); } @Test void shouldGenerateListResultReturnType() { QueryModel query = new QueryModel( - "ListUsers", - QueryType.MANY, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of() + "ListUsers", + QueryType.MANY, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); @@ -283,77 +279,77 @@ void shouldGenerateListResultReturnType() { assertTrue(file.content().contains("import java.util.List;")); assertTrue( - file.content().contains( - "public List listUsers()" - ) + file.content().contains( + "public List listUsers()" + ) ); } @Test void shouldGenerateTypedMethodParameters() { QueryModel query = new QueryModel( - "ListUsersByIdAndName", - QueryType.MANY, - "users", - SQL, - List.of(1, 2), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "name", ColumnType.VARCHAR) - ) + "ListUsersByIdAndName", + QueryType.MANY, + "users", + SQL, + List.of(1, 2), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "name", ColumnType.VARCHAR) + ) ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "public List listUsersByIdAndName(Long id, String name)" - ) + file.content().contains( + "public List listUsersByIdAndName(Long id, String name)" + ) ); } @Test void shouldGenerateSingleResultWithTypedParameter() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT) - ) + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT) + ) ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "public GetUserResult getUser(Long id)" - ) + file.content().contains( + "public GetUserResult getUser(Long id)" + ) ); } @Test void shouldGenerateListImportForSingleResultWithoutParameters() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); @@ -367,25 +363,26 @@ void shouldGenerateListImportForSingleResultWithoutParameters() { @Test void shouldGenerateParameterNamesFromQueryParameters() { QueryModel query = query( - "GetUser", - QueryType.ONE, - List.of( - new QueryParameter(1, "userId", ColumnType.BIGINT), - new QueryParameter(2, "enabled", ColumnType.BOOLEAN) - ) + "GetUser", + QueryType.ONE, + List.of( + new QueryParameter(1, "userId", ColumnType.BIGINT), + new QueryParameter(2, "enabled", ColumnType.BOOLEAN) + ) ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "Long userId, Boolean enabled" - ) + file.content().contains( + "Long userId, Boolean enabled" + ) ); } @ParameterizedTest - @CsvSource({ + @CsvSource( + { "INTEGER, Integer", "BIGINT, Long", "SMALLINT, Short", @@ -395,160 +392,161 @@ void shouldGenerateParameterNamesFromQueryParameters() { "DATE, LocalDate", "TIMESTAMP, LocalDateTime", "DECIMAL, BigDecimal" - }) + } + ) void shouldGenerateJavaTypeForQueryParameter( - ColumnType columnType, - String expectedJavaType + ColumnType columnType, + String expectedJavaType ) { GeneratedFile file = codeGenerator.generate( - query( - "GetUser", - QueryType.ONE, - List.of( - new QueryParameter(1, "value", columnType) - ) + query( + "GetUser", + QueryType.ONE, + List.of( + new QueryParameter(1, "value", columnType) ) + ) ); assertTrue( - file.content().contains( - expectedJavaType + " value" - ) + file.content().contains( + expectedJavaType + " value" + ) ); } @Test void shouldGenerateQuerySpecificResultRecord() { QueryModel query = new QueryModel( - "ListUsers", - QueryType.MANY, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of() + "ListUsers", + QueryType.MANY, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "public record ListUsersResult(" - ) + file.content().contains( + "public record ListUsersResult(" + ) ); } @Test void shouldGenerateImportForLocalDate() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn( - "birthDate", - ColumnType.DATE, - true - ) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn( + "birthDate", + ColumnType.DATE, + true + ) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "import java.time.LocalDate;" - ) + file.content().contains( + "import java.time.LocalDate;" + ) ); } @Test void shouldGenerateImportForBigDecimal() { QueryModel query = new QueryModel( - "GetAccount", - QueryType.ONE, - "accounts", - SQL, - List.of(), - List.of( - new QueryColumn( - "balance", - ColumnType.DECIMAL, - false - ) - ), - List.of() + "GetAccount", + QueryType.ONE, + "accounts", + SQL, + List.of(), + List.of( + new QueryColumn( + "balance", + ColumnType.DECIMAL, + false + ) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "import java.math.BigDecimal;" - ) + file.content().contains( + "import java.math.BigDecimal;" + ) ); } @Test void shouldGenerateImportForQueryParameterType() { QueryModel query = new QueryModel( - "FindUser", - QueryType.ONE, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - false - ) - ), - List.of( - new QueryParameter( - 1, - "createdAt", - ColumnType.TIMESTAMP - ) + "FindUser", + QueryType.ONE, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + false ) + ), + List.of( + new QueryParameter( + 1, + "createdAt", + ColumnType.TIMESTAMP + ) + ) ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "import java.time.LocalDateTime;" - ) + file.content().contains( + "import java.time.LocalDateTime;" + ) ); } @Test void shouldGenerateEachImportOnlyOnce() { QueryModel query = new QueryModel( - "FindUsers", - QueryType.MANY, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn( - "createdAt", - ColumnType.TIMESTAMP, - true - ) - ), - List.of( - new QueryParameter( - 1, - "updatedAt", - ColumnType.TIMESTAMP - ) + "FindUsers", + QueryType.MANY, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn( + "createdAt", + ColumnType.TIMESTAMP, + true ) + ), + List.of( + new QueryParameter( + 1, + "updatedAt", + ColumnType.TIMESTAMP + ) + ) ); GeneratedFile file = codeGenerator.generate(query); @@ -556,34 +554,34 @@ void shouldGenerateEachImportOnlyOnce() { String source = file.content(); assertEquals( - 1, - source.lines() - .filter(line -> line.equals("import java.time.LocalDateTime;")) - .count() + 1, + source.lines() + .filter(line -> line.equals("import java.time.LocalDateTime;")) + .count() ); } @Test void shouldGenerateMultipleRequiredImports() { QueryModel query = new QueryModel( - "ListAccounts", - QueryType.MANY, - "accounts", - SQL, - List.of(), - List.of( - new QueryColumn( - "createdAt", - ColumnType.TIMESTAMP, - false - ), - new QueryColumn( - "balance", - ColumnType.DECIMAL, - false - ) + "ListAccounts", + QueryType.MANY, + "accounts", + SQL, + List.of(), + List.of( + new QueryColumn( + "createdAt", + ColumnType.TIMESTAMP, + false ), - List.of() + new QueryColumn( + "balance", + ColumnType.DECIMAL, + false + ) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); @@ -598,25 +596,25 @@ void shouldGenerateMultipleRequiredImports() { @Test void shouldGenerateQueryExecutionMethodBody() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - false - ) - ), - List.of( - new QueryParameter( - 1, - "id", - ColumnType.BIGINT - ) + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + false ) + ), + List.of( + new QueryParameter( + 1, + "id", + ColumnType.BIGINT + ) + ) ); String source = codeGenerator.generate(query).content(); @@ -630,40 +628,40 @@ void shouldGenerateQueryExecutionMethodBody() { @Test void shouldGenerateCompilableJavaSource() throws IOException { QueryModel query = new QueryModel( - "ListUsers", - QueryType.MANY, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - false - ), - new QueryColumn( - "birth_date", - ColumnType.DATE, - true - ), - new QueryColumn( - "created_at", - ColumnType.TIMESTAMP, - true - ), - new QueryColumn( - "balance", - ColumnType.DECIMAL, - true - ) + "ListUsers", + QueryType.MANY, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + false ), - List.of( - new QueryParameter( - 1, - "created_at", - ColumnType.TIMESTAMP - ) + new QueryColumn( + "birth_date", + ColumnType.DATE, + true + ), + new QueryColumn( + "created_at", + ColumnType.TIMESTAMP, + true + ), + new QueryColumn( + "balance", + ColumnType.DECIMAL, + true + ) + ), + List.of( + new QueryParameter( + 1, + "created_at", + ColumnType.TIMESTAMP ) + ) ); GeneratedFile file = codeGenerator.generate(query); @@ -684,21 +682,22 @@ void shouldGenerateCompilableJavaSource() throws IOException { String classpath = System.getProperty("java.class.path"); int result = compiler.run( - null, - null, - null, - "-classpath", - classpath, - "-d", - outputDirectory.toString(), - sourceFile.toString() + null, + null, + null, + "-classpath", + classpath, + "-d", + outputDirectory.toString(), + sourceFile.toString() ); assertEquals(0, result); } @ParameterizedTest - @CsvSource({ + @CsvSource( + { "INTEGER, Integer", "BIGINT, Long", "SMALLINT, Short", @@ -708,187 +707,195 @@ void shouldGenerateCompilableJavaSource() throws IOException { "DATE, LocalDate", "TIMESTAMP, LocalDateTime", "DECIMAL, BigDecimal" - }) - void shouldGenerateJavaTypeForResultColumn( - ColumnType columnType, - String expectedJavaType - ) { + } + ) + void shouldGenerateJavaTypeForResultColumn(ColumnType columnType, String expectedJavaType) { QueryModel query = new QueryModel( - "GetValue", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn( - "value", - columnType, - true - ) - ), - List.of() + "GetValue", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn( + "value", + columnType, + true + ) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - expectedJavaType + " value" - ) + file.content().contains( + expectedJavaType + " value" + ) ); } @Test void shouldGenerateWrapperTypeForNullableColumn() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - true - ) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + true + ) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains("Long id") + file.content().contains("Long id") ); } @Test void shouldGenerateWrapperTypeForNonNullableColumn() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - false - ) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + false + ) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains("Long id") + file.content().contains("Long id") ); } @Test void shouldGenerateUniqueParameterNamesForDuplicateColumns() { QueryModel query = new QueryModel( - "FindUsers", - QueryType.MANY, - "users", - SQL, - List.of(1, 2), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "id", ColumnType.BIGINT) - ) + "FindUsers", + QueryType.MANY, + "users", + SQL, + List.of(1, 2), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "id", ColumnType.BIGINT) + ) ); GeneratedFile file = codeGenerator.generate(query); assertTrue( - file.content().contains( - "public List findUsers(Long id1, Long id2)" - ) + file.content().contains( + "public List findUsers(Long id1, Long id2)" + ) ); } @Test void shouldGenerateRowMapperForOneQuery() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true), - new QueryColumn("birth_date", ColumnType.DATE, true), - new QueryColumn("created_at", ColumnType.TIMESTAMP, true), - new QueryColumn("balance", ColumnType.DECIMAL, true) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true), + new QueryColumn("birth_date", ColumnType.DATE, true), + new QueryColumn("created_at", ColumnType.TIMESTAMP, true), + new QueryColumn("balance", ColumnType.DECIMAL, true) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); String source = file.content(); - assertTrue(source.contains( + assertTrue( + source.contains( "import dev.sqlcj.runtime.RowMapper;" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "private static final RowMapper ROW_MAPPER" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"id\", Long.class)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"name\", String.class)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"birth_date\", LocalDate.class)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"created_at\", LocalDateTime.class)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"balance\", BigDecimal.class)" - )); + ) + ); } @Test void shouldPreserveResultColumnOrder() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("name", ColumnType.VARCHAR, true), - new QueryColumn("id", ColumnType.BIGINT, false) - ), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("name", ColumnType.VARCHAR, true), + new QueryColumn("id", ColumnType.BIGINT, false) + ), + List.of() ); String source = codeGenerator.generate(query).content(); - int nameIndex = source.indexOf( - "resultSet.getObject(\"name\", String.class)" - ); + int nameIndex = source.indexOf("resultSet.getObject(\"name\", String.class)"); - int idIndex = source.indexOf( - "resultSet.getObject(\"id\", Long.class)" - ); + int idIndex = source.indexOf("resultSet.getObject(\"id\", Long.class)"); assertTrue(nameIndex < idIndex); } @@ -896,284 +903,312 @@ void shouldPreserveResultColumnOrder() { @Test void shouldGenerateRowMapperForManyQuery() { QueryModel query = new QueryModel( - "ListUsers", - QueryType.MANY, - "users", - SQL, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of() + "ListUsers", + QueryType.MANY, + "users", + SQL, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of() ); String source = codeGenerator.generate(query).content(); - assertTrue(source.contains( + assertTrue( + source.contains( "import dev.sqlcj.runtime.RowMapper;" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "private static final RowMapper ROW_MAPPER" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"id\", Long.class)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "resultSet.getObject(\"name\", String.class)" - )); + ) + ); } @Test void shouldGenerateQueryExecutorImport() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of(), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of(), + List.of() ); String source = codeGenerator.generate(query).content(); assertTrue( - source.contains( - "import dev.sqlcj.runtime.QueryExecutor;" - ) + source.contains( + "import dev.sqlcj.runtime.QueryExecutor;" + ) ); } @Test void shouldGenerateQueryExecutorField() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of(), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of(), + List.of() ); String source = codeGenerator.generate(query).content(); assertTrue( - source.contains( - "private final QueryExecutor executor;" - ) + source.contains( + "private final QueryExecutor executor;" + ) ); } @Test void shouldGenerateQueryExecutorConstructor() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - SQL, - List.of(), - List.of(), - List.of() + "GetUser", + QueryType.ONE, + "users", + SQL, + List.of(), + List.of(), + List.of() ); String source = codeGenerator.generate(query).content(); assertTrue( - source.contains( - "public GetUser(QueryExecutor executor)" - ) + source.contains( + "public GetUser(QueryExecutor executor)" + ) ); assertTrue( - source.contains( - "this.executor = executor;" - ) + source.contains( + "this.executor = executor;" + ) ); } @Test void shouldGenerateExecutionForOneQuery() { QueryModel query = new QueryModel( - "GetUser", - QueryType.ONE, - "users", - """ - SELECT id, name - FROM users - WHERE id = ? - """, - List.of(1), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - false - ), - new QueryColumn( - "name", - ColumnType.VARCHAR, - true - ) + "GetUser", + QueryType.ONE, + "users", + """ + SELECT id, name + FROM users + WHERE id = ? + """, + List.of(1), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + false ), - List.of( - new QueryParameter( - 1, - "id", - ColumnType.BIGINT - ) + new QueryColumn( + "name", + ColumnType.VARCHAR, + true ) + ), + List.of( + new QueryParameter( + 1, + "id", + ColumnType.BIGINT + ) + ) ); String source = codeGenerator.generate(query).content(); - assertTrue(source.contains(""" + assertTrue( + source.contains(""" return executor.query( - """)); + """) + ); - assertTrue(source.contains(""" + assertTrue( + source.contains(""" WHERE id = ? - """)); + """) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "List.of(id)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "ROW_MAPPER" - )); + ) + ); assertFalse( - source.contains("UnsupportedOperationException") + source.contains("UnsupportedOperationException") ); - assertTrue(source.contains(""" + assertTrue( + source.contains(""" return executor.query( - """)); + """) + ); - assertFalse(source.contains( + assertFalse( + source.contains( "return executor.queryMany(" - )); + ) + ); } @Test void shouldGenerateQueryManyExecutionForManyQuery() { QueryModel query = new QueryModel( - "ListUsers", - QueryType.MANY, - "users", - SQL, - List.of(1), - List.of( - new QueryColumn( - "id", - ColumnType.BIGINT, - false - ), - new QueryColumn( - "name", - ColumnType.VARCHAR, - true - ) + "ListUsers", + QueryType.MANY, + "users", + SQL, + List.of(1), + List.of( + new QueryColumn( + "id", + ColumnType.BIGINT, + false ), - List.of( - new QueryParameter( - 1, - "active", - ColumnType.BOOLEAN - ) + new QueryColumn( + "name", + ColumnType.VARCHAR, + true + ) + ), + List.of( + new QueryParameter( + 1, + "active", + ColumnType.BOOLEAN ) + ) ); String source = codeGenerator.generate(query).content(); - assertTrue(source.contains(""" + assertTrue( + source.contains(""" return executor.queryMany( - """)); + """) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "List.of(active)" - )); + ) + ); - assertTrue(source.contains( + assertTrue( + source.contains( "ROW_MAPPER" - )); + ) + ); - assertFalse(source.contains( + assertFalse( + source.contains( "return executor.query(" - )); + ) + ); } @Test void shouldPreserveParameterOrderWhenGeneratingExecution() { QueryModel query = new QueryModel( - "FindUser", - QueryType.ONE, - "users", - """ - SELECT id, name - FROM users - WHERE active = ? - AND id = ? - AND name = ? - """, - List.of(1, 2, 3), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of( - new QueryParameter(1, "active", ColumnType.BOOLEAN), - new QueryParameter(2, "id", ColumnType.BIGINT), - new QueryParameter(3, "name", ColumnType.VARCHAR) - ) + "FindUser", + QueryType.ONE, + "users", + """ + SELECT id, name + FROM users + WHERE active = ? + AND id = ? + AND name = ? + """, + List.of(1, 2, 3), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of( + new QueryParameter(1, "active", ColumnType.BOOLEAN), + new QueryParameter(2, "id", ColumnType.BIGINT), + new QueryParameter(3, "name", ColumnType.VARCHAR) + ) ); String source = codeGenerator.generate(query).content(); assertTrue( - source.contains( - "List.of(active, id, name)" - ) + source.contains( + "List.of(active, id, name)" + ) ); } @Test - void shouldGenerateLogicalParametersWithTextualBindingOrder() - throws IOException { - + void shouldGenerateLogicalParametersWithTextualBindingOrder() throws IOException { QueryModel query = new QueryModel( - "FindUser", - QueryType.ONE, - "users", - """ - SELECT id, name - FROM users - WHERE active = ? - AND id = ? - """, - List.of(2, 1), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of( - new QueryParameter(1, "id", ColumnType.BIGINT), - new QueryParameter(2, "active", ColumnType.BOOLEAN) - ) + "FindUser", + QueryType.ONE, + "users", + """ + SELECT id, name + FROM users + WHERE active = ? + AND id = ? + """, + List.of(2, 1), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of( + new QueryParameter(1, "id", ColumnType.BIGINT), + new QueryParameter(2, "active", ColumnType.BOOLEAN) + ) ); GeneratedFile file = codeGenerator.generate(query); String source = file.content(); - assertTrue(source.contains( + assertTrue( + source.contains( "public FindUserResult findUser(Long id, Boolean active)" - )); + ) + ); assertTrue(source.contains("WHERE active = ?")); assertTrue(source.contains("AND id = ?")); @@ -1183,32 +1218,32 @@ void shouldGenerateLogicalParametersWithTextualBindingOrder() } @Test - void shouldGenerateEmptyArgumentListForQueryWithoutParameters() - throws IOException { - + void shouldGenerateEmptyArgumentListForQueryWithoutParameters() throws IOException { QueryModel query = new QueryModel( - "GetFirstUser", - QueryType.ONE, - "users", - """ - SELECT id, name - FROM users - """, - List.of(), - List.of( - new QueryColumn("id", ColumnType.BIGINT, false), - new QueryColumn("name", ColumnType.VARCHAR, true) - ), - List.of() + "GetFirstUser", + QueryType.ONE, + "users", + """ + SELECT id, name + FROM users + """, + List.of(), + List.of( + new QueryColumn("id", ColumnType.BIGINT, false), + new QueryColumn("name", ColumnType.VARCHAR, true) + ), + List.of() ); GeneratedFile file = codeGenerator.generate(query); String source = file.content(); - assertTrue(source.contains( + assertTrue( + source.contains( "public GetFirstUserResult getFirstUser()" - )); + ) + ); assertTrue(source.contains("import java.util.List;")); assertTrue(source.contains("List.of()")); @@ -1234,34 +1269,30 @@ private void assertCompiles(GeneratedFile file) throws IOException { assertNotNull(compiler); int result = compiler.run( - null, - null, - null, - "-classpath", - System.getProperty("java.class.path"), - "-d", - outputDirectory.toString(), - sourceFile.toString() + null, + null, + null, + "-classpath", + System.getProperty("java.class.path"), + "-d", + outputDirectory.toString(), + sourceFile.toString() ); assertEquals(0, result); } - private QueryModel query( - String name, - QueryType type, - List parameters - ) { + private QueryModel query(String name, QueryType type, List parameters) { return new QueryModel( - name, - type, - "users", - SQL, - parameters.stream() - .map(QueryParameter::index) - .toList(), - List.of(), - parameters + name, + type, + "users", + SQL, + parameters.stream() + .map(QueryParameter::index) + .toList(), + List.of(), + parameters ); } } diff --git a/src/test/java/dev/sqlcj/io/GeneratedFileWriterTest.java b/src/test/java/dev/sqlcj/io/GeneratedFileWriterTest.java index 8feeb6e..c67a804 100644 --- a/src/test/java/dev/sqlcj/io/GeneratedFileWriterTest.java +++ b/src/test/java/dev/sqlcj/io/GeneratedFileWriterTest.java @@ -23,19 +23,18 @@ void shouldWriteGeneratedFileToOutputDirectory() throws IOException { Path outputDirectory = tempDir.resolve("generated"); GeneratedFile file = new GeneratedFile( - Path.of("GetUser.java"), - "public final class GetUser {}" + Path.of("GetUser.java"), + "public final class GetUser {}" ); writer.write(file, outputDirectory); - Path outputFile = - outputDirectory.resolve("GetUser.java"); + Path outputFile = outputDirectory.resolve("GetUser.java"); assertTrue(Files.exists(outputFile)); assertEquals( - "public final class GetUser {}", - Files.readString(outputFile) + "public final class GetUser {}", + Files.readString(outputFile) ); } @@ -44,19 +43,18 @@ void shouldCreateParentDirectories() throws IOException { Path outputDirectory = tempDir.resolve("generated"); GeneratedFile file = new GeneratedFile( - Path.of("nested", "GetUser.java"), - "public final class GetUser {}" + Path.of("nested", "GetUser.java"), + "public final class GetUser {}" ); writer.write(file, outputDirectory); - Path outputFile = - outputDirectory.resolve("nested").resolve("GetUser.java"); + Path outputFile = outputDirectory.resolve("nested").resolve("GetUser.java"); assertTrue(Files.exists(outputFile)); assertEquals( - "public final class GetUser {}", - Files.readString(outputFile) + "public final class GetUser {}", + Files.readString(outputFile) ); } } diff --git a/src/test/java/dev/sqlcj/parser/DefaultQueryParserTest.java b/src/test/java/dev/sqlcj/parser/DefaultQueryParserTest.java index e5b4a5e..53e95c0 100644 --- a/src/test/java/dev/sqlcj/parser/DefaultQueryParserTest.java +++ b/src/test/java/dev/sqlcj/parser/DefaultQueryParserTest.java @@ -15,11 +15,11 @@ class DefaultQueryParserTest { @Test void parsesSingleQuery() { String source = """ - -- name: GetUser :one - SELECT * - FROM users - WHERE id = $1; - """; + -- name: GetUser :one + SELECT * + FROM users + WHERE id = $1; + """; List queries = parser.parse(source); @@ -30,24 +30,24 @@ void parsesSingleQuery() { assertEquals("GetUser", query.name()); assertEquals(QueryType.ONE, query.type()); assertEquals(""" - SELECT * - FROM users - WHERE id = $1; - """.trim(), query.sql()); + SELECT * + FROM users + WHERE id = $1; + """.trim(), query.sql()); } @Test void parsesMultipleQueries() { String source = """ - -- name: GetUser :one - SELECT * - FROM users - WHERE id = $1; - - -- name: ListUsers :many - SELECT * - FROM users; - """; + -- name: GetUser :one + SELECT * + FROM users + WHERE id = $1; + + -- name: ListUsers :many + SELECT * + FROM users; + """; List queries = parser.parse(source); @@ -65,10 +65,10 @@ void parsesMultipleQueries() { @Test void parsesExecQueryType() { String source = """ - -- name: DeleteUser :exec - DELETE FROM users - WHERE id = $1; - """; + -- name: DeleteUser :exec + DELETE FROM users + WHERE id = $1; + """; List queries = parser.parse(source); @@ -79,69 +79,69 @@ void parsesExecQueryType() { @Test void rejectsInvalidQueryType() { String source = """ - -- name: GetUser :invalid - SELECT * - FROM users; - """; + -- name: GetUser :invalid + SELECT * + FROM users; + """; IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> parser.parse(source) + IllegalArgumentException.class, + () -> parser.parse(source) ); assertEquals( - "Unknown query type: :invalid", - exception.getMessage() + "Unknown query type: :invalid", + exception.getMessage() ); } @Test void rejectsDuplicateQueryNames() { String source = """ - -- name: GetUser :one - SELECT * - FROM users - WHERE id = $1; - - -- name: GetUser :many - SELECT * - FROM users; - """; + -- name: GetUser :one + SELECT * + FROM users + WHERE id = $1; + + -- name: GetUser :many + SELECT * + FROM users; + """; IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> parser.parse(source) + IllegalArgumentException.class, + () -> parser.parse(source) ); assertEquals( - "Duplicate query: GetUser", - exception.getMessage() + "Duplicate query: GetUser", + exception.getMessage() ); } @Test void rejectsQueryWithoutSql() { String source = """ - -- name: GetUser :one - """; + -- name: GetUser :one + """; IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> parser.parse(source) + IllegalArgumentException.class, + () -> parser.parse(source) ); assertEquals( - "Query 'GetUser' has no SQL", - exception.getMessage() + "Query 'GetUser' has no SQL", + exception.getMessage() ); } @Test void returnsEmptyListWhenNoQueriesExist() { String source = """ - SELECT * - FROM users; - """; + SELECT * + FROM users; + """; List queries = parser.parse(source); @@ -151,19 +151,19 @@ void returnsEmptyListWhenNoQueriesExist() { @Test void rejectsInvalidHeader() { String source = """ - -- name: - SELECT * - FROM users; - """; + -- name: + SELECT * + FROM users; + """; IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> parser.parse(source) + IllegalArgumentException.class, + () -> parser.parse(source) ); assertEquals( - "Invalid query header: -- name:", - exception.getMessage() + "Invalid query header: -- name:", + exception.getMessage() ); } @@ -172,10 +172,10 @@ void preservesQueryOrder() { String source = """ -- name: First :one SELECT 1; - + -- name: Second :one SELECT 2; - + -- name: Third :one SELECT 3; """; diff --git a/src/test/java/dev/sqlcj/runtime/JdbcQueryExecutorTest.java b/src/test/java/dev/sqlcj/runtime/JdbcQueryExecutorTest.java index ffa88e7..a6ff181 100644 --- a/src/test/java/dev/sqlcj/runtime/JdbcQueryExecutorTest.java +++ b/src/test/java/dev/sqlcj/runtime/JdbcQueryExecutorTest.java @@ -28,45 +28,47 @@ class JdbcQueryExecutorTest { void setUp() throws SQLException { dataSource = new JdbcDataSource(); dataSource.setURL( - "jdbc:h2:mem:" + UUID.randomUUID() + ";DB_CLOSE_DELAY=-1" + "jdbc:h2:mem:" + UUID.randomUUID() + ";DB_CLOSE_DELAY=-1" ); executor = new JdbcQueryExecutor(dataSource); - try (Connection connection = dataSource.getConnection(); - Statement statement = connection.createStatement()) { + try ( + Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement() + ) { statement.execute(""" - CREATE TABLE users ( - id BIGINT PRIMARY KEY, - name VARCHAR(255), - active BOOLEAN, - birth_date DATE, - created_at TIMESTAMP, - balance DECIMAL(10, 2) - ) - """); + CREATE TABLE users ( + id BIGINT PRIMARY KEY, + name VARCHAR(255), + active BOOLEAN, + birth_date DATE, + created_at TIMESTAMP, + balance DECIMAL(10, 2) + ) + """); statement.execute(""" - INSERT INTO users - (id, name, active, birth_date, created_at, balance) - VALUES - (1, 'Alice', TRUE, '1990-01-15', - '2026-01-01 10:00:00', 100.50), - (2, 'Bob', FALSE, '1985-05-20', - '2026-02-01 11:30:00', 200.75), - (3, 'Charlie', TRUE, '1995-10-10', - '2026-03-01 12:45:00', 300.25) - """); + INSERT INTO users + (id, name, active, birth_date, created_at, balance) + VALUES + (1, 'Alice', TRUE, '1990-01-15', + '2026-01-01 10:00:00', 100.50), + (2, 'Bob', FALSE, '1985-05-20', + '2026-02-01 11:30:00', 200.75), + (3, 'Charlie', TRUE, '1995-10-10', + '2026-03-01 12:45:00', 300.25) + """); } } @Test void shouldBindSingleParameter() { Long result = executor.query( - "SELECT id FROM users WHERE id = ?", - List.of(1L), - resultSet -> resultSet.getLong("id") + "SELECT id FROM users WHERE id = ?", + List.of(1L), + resultSet -> resultSet.getLong("id") ); assertEquals(1L, result); @@ -75,14 +77,14 @@ void shouldBindSingleParameter() { @Test void shouldBindParametersInOrder() { String result = executor.query( - """ + """ SELECT name FROM users WHERE id = ? AND active = ? """, - List.of(2L, false), - resultSet -> resultSet.getString("name") + List.of(2L, false), + resultSet -> resultSet.getString("name") ); assertEquals("Bob", result); @@ -91,19 +93,19 @@ void shouldBindParametersInOrder() { @Test void shouldBindSupportedJavaTypes() { String result = executor.query( - """ + """ SELECT name FROM users WHERE birth_date = ? AND created_at = ? AND balance = ? """, - List.of( - LocalDate.of(1990, 1, 15), - LocalDateTime.of(2026, 1, 1, 10, 0), - new BigDecimal("100.50") - ), - resultSet -> resultSet.getString("name") + List.of( + LocalDate.of(1990, 1, 15), + LocalDateTime.of(2026, 1, 1, 10, 0), + new BigDecimal("100.50") + ), + resultSet -> resultSet.getString("name") ); assertEquals("Alice", result); @@ -112,41 +114,41 @@ void shouldBindSupportedJavaTypes() { @Test void shouldReturnAllRowsForQueryMany() { List results = executor.queryMany( - """ + """ SELECT id, name FROM users WHERE active = ? ORDER BY id """, - List.of(true), - resultSet -> new User( - resultSet.getLong("id"), - resultSet.getString("name") - ) + List.of(true), + resultSet -> new User( + resultSet.getLong("id"), + resultSet.getString("name") + ) ); assertEquals( - List.of( - new User(1L, "Alice"), - new User(3L, "Charlie") - ), - results + List.of( + new User(1L, "Alice"), + new User(3L, "Charlie") + ), + results ); } @Test void shouldReturnEmptyListWhenQueryManyFindsNoRows() { List results = executor.queryMany( - """ + """ SELECT id, name FROM users WHERE id = ? """, - List.of(999L), - resultSet -> new User( - resultSet.getLong("id"), - resultSet.getString("name") - ) + List.of(999L), + resultSet -> new User( + resultSet.getLong("id"), + resultSet.getString("name") + ) ); assertTrue(results.isEmpty()); @@ -155,16 +157,16 @@ void shouldReturnEmptyListWhenQueryManyFindsNoRows() { @Test void shouldReturnNullWhenQueryFindsNoRows() { User result = executor.query( - """ + """ SELECT id, name FROM users WHERE id = ? """, - List.of(999L), - resultSet -> new User( - resultSet.getLong("id"), - resultSet.getString("name") - ) + List.of(999L), + resultSet -> new User( + resultSet.getLong("id"), + resultSet.getString("name") + ) ); assertNull(result); @@ -173,12 +175,12 @@ void shouldReturnNullWhenQueryFindsNoRows() { @Test void shouldWrapSqlException() { QueryExecutionException exception = assertThrows( - QueryExecutionException.class, - () -> executor.query( - "SELECT * FROM missing_table", - List.of(), - resultSet -> resultSet.getLong("id") - ) + QueryExecutionException.class, + () -> executor.query( + "SELECT * FROM missing_table", + List.of(), + resultSet -> resultSet.getLong("id") + ) ); assertEquals("Failed to execute query", exception.getMessage()); @@ -186,8 +188,8 @@ void shouldWrapSqlException() { } private record User( - long id, - String name + long id, + String name ) { } } diff --git a/src/test/java/dev/sqlcj/schema/parser/DefaultSchemaParserTest.java b/src/test/java/dev/sqlcj/schema/parser/DefaultSchemaParserTest.java index 8ec5d0d..3155439 100644 --- a/src/test/java/dev/sqlcj/schema/parser/DefaultSchemaParserTest.java +++ b/src/test/java/dev/sqlcj/schema/parser/DefaultSchemaParserTest.java @@ -21,12 +21,12 @@ class DefaultSchemaParserTest { @Test void shouldParseTable() { String sql = """ - CREATE TABLE users ( - id BIGINT NOT NULL, - name VARCHAR(255), - active BOOLEAN - ); - """; + CREATE TABLE users ( + id BIGINT NOT NULL, + name VARCHAR(255), + active BOOLEAN + ); + """; Schema schema = parser.parse(sql); @@ -53,18 +53,18 @@ name VARCHAR(255), Table table = schema.tables().getFirst(); assertEquals( - new Column("id", ColumnType.BIGINT, false), - table.columns().get(0) + new Column("id", ColumnType.BIGINT, false), + table.columns().get(0) ); assertEquals( - new Column("name", ColumnType.VARCHAR, true), - table.columns().get(1) + new Column("name", ColumnType.VARCHAR, true), + table.columns().get(1) ); assertEquals( - new Column("active", ColumnType.BOOLEAN, true), - table.columns().get(2) + new Column("active", ColumnType.BOOLEAN, true), + table.columns().get(2) ); } @@ -84,17 +84,17 @@ PRIMARY KEY (id), Table table = schema.tables().getFirst(); assertEquals( - List.of( - new Constraint( - ConstraintType.PRIMARY_KEY, - List.of("id") - ), - new Constraint( - ConstraintType.UNIQUE, - List.of("email") - ) + List.of( + new Constraint( + ConstraintType.PRIMARY_KEY, + List.of("id") ), - table.constraints() + new Constraint( + ConstraintType.UNIQUE, + List.of("email") + ) + ), + table.constraints() ); } @@ -122,8 +122,8 @@ CREATE TABLE users ( """; assertThrows( - SchemaParseException.class, - () -> parser.parse(sql) + SchemaParseException.class, + () -> parser.parse(sql) ); } } From 260a1d0da2af7d301fdde9b4df1c7d287bc8adc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20=C3=87engel?= Date: Thu, 17 Sep 2026 00:14:18 +0300 Subject: [PATCH 2/2] ci: check Java formatting on pull requests --- .github/workflows/formatting.yml | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/formatting.yml diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml new file mode 100644 index 0000000..4c72b35 --- /dev/null +++ b/.github/workflows/formatting.yml @@ -0,0 +1,35 @@ +name: Formatting + +on: + pull_request: + branches: + - master + +permissions: + contents: read + +concurrency: + group: formatting-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + spotless: + name: Spotless check + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + with: + persist-credentials: false + + - name: Set up Java 21 + uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 + with: + distribution: temurin + java-version: "21" + cache: maven + cache-dependency-path: pom.xml + + - name: Check formatting + run: mvn --batch-mode --no-transfer-progress spotless:check