From cfafba274f08a3c211537dd5840df285935fc97d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Ho=C3=9F?= Date: Fri, 10 Jun 2022 14:36:43 +0200 Subject: [PATCH] fix #123 allow to specify extra annotations on repositories/methods --- README.md | 3 +- .../metio/yosql/codegen/blocks/Annotations.java | 16 + .../yosql/codegen/blocks/DefaultAnnotations.java | 111 ++- .../yosql/codegen/blocks/DefaultCodeBlocks.java | 10 +- .../metio/yosql/codegen/blocks/DefaultJavadoc.java | 9 +- .../metio/yosql/codegen/blocks/DefaultMethods.java | 6 +- .../yosql/codegen/dao/DefaultCodeGenerator.java | 5 +- .../codegen/dao/DefaultConstructorGenerator.java | 2 +- .../yosql/codegen/dao/DefaultFieldsGenerator.java | 17 +- .../metio/yosql/codegen/dao/DefaultJdbcBlocks.java | 66 +- .../yosql/codegen/dao/DefaultJdbcParameters.java | 3 +- .../yosql/codegen/dao/DefaultMethodsGenerator.java | 3 +- .../codegen/dao/DefaultParameterGenerator.java | 19 +- .../codegen/dao/DefaultRepositoryGenerator.java | 6 +- .../yosql/codegen/dao/DefaultReturnTypes.java | 18 +- .../wtf/metio/yosql/codegen/dao/ReturnTypes.java | 10 +- ...ultFileResolver.java => DefaultFileParser.java} | 33 +- .../codegen/files/DefaultMethodNameConfigurer.java | 28 +- .../codegen/files/DefaultMethodNameValidator.java | 36 +- .../files/DefaultMethodParameterConfigurer.java | 31 +- ...DefaultMethodResultRowConverterConfigurer.java} | 52 +- .../files/DefaultMethodSettingsConfigurer.java | 38 +- .../files/DefaultSqlConfigurationFactory.java | 6 +- .../files/DefaultSqlConfigurationParser.java | 45 +- .../wtf/metio/yosql/codegen/files/FileParser.java | 3 +- .../metio/yosql/codegen/files/FileResolver.java | 23 - ...ava => MethodResultRowConverterConfigurer.java} | 4 +- .../files/ResultRowConverterDeserializer.java | 40 - .../codegen/files/SqlParameterDeserializer.java | 40 - .../yosql/codegen/lifecycle/ValidationErrors.java | 5 - .../main/resources/validation-errors_de.properties | 3 +- .../main/resources/validation-errors_en.properties | 3 +- .../codegen/blocks/DefaultAnnotationsTest.java | 164 +++++ .../files/DefaultMethodApiConfigurerTest.java | 4 +- .../files/DefaultMethodNameConfigurerTest.java | 58 +- .../files/DefaultMethodNameValidatorTest.java | 24 +- .../DefaultMethodParameterConfigurerTest.java | 4 +- .../files/DefaultMethodSettingsConfigurerTest.java | 52 +- .../files/DefaultSqlConfigurationFactoryTest.java | 32 +- .../files/DefaultSqlConfigurationParserTest.java | 171 +++-- .../yosql/codegen/files/FilesObjectMother.java | 6 +- .../yosql/example/common/CustomAnnotation.java} | 9 +- .../example/common/CustomAnnotationWithData.java} | 26 +- .../src/main/yosql/company/findCompanies.sql | 8 +- .../src/main/yosql/company/queryAllCompanies.sql | 27 + .../build.gradle.kts | 17 + .../yosql-examples-maven-jdbc-java8/pom.xml | 31 + .../yosql/internals/javapoet/TypicalTypes.java | 21 +- .../wtf/metio/yosql/internals/jdk/Buckets.java | 20 +- yosql-models/yosql-models-configuration/pom.xml | 10 + .../yosql/models/configuration/Annotation.java | 90 +++ .../models/configuration/AnnotationMember.java | 55 ++ ...ationApis.java => GeneratedAnnotationApis.java} | 9 +- ...embers.java => GeneratedAnnotationMembers.java} | 2 +- .../yosql/models/configuration/LoggingApis.java | 5 - .../models/configuration/ParameterConverter.java | 8 + .../models/configuration/ResultRowConverter.java | 49 +- .../yosql/models/configuration/SqlParameter.java | 74 +- .../{SqlType.java => SqlStatementType.java} | 7 +- .../yosql/models/configuration/AnnotationTest.java | 79 ++ .../models/configuration/SqlParameterTest.java | 174 +++++ ...sTest.java => GeneratedAnnotationApisTest.java} | 10 +- .../models/constants/api/LoggingApisTest.java | 2 +- ...st.java => GeneratedAnnotationMembersTest.java} | 8 +- ...{SqlTypeTest.java => SqlStatementTypeTest.java} | 10 +- .../generator/AbstractFieldsBasedGenerator.java | 5 + .../wtf/metio/yosql/model/generator/Generator.java | 5 + .../yosql/model/generator/GradleGenerator.java | 86 +-- .../yosql/model/generator/MavenGenerator.java | 53 +- .../yosql/models/immutables/SqlStatement.java | 37 +- .../models/immutables/SqlConfigurationTest.java | 808 ++++++++++++++++++++- .../yosql/models/meta/ConfigurationGroup.java | 16 + .../meta/data/AbstractConfigurationGroup.java | 87 +++ .../yosql/models/meta/data/AllConfigurations.java | 4 + .../metio/yosql/models/meta/data/Annotations.java | 197 ++++- .../metio/yosql/models/meta/data/Converter.java | 152 ++-- .../metio/yosql/models/meta/data/Repositories.java | 10 + .../java/wtf/metio/yosql/models/meta/data/Sql.java | 88 +-- .../wtf/metio/yosql/models/meta/data/Tags.java | 5 + .../testing/configs/AnnotationsConfigurations.java | 4 +- .../yosql/testing/configs/SqlConfigurations.java | 4 +- yosql-tooling/pom.xml | 5 +- .../tooling/dagger/files/DefaultFilesModule.java | 32 +- .../metio/yosql/tooling/gradle/YoSqlPlugin.java | 12 +- 84 files changed, 2672 insertions(+), 898 deletions(-) rename yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/{DefaultFileResolver.java => DefaultFileParser.java} (69%) rename yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/{DefaultMethodConverterConfigurer.java => DefaultMethodResultRowConverterConfigurer.java} (60%) delete mode 100644 yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileResolver.java rename yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/{MethodConverterConfigurer.java => MethodResultRowConverterConfigurer.java} (85%) delete mode 100644 yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/ResultRowConverterDeserializer.java delete mode 100644 yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/SqlParameterDeserializer.java copy yosql-examples/yosql-examples-common/src/main/{yosql/company/queryAllCompanies.sql => java/wtf/metio/yosql/example/common/CustomAnnotation.java} (82%) copy yosql-examples/yosql-examples-common/src/main/{yosql/company/findCompanies.sql => java/wtf/metio/yosql/example/common/CustomAnnotationWithData.java} (57%) create mode 100644 yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/Annotation.java create mode 100644 yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMember.java rename yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/{AnnotationApis.java => GeneratedAnnotationApis.java} (79%) rename yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/{AnnotationMembers.java => GeneratedAnnotationMembers.java} (95%) rename yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/{SqlType.java => SqlStatementType.java} (89%) create mode 100644 yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/AnnotationTest.java create mode 100644 yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/SqlParameterTest.java rename yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/{AnnotationApisTest.java => GeneratedAnnotationApisTest.java} (64%) rename yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/{AnnotationMembersTest.java => GeneratedAnnotationMembersTest.java} (71%) rename yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/{SqlTypeTest.java => SqlStatementTypeTest.java} (71%) create mode 100644 yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AbstractConfigurationGroup.java diff --git a/README.md b/README.md index d2c5fc14..b92fbad0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # YoSQL [![Chat](https://img.shields.io/badge/matrix-%23yosql:matrix.org-brightgreen.svg?style=social&label=Matrix)](https://matrix.to/#yosql:matrix.org) [![Mailing List](https://img.shields.io/badge/email-yosql%40metio.groups.io%20-brightgreen.svg?style=social&label=Mail)](https://metio.groups.io/g/yosql/topics) -Take a look at the [project website](https://yosql.projects.metio.wtf/) to read the documentation. The *yosql-examples* -folder contains multiple examples that uses all available features of YoSQL. +Take a look at the [project website](https://yosql.projects.metio.wtf/) to read the documentation. ## License diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/Annotations.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/Annotations.java index 8d3656d9..9b647b85 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/Annotations.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/Annotations.java @@ -8,6 +8,7 @@ package wtf.metio.yosql.codegen.blocks; import com.squareup.javapoet.AnnotationSpec; +import wtf.metio.yosql.models.immutables.SqlConfiguration; /** * Generates annotations for classes, fields, and methods. @@ -29,4 +30,19 @@ public interface Annotations { */ Iterable generatedMethod(); + /** + * @return User specified annotations for generated repositories and their interfaces. + */ + Iterable generatedRepository(); + + /** + * @return User specified annotations for generated methods. + */ + Iterable generatedMethod(SqlConfiguration configuration); + + /** + * @return User specified annotations for generated constructors. + */ + Iterable generatedConstructor(); + } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotations.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotations.java index 976207cf..bf85fd4c 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotations.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotations.java @@ -8,9 +8,15 @@ package wtf.metio.yosql.codegen.blocks; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; -import wtf.metio.yosql.models.configuration.AnnotationApis; -import wtf.metio.yosql.models.configuration.AnnotationMembers; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.TypeName; +import de.xn__ho_hia.javapoet.TypeGuesser; +import wtf.metio.yosql.models.configuration.Annotation; +import wtf.metio.yosql.models.configuration.AnnotationMember; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationApis; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationMembers; import wtf.metio.yosql.models.immutables.AnnotationsConfiguration; +import wtf.metio.yosql.models.immutables.SqlConfiguration; import java.time.ZonedDateTime; import java.util.Collections; @@ -18,63 +24,63 @@ import java.util.EnumSet; public final class DefaultAnnotations implements Annotations { - private static final EnumSet OPTIONS_WITH_VALUE = EnumSet.of( - AnnotationMembers.ALL, - AnnotationMembers.VALUE, - AnnotationMembers.WITHOUT_DATE); + private static final EnumSet OPTIONS_WITH_VALUE = EnumSet.of( + GeneratedAnnotationMembers.ALL, + GeneratedAnnotationMembers.VALUE, + GeneratedAnnotationMembers.WITHOUT_DATE); - private static final EnumSet OPTIONS_WITH_DATE = EnumSet.of( - AnnotationMembers.ALL, - AnnotationMembers.DATE); + private static final EnumSet OPTIONS_WITH_DATE = EnumSet.of( + GeneratedAnnotationMembers.ALL, + GeneratedAnnotationMembers.DATE); - private static final EnumSet OPTIONS_WITH_COMMENT = EnumSet.of( - AnnotationMembers.ALL, - AnnotationMembers.COMMENT, - AnnotationMembers.WITHOUT_DATE); + private static final EnumSet OPTIONS_WITH_COMMENT = EnumSet.of( + GeneratedAnnotationMembers.ALL, + GeneratedAnnotationMembers.COMMENT, + GeneratedAnnotationMembers.WITHOUT_DATE); - private final AnnotationsConfiguration configuration; + private final AnnotationsConfiguration annotations; - public DefaultAnnotations(final AnnotationsConfiguration configuration) { - this.configuration = configuration; + public DefaultAnnotations(final AnnotationsConfiguration annotations) { + this.annotations = annotations; } @Override public Iterable generatedClass() { return getAnnotationSpecs( - configuration.annotateClasses(), - configuration.annotationApi(), - configuration.classMembers(), - configuration.classComment()); + annotations.annotateClasses(), + annotations.annotationApi(), + annotations.classMembers(), + annotations.classComment()); } @Override public Iterable generatedField() { return getAnnotationSpecs( - configuration.annotateFields(), - configuration.annotationApi(), - configuration.fieldMembers(), - configuration.fieldComment()); + annotations.annotateFields(), + annotations.annotationApi(), + annotations.fieldMembers(), + annotations.fieldComment()); } @Override public Iterable generatedMethod() { return getAnnotationSpecs( - configuration.annotateMethods(), - configuration.annotationApi(), - configuration.methodMembers(), - configuration.methodComment()); + annotations.annotateMethods(), + annotations.annotationApi(), + annotations.methodMembers(), + annotations.methodComment()); } private Iterable getAnnotationSpecs( final boolean shouldAnnotate, - final AnnotationApis annotationApi, - final AnnotationMembers memberOption, + final GeneratedAnnotationApis annotationApi, + final GeneratedAnnotationMembers memberOption, final String comment) { if (shouldAnnotate) { final var annotationClass = ClassName.bestGuess(annotationApi.annotationClass); final var builder = AnnotationSpec.builder(annotationClass); if (OPTIONS_WITH_VALUE.contains(memberOption)) { - builder.addMember("value", "$S", configuration.generatorName()); + builder.addMember("value", "$S", annotations.generatorName()); } if (OPTIONS_WITH_DATE.contains(memberOption)) { builder.addMember("date", "$S", ZonedDateTime.now().toString()); @@ -87,4 +93,47 @@ public final class DefaultAnnotations implements Annotations { return Collections.emptyList(); } + @Override + public Iterable generatedRepository() { + return annotations.repositoryAnnotations().stream() + .map(DefaultAnnotations::asAnnotationSpec) + .toList(); + } + + @Override + public Iterable generatedMethod(final SqlConfiguration configuration) { + return Annotation.mergeAnnotations(configuration.annotations(), annotations.methodAnnotations()).stream() + .map(DefaultAnnotations::asAnnotationSpec) + .toList(); + } + + @Override + public Iterable generatedConstructor() { + return annotations.constructorAnnotations().stream() + .map(DefaultAnnotations::asAnnotationSpec) + .toList(); + } + + // visible for testing + static AnnotationSpec asAnnotationSpec(final Annotation annotation) { + // TODO: catch exception thrown by bestGuess and return Optional + use ExecutionErrors? + final var type = ClassName.bestGuess(annotation.type()); + final var builder = AnnotationSpec.builder(type); + annotation.members().forEach(member -> builder.addMember(member.key(), asAnnotationMemberSpec(member))); + return builder.build(); + } + + private static CodeBlock asAnnotationMemberSpec(final AnnotationMember member) { + final var builder = CodeBlock.builder(); + final var type = TypeGuesser.guessTypeName(member.type()); + if (TypeName.CHAR.equals(type)) { + builder.add("'$L'", member.value()); + } else if (type.isPrimitive()) { + builder.add("$L", member.value()); + } else { + builder.add("$S", member.value()); + } + return builder.build(); + } + } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultCodeBlocks.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultCodeBlocks.java index 50a47f79..ba433b75 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultCodeBlocks.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultCodeBlocks.java @@ -7,12 +7,9 @@ package wtf.metio.yosql.codegen.blocks; -import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import wtf.metio.yosql.models.configuration.ResultRowConverter; -import java.util.Objects; - public final class DefaultCodeBlocks implements CodeBlocks { @Override @@ -46,11 +43,10 @@ public final class DefaultCodeBlocks implements CodeBlocks { @Override public CodeBlock initializeConverter(final ResultRowConverter converter) { - final var type = converter.converterType(); - final ClassName converterClass = ClassName.bestGuess((Objects.isNull(type) || type.isBlank()) ? "java.lang.Object" : - type); return CodeBlock.builder() - .addStatement("this.$N = new $T()", converter.alias(), converterClass) + .addStatement("this.$N = new $T()", + converter.alias().orElseThrow(), // TODO: throw business exception + converter.converterTypeName().orElseThrow()) // TODO: throw business exception .build(); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultJavadoc.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultJavadoc.java index d42f9fab..25892b1e 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultJavadoc.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultJavadoc.java @@ -13,10 +13,11 @@ import de.xn__ho_hia.javapoet.TypeGuesser; import wtf.metio.yosql.internals.jdk.Strings; import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.immutables.FilesConfiguration; +import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.models.immutables.SqlStatement; import java.util.List; -import java.util.Objects; +import java.util.Optional; import static java.util.function.Predicate.not; @@ -93,10 +94,10 @@ public final class DefaultJavadoc implements Javadoc { builder.add(messages.getMessage(Javadocs.DISABLE_WITH), configuration); statements.stream() .map(SqlStatement::getConfiguration) - .flatMap(config -> config.resultRowConverter().stream()) - .filter(Objects::nonNull) + .map(SqlConfiguration::resultRowConverter) + .flatMap(Optional::stream) .map(ResultRowConverter::resultType) - .filter(Objects::nonNull) + .flatMap(Optional::stream) .filter(type -> !type.startsWith("java")) .map(type -> type.substring(0, type.contains("<") ? type.indexOf("<") : type.length())) .distinct() diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultMethods.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultMethods.java index fe756b82..dc952dce 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultMethods.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/blocks/DefaultMethods.java @@ -9,6 +9,7 @@ package wtf.metio.yosql.codegen.blocks; import com.squareup.javapoet.MethodSpec; import wtf.metio.yosql.models.immutables.JavaConfiguration; +import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.models.immutables.SqlStatement; import javax.lang.model.element.Modifier; @@ -47,6 +48,7 @@ public final class DefaultMethods implements Methods { return MethodSpec.methodBuilder(name) .addModifiers(modifiers) .addAnnotations(annotations.generatedMethod()) + .addAnnotations(annotations.generatedMethod(SqlConfiguration.fromStatements(statements))) .addJavadoc(javadoc.methodJavadoc(statements, configuration)); } @@ -58,6 +60,7 @@ public final class DefaultMethods implements Methods { return MethodSpec.methodBuilder(name) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addAnnotations(annotations.generatedMethod()) + .addAnnotations(annotations.generatedMethod(SqlConfiguration.fromStatements(statements))) .addJavadoc(javadoc.methodJavadoc(statements, configuration)); } @@ -76,7 +79,8 @@ public final class DefaultMethods implements Methods { public MethodSpec.Builder constructor() { return MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) - .addAnnotations(annotations.generatedMethod()); + .addAnnotations(annotations.generatedMethod()) + .addAnnotations(annotations.generatedConstructor()); } } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultCodeGenerator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultCodeGenerator.java index ee160855..753e4ec8 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultCodeGenerator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultCodeGenerator.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Map; import java.util.function.BiFunction; import java.util.stream.Collector; +import java.util.stream.Collectors; import java.util.stream.Stream; public final class DefaultCodeGenerator implements CodeGenerator { @@ -46,11 +47,11 @@ public final class DefaultCodeGenerator implements CodeGenerator { } private Stream generateRepositoryClasses(final List statements) { - return generate(statements, SqlStatement.groupByRepositoryClass(), repositoryGenerator::generateRepositoryClass); + return generate(statements, Collectors.groupingBy(SqlStatement::getRepositoryClass), repositoryGenerator::generateRepositoryClass); } private Stream generateRepositoryInterfaces(final List statements) { - return generate(statements, SqlStatement.groupByRepositoryInterface(), repositoryGenerator::generateRepositoryInterface); + return generate(statements, Collectors.groupingBy(SqlStatement::getRepositoryInterface), repositoryGenerator::generateRepositoryInterface); } private static Stream generate( diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultConstructorGenerator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultConstructorGenerator.java index 10781b75..09c03bf3 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultConstructorGenerator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultConstructorGenerator.java @@ -54,7 +54,7 @@ public final class DefaultConstructorGenerator implements ConstructorGenerator { final var constructor = methods.constructor().addParameter(jdbcParameters.dataSource()); resultConverters(statements).forEach(converter -> { constructor.addParameter(jdbcParameters.converter(converter)); - builder.add(blocks.initializeFieldToSelf(converter.alias())); + builder.add(blocks.initializeFieldToSelf(converter.alias().orElseThrow())); // TODO: throw business exception }); return constructor .addCode(blocks.initializeFieldToSelf(names.dataSource())) diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultFieldsGenerator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultFieldsGenerator.java index 4aa156db..06b0b975 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultFieldsGenerator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultFieldsGenerator.java @@ -9,7 +9,6 @@ package wtf.metio.yosql.codegen.dao; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; -import de.xn__ho_hia.javapoet.TypeGuesser; import wtf.metio.yosql.codegen.blocks.Fields; import wtf.metio.yosql.codegen.blocks.Javadoc; import wtf.metio.yosql.codegen.files.SqlStatementParser; @@ -76,13 +75,15 @@ public final class DefaultFieldsGenerator implements FieldsGenerator { final SqlConfiguration config) { builder.addStatement("$N.put($S, $L)", constantSqlStatementParameterIndexFieldName(config), - parameter.name(), + parameter.name().orElseThrow(), // TODO: throw business exception indexArray(parameter)); } private static String indexArray(final SqlParameter param) { - return IntStream.of(param.indices()) - .boxed() + return param.indices() + .stream() + .map(IntStream::of) + .flatMap(IntStream::boxed) .map(Object::toString) .collect(Collectors.joining(", ", "new int[] { ", " }")); } @@ -114,10 +115,6 @@ public final class DefaultFieldsGenerator implements FieldsGenerator { } private Optional loggerField(final SqlStatement sqlStatement) { -// return sqlStatement.getRepository() -// .map(ClassName::bestGuess) -// .flatMap(logging::logger); - return logging.logger(ClassName.bestGuess(sqlStatement.getRepositoryClass())); } @@ -154,8 +151,8 @@ public final class DefaultFieldsGenerator implements FieldsGenerator { private FieldSpec asConverterField(final ResultRowConverter converter) { return fields.field( - TypeGuesser.guessTypeName(converter.converterType()), - converter.alias()); + converter.converterTypeName().orElseThrow(), // TODO: throw business exception + converter.alias().orElseThrow()); // TODO: throw business exception } @Override diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcBlocks.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcBlocks.java index 0469f9a1..100e74e1 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcBlocks.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcBlocks.java @@ -10,7 +10,6 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; -import de.xn__ho_hia.javapoet.TypeGuesser; import wtf.metio.yosql.codegen.blocks.*; import wtf.metio.yosql.codegen.logging.LoggingGenerator; import wtf.metio.yosql.internals.javapoet.TypicalTypes; @@ -25,7 +24,6 @@ import wtf.metio.yosql.models.immutables.SqlStatement; import java.sql.*; import java.util.*; import java.util.function.Function; -import java.util.stream.Stream; import java.util.stream.StreamSupport; import static wtf.metio.yosql.codegen.blocks.CodeBlocks.code; @@ -162,7 +160,7 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { code("int $N = 0; $N < $N.length; $N++", names.batch(), names.batch(), - config.parameters().get(0).name(), + config.parameters().get(0).name().orElseThrow(), // TODO: throw business exception names.batch()), CodeBlock.builder() .add(setBatchParameters(config)) @@ -248,16 +246,16 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { if (LoggingApis.NONE != runtimeConfiguration.logging().api()) { builder.beginControlFlow("if ($L)", logging.shouldLog()); builder.add(variables.inline(String.class, names.executedQuery(), "$N", names.rawQuery())); - Stream.ofNullable(sqlConfiguration.parameters()) - .flatMap(Collection::stream) + sqlConfiguration.parameters() .forEach(parameter -> { - if (TypeGuesser.guessTypeName(parameter.type()).isPrimitive()) { - builder.add("\n$>.replace($S, $T.valueOf($N))$<", ":" + parameter.name(), - String.class, parameter.name()); + final var type = parameter.typeName().orElseThrow(); // TODO: throw business exception + final var name = parameter.name().orElseThrow(); // TODO: throw business exception + if (type.isPrimitive()) { + builder.add("\n$>.replace($S, $T.valueOf($N))$<", ":" + name, + String.class, name); } else { builder.add("\n$>.replace($S, $N == null ? $S : $N.toString())$<", - ":" + parameter.name(), parameter.name(), "null", - parameter.name()); + ":" + name, name, "null", name); } }); builder.add(";\n"); @@ -273,16 +271,15 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { if (LoggingApis.NONE != runtimeConfiguration.logging().api()) { builder.beginControlFlow("if ($L)", logging.shouldLog()); builder.add(variables.inline(String.class, names.executedQuery(), "$N", names.rawQuery())); - Stream.ofNullable(sqlConfiguration.parameters()) - .flatMap(Collection::stream) + sqlConfiguration.parameters() .forEach(parameter -> { - if (TypeGuesser.guessTypeName(parameter.type()).isPrimitive()) { - builder.add("\n$>.replace($S, $T.toString($N))$<", ":" + parameter.name(), - Arrays.class, parameter.name()); + final var type = parameter.typeName().orElseThrow(); // TODO: throw business exception + final var name = parameter.name().orElseThrow(); // TODO: throw business exception + if (type.isPrimitive()) { + builder.add("\n$>.replace($S, $T.toString($N))$<", ":" + name, Arrays.class, name); } else { builder.add("\n$>.replace($S, $N == null ? $S : $T.toString($N))$<", - ":" + parameter.name(), parameter.name(), "null", - Arrays.class, parameter.name()); + ":" + name, name, "null", Arrays.class, name); } }); builder.add(";\n"); @@ -306,22 +303,22 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { .add(controlFlows.whileHasNext()) .addStatement("$N.add($N.$N($N))", names.list(), - converter.alias(), - converter.methodName(), + converter.alias().orElseThrow(), // TODO: throw business exception + converter.methodName().orElseThrow(), // TODO: throw business exception names.resultSet()) .endControlFlow(); } @Override public CodeBlock returnAsMultiple(final ResultRowConverter converter) { - return prepareReturnList(TypicalTypes.listOf(converter.resultTypeName()), converter) + return prepareReturnList(TypicalTypes.listOf(converter.resultTypeName().orElseThrow()), converter) // TODO: throw business exception .addStatement("return $N", names.list()) .build(); } @Override public CodeBlock returnAsSingle(final ResultRowConverter converter) { - return prepareReturnList(TypicalTypes.listOf(converter.resultTypeName()), converter) + return prepareReturnList(TypicalTypes.listOf(converter.resultTypeName().orElseThrow()), converter) // TODO: throw business exception .addStatement("return $N.size() > 0 ? $T.of($N.get(0)) : $T.empty()", names.list(), Optional.class, names.list(), Optional.class) .build(); @@ -340,7 +337,7 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { private TypeSpec lazyStreamSpliterator(final ResultRowConverter converter) { final var spliteratorClass = ClassName.get(Spliterators.AbstractSpliterator.class); - final var resultType = TypeGuesser.guessTypeName(converter.resultType()); + final var resultType = converter.resultTypeName().orElseThrow(); // TODO: throw business exception final var superinterface = ParameterizedTypeName.get(spliteratorClass, resultType); final var consumerType = TypicalTypes.consumerOf(resultType); return TypeSpec @@ -351,7 +348,8 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { .returns(boolean.class) .addCode(controlFlows.startTryBlock()) .addCode(controlFlows.ifHasNext()) - .addStatement("$N.accept($N.$N($N))", names.action(), converter.alias(), converter.methodName(), + .addStatement("$N.accept($N.$N($N))", names.action(), converter.alias().orElseThrow(), // TODO: throw business exception + converter.methodName().orElseThrow(), // TODO: throw business exception names.resultSet()) .addCode(blocks.returnTrue()) .addCode(controlFlows.endIf()) @@ -401,20 +399,14 @@ public final class DefaultJdbcBlocks implements JdbcBlocks { final String codeStatement, final Function parameterSetter) { final var builder = CodeBlock.builder(); - final var parameters = config.parameters(); - - if (parameters != null && !parameters.isEmpty()) { - for (final var parameter : config.parameters()) { - builder.add(controlFlows.forLoop( - code("final int $N : $N.get($S)", - names.jdbcIndexVariable(), - names.indexVariable(), - parameter.name()), - CodeBlock.builder() - .addStatement(codeStatement, parameterSetter.apply(parameter.name())) - .build())); - } - } + config.parameters().forEach(parameter -> builder.add(controlFlows.forLoop( + code("final int $N : $N.get($S)", + names.jdbcIndexVariable(), + names.indexVariable(), + parameter.name().orElseThrow()), // TODO: throw business exception + CodeBlock.builder() + .addStatement(codeStatement, parameterSetter.apply(parameter.name().orElseThrow())) // TODO: throw business exception + .build()))); return builder.build(); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcParameters.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcParameters.java index 5e38260e..dcb6572d 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcParameters.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultJdbcParameters.java @@ -7,7 +7,6 @@ package wtf.metio.yosql.codegen.dao; -import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; import wtf.metio.yosql.codegen.blocks.Parameters; @@ -73,7 +72,7 @@ public final class DefaultJdbcParameters implements JdbcParameters { @Override public ParameterSpec converter(final ResultRowConverter converter) { - return parameters.parameter(ClassName.bestGuess(converter.converterType()), converter.alias()); + return parameters.parameter(converter.converterTypeName().orElseThrow(), converter.alias().orElseThrow()); // TODO: throw business exception } @Override diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultMethodsGenerator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultMethodsGenerator.java index 8ee0f298..860d0ef3 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultMethodsGenerator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultMethodsGenerator.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Default implementation of a {@link MethodsGenerator} that delegates most of its work to other interfaces/classes. @@ -79,7 +80,7 @@ public final class DefaultMethodsGenerator implements MethodsGenerator { final BiFunction, MethodSpec> generator) { return statements.stream() .filter(filter) - .collect(SqlStatement.groupByName()) + .collect(Collectors.groupingBy(SqlStatement::getName)) .values() .stream() .map(statementsInRepository -> generator.apply( diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultParameterGenerator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultParameterGenerator.java index 0b4fb743..e007591b 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultParameterGenerator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultParameterGenerator.java @@ -9,13 +9,10 @@ package wtf.metio.yosql.codegen.dao; import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.ParameterSpec; -import de.xn__ho_hia.javapoet.TypeGuesser; import wtf.metio.yosql.codegen.blocks.Parameters; import wtf.metio.yosql.models.configuration.SqlParameter; -import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -33,7 +30,7 @@ public class DefaultParameterGenerator implements ParameterGenerator { } private ParameterSpec ofSqlParameter(final SqlParameter parameter) { - return parameters.parameter(TypeGuesser.guessTypeName(parameter.type()), parameter.name()); + return parameters.parameter(parameter.typeName().orElseThrow(), parameter.name().orElseThrow()); } @Override @@ -42,7 +39,7 @@ public class DefaultParameterGenerator implements ParameterGenerator { } private ParameterSpec ofSqlParameterForInterfaces(final SqlParameter parameter) { - return parameters.parameterForInterfaces(TypeGuesser.guessTypeName(parameter.type()), parameter.name()); + return parameters.parameterForInterfaces(parameter.typeName().orElseThrow(), parameter.name().orElseThrow()); } @Override @@ -51,7 +48,7 @@ public class DefaultParameterGenerator implements ParameterGenerator { } private ParameterSpec batchOfSqlParameter(final SqlParameter parameter) { - return parameters.parameter(ArrayTypeName.of(TypeGuesser.guessTypeName(parameter.type())), parameter.name()); + return parameters.parameter(ArrayTypeName.of(parameter.typeName().orElseThrow()), parameter.name().orElseThrow()); } @Override @@ -60,17 +57,15 @@ public class DefaultParameterGenerator implements ParameterGenerator { } private ParameterSpec batchOfSqlParameterForInterfaces(final SqlParameter parameter) { - return parameters.parameterForInterfaces(ArrayTypeName.of(TypeGuesser.guessTypeName(parameter.type())), parameter.name()); + return parameters.parameterForInterfaces(ArrayTypeName.of(parameter.typeName().orElseThrow()), parameter.name().orElseThrow()); } private static Iterable asParameterSpecs( final List parameters, final Function asParameter) { - return Optional.ofNullable(parameters) - .map(params -> params.stream() - .map(asParameter) - .collect(Collectors.toList())) - .orElse(Collections.emptyList()); + return parameters.stream() + .map(asParameter) + .collect(Collectors.toList()); } } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultRepositoryGenerator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultRepositoryGenerator.java index 9a1b66a7..77af4d2d 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultRepositoryGenerator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultRepositoryGenerator.java @@ -63,7 +63,8 @@ public final class DefaultRepositoryGenerator implements RepositoryGenerator { .addJavadoc(javadoc.repositoryJavadoc(statements)) .addFields(fields.asFields(statements)) .addMethods(methods.asMethods(statements)) - .addAnnotations(annotations.generatedClass()); + .addAnnotations(annotations.generatedClass()) + .addAnnotations(annotations.generatedRepository()); fields.staticInitializer(statements).ifPresent(classBuilder::addStaticBlock); statements.stream() .map(SqlStatement::getRepositoryInterface) @@ -83,7 +84,8 @@ public final class DefaultRepositoryGenerator implements RepositoryGenerator { final var interfaceBuilder = classes.publicInterface(interfaceName) .addJavadoc(javadoc.repositoryJavadoc(statements)) .addMethods(methods.asMethodsDeclarations(statements)) - .addAnnotations(annotations.generatedClass()); + .addAnnotations(annotations.generatedClass()) + .addAnnotations(annotations.generatedRepository()); logger.debug(CodegenLifecycle.TYPE_GENERATED, interfaceName.packageName(), interfaceName.simpleName()); return PackagedTypeSpec.of(interfaceBuilder.build(), interfaceName.packageName()); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultReturnTypes.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultReturnTypes.java index 0bcf1fbf..49565d08 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultReturnTypes.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/DefaultReturnTypes.java @@ -7,8 +7,7 @@ package wtf.metio.yosql.codegen.dao; -import com.squareup.javapoet.ParameterizedTypeName; -import de.xn__ho_hia.javapoet.TypeGuesser; +import com.squareup.javapoet.TypeName; import wtf.metio.yosql.internals.javapoet.TypicalTypes; import wtf.metio.yosql.models.immutables.ConverterConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; @@ -33,10 +32,11 @@ public final class DefaultReturnTypes implements ReturnTypes { } @Override - public Optional resultType(final SqlConfiguration configuration) { + public Optional resultType(final SqlConfiguration configuration) { return configuration.returningMode() .filter(mode -> NONE != mode) .map(mode -> switch (mode) { +// case NONE -> TypeName.VOID; case SINGLE -> singleResultType(configuration); case CURSOR -> cursorResultType(configuration); default -> multiResultType(configuration); @@ -44,23 +44,23 @@ public final class DefaultReturnTypes implements ReturnTypes { } @Override - public ParameterizedTypeName singleResultType(final SqlConfiguration configuration) { + public TypeName singleResultType(final SqlConfiguration configuration) { final var converter = configuration.converter(converters::defaultConverter); - final var resultType = TypeGuesser.guessTypeName(converter.resultType()); + final var resultType = converter.resultTypeName().orElseThrow(); return TypicalTypes.optionalOf(resultType); } @Override - public ParameterizedTypeName multiResultType(final SqlConfiguration configuration) { + public TypeName multiResultType(final SqlConfiguration configuration) { final var converter = configuration.converter(converters::defaultConverter); - final var resultType = TypeGuesser.guessTypeName(converter.resultType()); + final var resultType = converter.resultTypeName().orElseThrow(); return TypicalTypes.listOf(resultType); } @Override - public ParameterizedTypeName cursorResultType(final SqlConfiguration configuration) { + public TypeName cursorResultType(final SqlConfiguration configuration) { final var converter = configuration.converter(converters::defaultConverter); - final var resultType = TypeGuesser.guessTypeName(converter.resultType()); + final var resultType = converter.resultTypeName().orElseThrow(); return TypicalTypes.streamOf(resultType); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/ReturnTypes.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/ReturnTypes.java index 856fa786..faa89b57 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/ReturnTypes.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/dao/ReturnTypes.java @@ -7,7 +7,7 @@ package wtf.metio.yosql.codegen.dao; -import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; import wtf.metio.yosql.models.immutables.SqlConfiguration; import java.util.Optional; @@ -24,7 +24,7 @@ public interface ReturnTypes { * @param configuration The configuration to use. * @return The fully qualified return type. */ - Optional resultType(SqlConfiguration configuration); + Optional resultType(SqlConfiguration configuration); /** * Determine return type for a method that returns a single result. @@ -32,7 +32,7 @@ public interface ReturnTypes { * @param configuration The configuration to use. * @return The fully qualified return type. */ - ParameterizedTypeName singleResultType(SqlConfiguration configuration); + TypeName singleResultType(SqlConfiguration configuration); /** * Determine return type for a method that returns multiple results. @@ -40,7 +40,7 @@ public interface ReturnTypes { * @param configuration The configuration to use. * @return The fully qualified return type. */ - ParameterizedTypeName multiResultType(SqlConfiguration configuration); + TypeName multiResultType(SqlConfiguration configuration); /** * Determine return type for a method that returns a cursor result. @@ -48,6 +48,6 @@ public interface ReturnTypes { * @param configuration The configuration to use. * @return The fully qualified return type. */ - ParameterizedTypeName cursorResultType(SqlConfiguration configuration); + TypeName cursorResultType(SqlConfiguration configuration); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultFileResolver.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultFileParser.java similarity index 69% rename from yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultFileResolver.java rename to yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultFileParser.java index ace79f0b..9839022d 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultFileResolver.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultFileParser.java @@ -4,6 +4,7 @@ * including this file, may be copied, modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ + package wtf.metio.yosql.codegen.files; import org.slf4j.cal10n.LocLogger; @@ -11,56 +12,60 @@ import wtf.metio.yosql.codegen.lifecycle.ApplicationErrors; import wtf.metio.yosql.codegen.lifecycle.FileLifecycle; import wtf.metio.yosql.codegen.orchestration.ExecutionErrors; import wtf.metio.yosql.models.immutables.FilesConfiguration; +import wtf.metio.yosql.models.immutables.SqlStatement; import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.Files; -import java.nio.file.Path; -import java.util.stream.Stream; +import java.util.List; /** - * A SQL file resolver that starts at {@link FilesConfiguration#inputBaseDirectory() - * the given source}, walks into every subdirectory and returns all .sql files. + * Default SQL file parser that starts at {@link FilesConfiguration#inputBaseDirectory() + * the given source}, walks into every subdirectory and returns all statements found in + * {@link FilesConfiguration#sqlFilesSuffix() .sql files}. */ -public final class DefaultFileResolver implements FileResolver { +public final class DefaultFileParser implements FileParser { private final LocLogger logger; private final ParserPreconditions preconditions; private final FilesConfiguration fileConfiguration; private final ExecutionErrors errors; + private final SqlStatementParser fileParser; - public DefaultFileResolver( + public DefaultFileParser( final LocLogger logger, final ParserPreconditions preconditions, final FilesConfiguration fileConfiguration, - final ExecutionErrors errors) { + final ExecutionErrors errors, + final SqlStatementParser fileParser) { this.logger = logger; this.preconditions = preconditions; this.fileConfiguration = fileConfiguration; this.errors = errors; + this.fileParser = fileParser; } @Override - public Stream resolveFiles() { + public List parseFiles() { final var source = fileConfiguration.inputBaseDirectory(); logger.trace(FileLifecycle.READ_FILES, source); preconditions.directoryIsReadable(source); if (!errors.hasErrors()) { - try { - return Files.walk(source, FileVisitOption.FOLLOW_LINKS) - .parallel() - .peek(path -> logger.trace(FileLifecycle.ENCOUNTER_FILE, path)) + try (final var files = Files.walk(source, FileVisitOption.FOLLOW_LINKS).parallel()) { + return files.peek(path -> logger.trace(FileLifecycle.ENCOUNTER_FILE, path)) .filter(Files::isRegularFile) .filter(path -> path.toString().endsWith(fileConfiguration.sqlFilesSuffix())) - .peek(path -> logger.trace(FileLifecycle.CONSIDER_FILE, path)); + .peek(path -> logger.trace(FileLifecycle.CONSIDER_FILE, path)) + .flatMap(fileParser::parse) + .toList(); } catch (final IOException | SecurityException exception) { logger.error(ApplicationErrors.READ_FILES_FAILED, exception.getLocalizedMessage()); errors.add(exception); } } - return Stream.empty(); + return List.of(); } } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurer.java index a822e005..4f7e3ebd 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurer.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurer.java @@ -10,11 +10,12 @@ package wtf.metio.yosql.codegen.files; import org.slf4j.cal10n.LocLogger; import wtf.metio.yosql.codegen.lifecycle.SqlConfigurationLifecycle; import wtf.metio.yosql.internals.jdk.Strings; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.RepositoriesConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; import javax.lang.model.SourceVersion; +import java.util.Optional; import static java.util.function.Predicate.not; @@ -48,16 +49,18 @@ public final class DefaultMethodNameConfigurer implements MethodNameConfigurer { // visible for testing SqlConfiguration baseName(final SqlConfiguration configuration, final String fileName, final int statementInFile) { - return configuration.name() - .filter(not(Strings::isBlank)) - .filter(SourceVersion::isName) - .map(name -> configuration) - .orElseGet(() -> SqlConfiguration.copyOf(configuration) - .withName(calculateName(validName(configuration.type().orElse(SqlType.UNKNOWN), fileName), - statementInFile))); + return SqlConfiguration.copyOf(configuration) + .withName(configuration.name() + .filter(SourceVersion::isName) + .or(() -> configuration.type() + .map(type -> validName(type, fileName)) + .map(name -> calculateName(name, statementInFile))) + .or(() -> Optional.of(fileName) + .filter(SourceVersion::isName) + .map(name -> calculateName(name, statementInFile)))); } - private String validName(final SqlType type, final String fileName) { + private String validName(final SqlStatementType type, final String fileName) { return SourceVersion.isName(fileName) ? fileName : generateName(type); } @@ -65,14 +68,13 @@ public final class DefaultMethodNameConfigurer implements MethodNameConfigurer { return statementInFile > 1 ? name + statementInFile : name; } - private String generateName(final SqlType type) { - final var typeLookup = switch (type) { + private String generateName(final SqlStatementType type) { + final var prefix = switch (type) { case READING -> repositories.allowedReadPrefixes().get(0); case WRITING -> repositories.allowedWritePrefixes().get(0); case CALLING -> repositories.allowedCallPrefixes().get(0); - case UNKNOWN -> "statement"; }; - return typeLookup + "NameWasChanged"; + return prefix + "NameWasChanged"; } // visible for testing diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidator.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidator.java index ef090a9e..294ddc16 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidator.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidator.java @@ -10,15 +10,13 @@ package wtf.metio.yosql.codegen.files; import ch.qos.cal10n.IMessageConveyor; import wtf.metio.yosql.codegen.lifecycle.ValidationErrors; import wtf.metio.yosql.codegen.orchestration.ExecutionErrors; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.RepositoriesConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; import java.nio.file.Path; import java.util.List; -import static wtf.metio.yosql.models.configuration.SqlType.*; - public final class DefaultMethodNameValidator implements MethodNameValidator { private final RepositoriesConfiguration repositories; @@ -37,30 +35,28 @@ public final class DefaultMethodNameValidator implements MethodNameValidator { @Override public void validateNames(final SqlConfiguration configuration, final Path source) { if (repositories.validateMethodNamePrefixes()) { - configuration.type().ifPresent(type -> { - switch (type) { - case READING -> configuration.name() - .filter(name -> notStartsWith(name, repositories.allowedReadPrefixes())) - .ifPresent(name -> invalidPrefix(source, READING, name)); - case WRITING -> configuration.name() - .filter(name -> notStartsWith(name, repositories.allowedWritePrefixes())) - .ifPresent(name -> invalidPrefix(source, WRITING, name)); - case CALLING -> configuration.name() - .filter(name -> notStartsWith(name, repositories.allowedCallPrefixes())) - .ifPresent(name -> invalidPrefix(source, CALLING, name)); - default -> errors.illegalArgument( - messages.getMessage(ValidationErrors.UNSUPPORTED_TYPE, source, configuration.type())); - } - }); + configuration.type() + .map(this::allowedPrefixes) + .flatMap(prefixes -> configuration.name() + .filter(name -> notStartsWith(name, prefixes))) + .ifPresent(name -> invalidPrefix(source, name)); } } + private List allowedPrefixes(final SqlStatementType type) { + return switch (type) { + case READING -> repositories.allowedReadPrefixes(); + case WRITING -> repositories.allowedWritePrefixes(); + case CALLING -> repositories.allowedCallPrefixes(); + }; + } + private static boolean notStartsWith(final String fileName, final List prefixes) { return prefixes == null || prefixes.stream().noneMatch(fileName::startsWith); } - private void invalidPrefix(final Path source, final SqlType sqlType, final String name) { - errors.illegalArgument(messages.getMessage(ValidationErrors.INVALID_PREFIX, source, sqlType, name)); + private void invalidPrefix(final Path source, final String name) { + errors.illegalArgument(messages.getMessage(ValidationErrors.INVALID_PREFIX, source, name)); } } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurer.java index ea05f7df..faeda2a0 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurer.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurer.java @@ -16,12 +16,11 @@ import wtf.metio.yosql.models.immutables.SqlConfiguration; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; public final class DefaultMethodParameterConfigurer implements MethodParameterConfigurer { @@ -53,10 +52,12 @@ public final class DefaultMethodParameterConfigurer implements MethodParameterCo final Path source, final Map> parameterIndices, final SqlConfiguration configuration) { - final var parameterErrors = Stream.ofNullable(configuration.parameters()) - .flatMap(Collection::stream) - .filter(param -> !parameterIndices.containsKey(param.name())) - .map(param -> messages.getMessage(ValidationErrors.UNKNOWN_PARAMETER, source, param.name())) + final var parameterErrors = configuration.parameters() + .stream() + .map(SqlParameter::name) + .flatMap(Optional::stream) + .filter(name -> !parameterIndices.containsKey(name)) + .map(name -> messages.getMessage(ValidationErrors.UNKNOWN_PARAMETER, source, name)) .peek(errors::illegalArgument) .peek(logger::error) .toList(); @@ -65,12 +66,10 @@ public final class DefaultMethodParameterConfigurer implements MethodParameterCo private static List updateIndices(final List parameters, final Map> indices) { return parameters.stream() - .map(parameter -> SqlParameter.builder() - .setName(parameter.name()) - .setType(parameter.type()) - .setIndices(asIntArray(indices.get(parameter.name()))) - .setConverter(parameter.converter()) - .build()) + .map(parameter -> SqlParameter.copyOf(parameter) + .withIndices(parameter.name() + .map(indices::get) + .map(DefaultMethodParameterConfigurer::asIntArray))) .collect(Collectors.toList()); } @@ -80,7 +79,7 @@ public final class DefaultMethodParameterConfigurer implements MethodParameterCo .toArray(); } - private List addMissingParameters(final List parameters, final Map> indices) { + private static List addMissingParameters(final List parameters, final Map> indices) { final var all = new ArrayList<>(parameters); for (final var entry : indices.entrySet()) { final var parameterName = entry.getKey(); @@ -96,11 +95,13 @@ public final class DefaultMethodParameterConfigurer implements MethodParameterCo } private static boolean isMissingParameter(final List parameters, final String parameterName) { - return Stream.ofNullable(parameters).flatMap(Collection::stream).noneMatch(nameMatches(parameterName)); + return parameters.stream().noneMatch(nameMatches(parameterName)); } private static Predicate nameMatches(final String parameterName) { - return parameter -> parameterName.equals(parameter.name()); + return parameter -> parameter.name() + .map(parameterName::equals) + .orElse(Boolean.FALSE); } } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodConverterConfigurer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodResultRowConverterConfigurer.java similarity index 60% rename from yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodConverterConfigurer.java rename to yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodResultRowConverterConfigurer.java index 283b30eb..1cb55f50 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodConverterConfigurer.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodResultRowConverterConfigurer.java @@ -7,7 +7,6 @@ package wtf.metio.yosql.codegen.files; -import wtf.metio.yosql.internals.jdk.Strings; import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.immutables.ConverterConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; @@ -16,41 +15,37 @@ import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; -public final class DefaultMethodConverterConfigurer implements MethodConverterConfigurer { +public final class DefaultMethodResultRowConverterConfigurer implements MethodResultRowConverterConfigurer { - private final ConverterConfiguration converter; + private final ConverterConfiguration converters; - public DefaultMethodConverterConfigurer(final ConverterConfiguration converter) { - this.converter = converter; + public DefaultMethodResultRowConverterConfigurer(final ConverterConfiguration converters) { + this.converters = converters; } @Override - public SqlConfiguration configureConverter(final SqlConfiguration configuration) { - if (configuration.resultRowConverter().isEmpty()) { - return SqlConfiguration.copyOf(configuration).withResultRowConverter(getDefaultRowConverter()); - } - final var currentConverter = configuration.resultRowConverter().get(); - final var converter = ResultRowConverter.builder() - .setAlias(Strings.isBlank(currentConverter.alias()) ? - getDefaultAlias(currentConverter) : currentConverter.alias()) - .setConverterType(Strings.isBlank(currentConverter.converterType()) ? - getDefaultConverterType(currentConverter) : currentConverter.converterType()) - .setMethodName(Strings.isBlank(currentConverter.methodName()) ? - getDefaultMethodName(currentConverter) : currentConverter.methodName()) - .setResultType(Strings.isBlank(currentConverter.resultType()) ? - getDefaultResultType(currentConverter) : currentConverter.resultType()) - .build(); - + public SqlConfiguration configureResultRowConverter(final SqlConfiguration configuration) { return SqlConfiguration.copyOf(configuration) - .withResultRowConverter(converter); + .withResultRowConverter(configuration.resultRowConverter() + .map(this::adjustConverter) + .or(this::getDefaultRowConverter)); + } + + private ResultRowConverter adjustConverter(final ResultRowConverter original) { + return ResultRowConverter.builder() + .setAlias(original.alias().orElse(getDefaultAlias(original))) + .setConverterType(original.converterType().orElse(getDefaultConverterType(original))) + .setMethodName(original.methodName().orElse(getDefaultMethodName(original))) + .setResultType(original.resultType().orElse(getDefaultResultType(original))) + .build(); } private Optional getDefaultRowConverter() { - final var resultRowConverter = converter.defaultConverter(); - return converter.rowConverters().stream() - .filter(converter -> resultRowConverter.isEmpty() || resultRowConverter.get().equals(converter)) + final var defaultConverter = converters.defaultConverter(); + return converters.rowConverters().stream() + .filter(converter -> defaultConverter.isEmpty() || defaultConverter.get().equals(converter)) .findFirst() - .or(() -> resultRowConverter); + .or(() -> defaultConverter); } private String getDefaultAlias(final ResultRowConverter resultConverter) { @@ -81,10 +76,11 @@ public final class DefaultMethodConverterConfigurer implements MethodConverterCo private String getConverterFieldOrEmptyString( final Predicate predicate, - final Function mapper) { - return converter.rowConverters().stream() + final Function> mapper) { + return converters.rowConverters().stream() .filter(predicate) .map(mapper) + .flatMap(Optional::stream) .findFirst() .orElse(""); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurer.java index 1b90bfe8..5bc4052a 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurer.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurer.java @@ -8,13 +8,14 @@ package wtf.metio.yosql.codegen.files; import wtf.metio.yosql.models.configuration.ReturningMode; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.RepositoriesConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; import java.util.List; +import java.util.Optional; -import static wtf.metio.yosql.models.configuration.SqlType.*; +import static wtf.metio.yosql.models.configuration.SqlStatementType.*; public final class DefaultMethodSettingsConfigurer implements MethodSettingsConfigurer { @@ -38,22 +39,20 @@ public final class DefaultMethodSettingsConfigurer implements MethodSettingsConf // visible for testing SqlConfiguration type(final SqlConfiguration configuration) { - return configuration.type() - .filter(type -> UNKNOWN != type) - .map(type -> configuration) - .orElseGet(() -> SqlConfiguration.copyOf(configuration) - .withType(mapNameToType(configuration.name().orElse("")))); + return SqlConfiguration.copyOf(configuration) + .withType(configuration.type() + .or(() -> mapNameToType(configuration.name().orElse("")))); } - private SqlType mapNameToType(final String name) { + private Optional mapNameToType(final String name) { if (startsWith(name, repositories.allowedWritePrefixes())) { - return WRITING; + return Optional.of(WRITING); } else if (startsWith(name, repositories.allowedReadPrefixes())) { - return READING; + return Optional.of(READING); } else if (startsWith(name, repositories.allowedCallPrefixes())) { - return CALLING; + return Optional.of(CALLING); } - return UNKNOWN; + return Optional.empty(); } private static boolean startsWith(final String fileName, final List prefixes) { @@ -61,18 +60,17 @@ public final class DefaultMethodSettingsConfigurer implements MethodSettingsConf } // visible for testing - SqlConfiguration returningMode(final SqlConfiguration configuration) { - return configuration.returningMode() - .map(mode -> configuration) - .orElseGet(() -> SqlConfiguration.copyOf(configuration) - .withReturningMode(mapTypeReturningMode(configuration.type().orElse(UNKNOWN)))); + static SqlConfiguration returningMode(final SqlConfiguration configuration) { + return SqlConfiguration.copyOf(configuration) + .withReturningMode(configuration.returningMode() + .or(() -> configuration.type().map(DefaultMethodSettingsConfigurer::mapTypeReturningMode))); } - private ReturningMode mapTypeReturningMode(final SqlType type) { + private static ReturningMode mapTypeReturningMode(final SqlStatementType type) { return switch (type) { - case READING -> ReturningMode.MULTIPLE; case CALLING -> ReturningMode.SINGLE; - default -> ReturningMode.NONE; + case READING -> ReturningMode.MULTIPLE; + case WRITING -> ReturningMode.NONE; }; } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactory.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactory.java index 1fc77368..8fcf4554 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactory.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactory.java @@ -26,7 +26,7 @@ public final class DefaultSqlConfigurationFactory implements SqlConfigurationFac private final MethodNameValidator methodNameValidator; private final MethodApiConfigurer methodApis; private final MethodParameterConfigurer methodParameters; - private final MethodConverterConfigurer methodConverter; + private final MethodResultRowConverterConfigurer methodConverter; private final RepositoryNameConfigurer repositoryName; /** @@ -48,7 +48,7 @@ public final class DefaultSqlConfigurationFactory implements SqlConfigurationFac final MethodNameValidator methodNameValidator, final MethodApiConfigurer methodApis, final MethodParameterConfigurer methodParameters, - final MethodConverterConfigurer methodConverter, + final MethodResultRowConverterConfigurer methodConverter, final RepositoryNameConfigurer repositoryName) { this.methodParameters = methodParameters; this.logger = logger; @@ -81,7 +81,7 @@ public final class DefaultSqlConfigurationFactory implements SqlConfigurationFac configuration = methodApis.configureApis(configuration); configuration = repositoryName.configureNames(configuration, source); configuration = methodParameters.configureParameters(configuration, source, parameterIndices); - configuration = methodConverter.configureConverter(configuration); + configuration = methodConverter.configureResultRowConverter(configuration); logger.debug("SQL configuration: {}", configuration); methodNameValidator.validateNames(configuration, source); return configuration; diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParser.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParser.java index 35d69502..645a4ef5 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParser.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParser.java @@ -7,43 +7,48 @@ package wtf.metio.yosql.codegen.files; +import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import wtf.metio.yosql.codegen.orchestration.ExecutionErrors; import wtf.metio.yosql.internals.jdk.Strings; -import wtf.metio.yosql.models.configuration.ResultRowConverter; -import wtf.metio.yosql.models.configuration.SqlParameter; import wtf.metio.yosql.models.immutables.SqlConfiguration; import java.util.Optional; +import java.util.function.Predicate; /** * Default implementation of a {@link SqlConfigurationParser} that works with YAML based configs. */ public final class DefaultSqlConfigurationParser implements SqlConfigurationParser { + private final ExecutionErrors errors; + private final YAMLMapper mapper; + + public DefaultSqlConfigurationParser(final ExecutionErrors errors) { + this.errors = errors; + mapper = YAMLMapper.builder() + .addModule(new Jdk8Module()) + .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) + .build(); + } + @Override public SqlConfiguration parseConfig(final String yaml) { - SqlConfiguration configuration = null; + return Optional.of(yaml) + .filter(Predicate.not(Strings::isBlank)) + .flatMap(this::parseYaml) + .orElseGet(() -> SqlConfiguration.usingDefaults().build()); + } + + private Optional parseYaml(final String yaml) { try { - if (!Strings.isBlank(yaml)) { - final var yoSqlModule = new SimpleModule(); - yoSqlModule.addDeserializer(SqlParameter.class, new SqlParameterDeserializer()); - yoSqlModule.addDeserializer(ResultRowConverter.class, new ResultRowConverterDeserializer()); - final var yamlMapper = YAMLMapper.builder() - .addModule(new Jdk8Module()) - .addModule(yoSqlModule) - .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) - .build(); - configuration = yamlMapper.readValue(yaml, SqlConfiguration.class); - } - } catch (final Exception exception) { - // TODO: add exception to execution errors - throw new RuntimeException(exception); + return Optional.of(mapper.readValue(yaml, SqlConfiguration.class)); + } catch (final JacksonException exception) { + errors.add(exception); + return Optional.empty(); } - return Optional.ofNullable(configuration) - .orElseGet(() -> SqlConfiguration.usingDefaults().build()); } } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileParser.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileParser.java index f4fe4f3a..302c76ec 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileParser.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileParser.java @@ -13,8 +13,7 @@ import java.util.List; /** * High-level interface that handles parsing of SQL files. - * - * @see FileResolver + * * @see SqlStatementParser */ @FunctionalInterface diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileResolver.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileResolver.java deleted file mode 100644 index 98061e6e..00000000 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/FileResolver.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, - * including this file, may be copied, modified, propagated, or distributed except according to the terms contained - * in the LICENSE file. - */ -package wtf.metio.yosql.codegen.files; - -import java.nio.file.Path; -import java.util.stream.Stream; - -/** - * Resolves SQL files possibly from an external source, like the file system. - */ -@FunctionalInterface -public interface FileResolver { - - /** - * @return A stream of SQL files found in the source of this resolver. - */ - Stream resolveFiles(); - -} diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/MethodConverterConfigurer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/MethodResultRowConverterConfigurer.java similarity index 85% rename from yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/MethodConverterConfigurer.java rename to yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/MethodResultRowConverterConfigurer.java index ca79e43a..9746c256 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/MethodConverterConfigurer.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/MethodResultRowConverterConfigurer.java @@ -15,7 +15,7 @@ import wtf.metio.yosql.models.immutables.SqlConfiguration; * @see DefaultSqlConfigurationFactory */ @FunctionalInterface -public interface MethodConverterConfigurer { +public interface MethodResultRowConverterConfigurer { /** * Configures method converters. @@ -23,6 +23,6 @@ public interface MethodConverterConfigurer { * @param configuration The original configuration to adapt. * @return An adapted version of the original. */ - SqlConfiguration configureConverter(SqlConfiguration configuration); + SqlConfiguration configureResultRowConverter(SqlConfiguration configuration); } diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/ResultRowConverterDeserializer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/ResultRowConverterDeserializer.java deleted file mode 100644 index 16b38a8d..00000000 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/ResultRowConverterDeserializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, - * including this file, may be copied, modified, propagated, or distributed except according to the terms contained - * in the LICENSE file. - */ - -package wtf.metio.yosql.codegen.files; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import wtf.metio.yosql.internals.jdk.Strings; -import wtf.metio.yosql.models.configuration.ResultRowConverter; - -import java.io.IOException; - -public final class ResultRowConverterDeserializer extends JsonDeserializer { - - @Override - public ResultRowConverter deserialize( - final JsonParser jsonParser, - final DeserializationContext context) throws IOException { - final var converter = jsonParser.readValueAs(Converter.class); - return ResultRowConverter.builder() - .setAlias(Strings.isBlank(converter.alias) ? "" : converter.alias) - .setConverterType(Strings.isBlank(converter.converterType) ? "" : converter.converterType) - .setMethodName(Strings.isBlank(converter.methodName) ? "" : converter.methodName) - .setResultType(Strings.isBlank(converter.resultType) ? "" : converter.resultType) - .build(); - } - - private static final class Converter { - public String alias; - public String converterType; - public String methodName; - public String resultType; - } - -} diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/SqlParameterDeserializer.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/SqlParameterDeserializer.java deleted file mode 100644 index a07f4a8a..00000000 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/files/SqlParameterDeserializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, - * including this file, may be copied, modified, propagated, or distributed except according to the terms contained - * in the LICENSE file. - */ - -package wtf.metio.yosql.codegen.files; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import wtf.metio.yosql.internals.jdk.Strings; -import wtf.metio.yosql.models.configuration.SqlParameter; - -import java.io.IOException; - -public final class SqlParameterDeserializer extends JsonDeserializer { - - @Override - public SqlParameter deserialize( - final JsonParser jsonParser, - final DeserializationContext context) throws IOException { - final var parameter = jsonParser.readValueAs(Parameter.class); - return SqlParameter.builder() - .setName(Strings.isBlank(parameter.name) ? "" : parameter.name) - .setType(Strings.isBlank(parameter.type) ? "" : parameter.type) - .setIndices(parameter.indices == null ? new int[0] : parameter.indices) - .setConverter(Strings.isBlank(parameter.converter) ? "" : parameter.converter) - .build(); - } - - private static final class Parameter { - public String name; - public String type; - public String converter; - public int[] indices; - } - -} diff --git a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/lifecycle/ValidationErrors.java b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/lifecycle/ValidationErrors.java index c3f99dce..d618c3e8 100644 --- a/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/lifecycle/ValidationErrors.java +++ b/yosql-codegen/src/main/java/wtf/metio/yosql/codegen/lifecycle/ValidationErrors.java @@ -19,11 +19,6 @@ import ch.qos.cal10n.LocaleData; public enum ValidationErrors { /** - * Signals that an unsupported SQL statement type was used. - */ - UNSUPPORTED_TYPE, - - /** * Signals that an invalid prefix was used for a query. */ INVALID_PREFIX, diff --git a/yosql-codegen/src/main/resources/validation-errors_de.properties b/yosql-codegen/src/main/resources/validation-errors_de.properties index f63af9f0..4e0b141b 100644 --- a/yosql-codegen/src/main/resources/validation-errors_de.properties +++ b/yosql-codegen/src/main/resources/validation-errors_de.properties @@ -4,6 +4,5 @@ # including this file, may be copied, modified, propagated, or distributed except according to the terms contained # in the LICENSE file. # -UNSUPPORTED_TYPE=[{0}] unterstützt [{1}] nicht -INVALID_PREFIX=[{0}] benutzt ungültigen Prefix {1} im Namen [{2}] +INVALID_PREFIX=[{0}] benutzt ungültigen Prefix im Namen [{1}] UNKNOWN_PARAMETER=[{0}] deklariert unbekannten Parameter [{1}] diff --git a/yosql-codegen/src/main/resources/validation-errors_en.properties b/yosql-codegen/src/main/resources/validation-errors_en.properties index 0b350a67..12c79a78 100644 --- a/yosql-codegen/src/main/resources/validation-errors_en.properties +++ b/yosql-codegen/src/main/resources/validation-errors_en.properties @@ -4,6 +4,5 @@ # including this file, may be copied, modified, propagated, or distributed except according to the terms contained # in the LICENSE file. # -UNSUPPORTED_TYPE=[{0}] has unsupported type [{1}] -INVALID_PREFIX=[{0}] has invalid {1} prefix in its name [{2}] +INVALID_PREFIX=[{0}] has invalid prefix in its name [{1}] UNKNOWN_PARAMETER=[{0}] declares unknown parameter [{1}] diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotationsTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotationsTest.java index e8c3b71e..534996c6 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotationsTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/blocks/DefaultAnnotationsTest.java @@ -11,6 +11,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import wtf.metio.yosql.models.configuration.Annotation; +import wtf.metio.yosql.models.configuration.AnnotationMember; import wtf.metio.yosql.testing.configs.AnnotationsConfigurations; @DisplayName("DefaultAnnotations") @@ -103,4 +105,166 @@ class DefaultAnnotationsTest { } + @Test + void asAnnotationSpec() { + final var annotation = Annotation.builder().setType("com.example.Annotation").build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMember() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder().setKey("value").setValue("test").build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation("test")""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingCustomKey() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder().setKey("random").setValue("test").build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(random = "test")""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMembers() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder().setKey("value").setValue("test").build()) + .addMembers(AnnotationMember.builder().setKey("another").setValue("value").build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(value = "test", another = "value")""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingBoolType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("true") + .setType("boolean") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = true)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingIntType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("123") + .setType("int") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 123)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingLongType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("456789") + .setType("long") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 456789)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingShortType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("123") + .setType("short") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 123)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingByteType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("123") + .setType("byte") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 123)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingFloatType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("3.14") + .setType("float") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 3.14)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingDoubleType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("3.14") + .setType("double") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 3.14)""", spec.toString()); + } + + @Test + void asAnnotationSpecWithMemberUsingCharType() { + final var annotation = Annotation.builder() + .setType("com.example.Annotation") + .addMembers(AnnotationMember.builder() + .setKey("test") + .setValue("a") + .setType("char") + .build()) + .build(); + final var spec = DefaultAnnotations.asAnnotationSpec(annotation); + Assertions.assertEquals(""" + @com.example.Annotation(test = 'a')""", spec.toString()); + } + } diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodApiConfigurerTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodApiConfigurerTest.java index 6a9276c1..2e10a3b5 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodApiConfigurerTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodApiConfigurerTest.java @@ -9,7 +9,7 @@ package wtf.metio.yosql.codegen.files; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.RepositoriesConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.testing.configs.RepositoriesConfigurations; @@ -50,7 +50,7 @@ class DefaultMethodApiConfigurerTest { void batchAllowsReads() { final var original = SqlConfiguration.usingDefaults() .setGenerateBatchApi(true) - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.batch(original); assertTrue(adapted.generateBatchApi().isPresent()); diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurerTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurerTest.java index b2f1216e..ae652816 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurerTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameConfigurerTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import wtf.metio.yosql.codegen.logging.LoggingObjectMother; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.RepositoriesConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.testing.configs.RepositoriesConfigurations; @@ -138,7 +138,6 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameUnknownType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "filename", 0); assertTrue(adapted.name().isPresent()); @@ -149,18 +148,15 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameUnknownType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); - assertTrue(adapted.name().isPresent()); - assertEquals("statementNameWasChanged", adapted.name().get()); + assertTrue(adapted.name().isEmpty()); } @Test void baseNameInvalidNameUnknownTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "filename", 3); assertTrue(adapted.name().isPresent()); @@ -171,18 +167,16 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameUnknownTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "!@#$%", 3); - assertTrue(adapted.name().isPresent()); - assertEquals("statementNameWasChanged3", adapted.name().get()); + assertTrue(adapted.name().isEmpty()); } @Test void baseNameInvalidNameReadType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.baseName(original, "filename", 0); assertTrue(adapted.name().isPresent()); @@ -193,7 +187,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameReadType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); assertTrue(adapted.name().isPresent()); @@ -204,7 +198,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameReadTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.baseName(original, "filename", 2); assertTrue(adapted.name().isPresent()); @@ -215,7 +209,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameReadTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 2); assertTrue(adapted.name().isPresent()); @@ -226,7 +220,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameWriteType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); final var adapted = configurer.baseName(original, "filename", 0); assertTrue(adapted.name().isPresent()); @@ -237,7 +231,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameWriteType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); assertTrue(adapted.name().isPresent()); @@ -248,7 +242,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameWriteTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); final var adapted = configurer.baseName(original, "filename", 3); assertTrue(adapted.name().isPresent()); @@ -259,7 +253,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameWriteTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 3); assertTrue(adapted.name().isPresent()); @@ -270,7 +264,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameCallType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); final var adapted = configurer.baseName(original, "filename", 0); assertTrue(adapted.name().isPresent()); @@ -281,7 +275,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameCallType() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); assertTrue(adapted.name().isPresent()); @@ -292,7 +286,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameCallTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); final var adapted = configurer.baseName(original, "filename", 4); assertTrue(adapted.name().isPresent()); @@ -303,7 +297,7 @@ class DefaultMethodNameConfigurerTest { void baseNameInvalidNameInvalidFileNameCallTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("!@#$%") - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 4); assertTrue(adapted.name().isPresent()); @@ -314,7 +308,6 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankName() { final var original = SqlConfiguration.usingDefaults() .setName("") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "some", 0); assertTrue(adapted.name().isPresent()); @@ -325,7 +318,6 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameNumbered() { final var original = SqlConfiguration.usingDefaults() .setName("") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "some", 1); assertTrue(adapted.name().isPresent()); @@ -336,29 +328,25 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameInvalidFileNameUnknownType() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); - assertTrue(adapted.name().isPresent()); - assertEquals("statementNameWasChanged", adapted.name().get()); + assertTrue(adapted.name().isEmpty()); } @Test void baseNameBlankNameInvalidFileNameUnknownTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.UNKNOWN) .build(); final var adapted = configurer.baseName(original, "!@#$%", 1); - assertTrue(adapted.name().isPresent()); - assertEquals("statementNameWasChanged", adapted.name().get()); + assertTrue(adapted.name().isEmpty()); } @Test void baseNameBlankNameInvalidFileNameReadType() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); assertTrue(adapted.name().isPresent()); @@ -369,7 +357,7 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameInvalidFileNameReadTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 2); assertTrue(adapted.name().isPresent()); @@ -380,7 +368,7 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameInvalidFileNameWriteType() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); assertTrue(adapted.name().isPresent()); @@ -391,7 +379,7 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameInvalidFileNameWriteTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 3); assertTrue(adapted.name().isPresent()); @@ -402,7 +390,7 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameInvalidFileNameCallType() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 0); assertTrue(adapted.name().isPresent()); @@ -413,7 +401,7 @@ class DefaultMethodNameConfigurerTest { void baseNameBlankNameInvalidFileNameCallTypeNumbered() { final var original = SqlConfiguration.usingDefaults() .setName(" ") - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); final var adapted = configurer.baseName(original, "!@#$%", 3); assertTrue(adapted.name().isPresent()); diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidatorTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidatorTest.java index ac4b20d8..92a89a23 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidatorTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodNameValidatorTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.Test; import wtf.metio.yosql.codegen.logging.LoggingObjectMother; import wtf.metio.yosql.codegen.orchestration.ExecutionErrors; import wtf.metio.yosql.codegen.orchestration.OrchestrationObjectMother; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.testing.configs.RepositoriesConfigurations; @@ -35,19 +35,9 @@ class DefaultMethodNameValidatorTest { } @Test - void detectUnknownType() { - final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.UNKNOWN) - .build(); - final var source = Paths.get("some.sql"); - validator.validateNames(configuration, source); - assertTrue(errors.hasErrors()); - } - - @Test void detectInvalidReadPrefix() { final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .setName("updateSomeData") .build(); final var source = Paths.get("some.sql"); @@ -58,7 +48,7 @@ class DefaultMethodNameValidatorTest { @Test void detectInvalidWritePrefix() { final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .setName("findSomeData") .build(); final var source = Paths.get("some.sql"); @@ -69,7 +59,7 @@ class DefaultMethodNameValidatorTest { @Test void detectInvalidCallPrefix() { final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .setName("findSomeData") .build(); final var source = Paths.get("some.sql"); @@ -80,7 +70,7 @@ class DefaultMethodNameValidatorTest { @Test void acceptValidReadPrefix() { final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .setName("findSomeData") .build(); final var source = Paths.get("some.sql"); @@ -91,7 +81,7 @@ class DefaultMethodNameValidatorTest { @Test void acceptValidWritePrefix() { final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .setName("writeSomeData") .build(); final var source = Paths.get("some.sql"); @@ -102,7 +92,7 @@ class DefaultMethodNameValidatorTest { @Test void acceptValidCallPrefix() { final var configuration = SqlConfiguration.usingDefaults() - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .setName("callSomeProcedure") .build(); final var source = Paths.get("some.sql"); diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurerTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurerTest.java index d9582db0..3ceae1c7 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurerTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodParameterConfigurerTest.java @@ -36,8 +36,8 @@ class DefaultMethodParameterConfigurerTest { Assertions.assertEquals(2, adapted.parameters().size()); Assertions.assertAll( - () -> Assertions.assertEquals("first", adapted.parameters().get(0).name()), - () -> Assertions.assertEquals("second", adapted.parameters().get(1).name())); + () -> Assertions.assertEquals("first", adapted.parameters().get(0).name().get()), + () -> Assertions.assertEquals("second", adapted.parameters().get(1).name().get())); } } diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurerTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurerTest.java index 04cec5cf..fc542f9e 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurerTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultMethodSettingsConfigurerTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import wtf.metio.yosql.models.configuration.ReturningMode; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.RepositoriesConfiguration; import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.testing.configs.RepositoriesConfigurations; @@ -32,7 +32,7 @@ class DefaultMethodSettingsConfigurerTest { @Test void typeKeep() { - final var original = SqlConfiguration.usingDefaults().setType(SqlType.CALLING).build(); + final var original = SqlConfiguration.usingDefaults().setType(SqlStatementType.CALLING).build(); final var adapted = configurer.type(original); assertEquals(original.type(), adapted.type()); } @@ -40,45 +40,31 @@ class DefaultMethodSettingsConfigurerTest { @Test void typeChangeReading() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.UNKNOWN) .setName(repositories.allowedReadPrefixes().get(0) + "Something") .build(); final var adapted = configurer.type(original); assertTrue(adapted.type().isPresent()); - assertEquals(SqlType.READING, adapted.type().get()); + assertEquals(SqlStatementType.READING, adapted.type().get()); } @Test void typeChangeWriting() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.UNKNOWN) .setName(repositories.allowedWritePrefixes().get(0) + "Something") .build(); final var adapted = configurer.type(original); assertTrue(adapted.type().isPresent()); - assertEquals(SqlType.WRITING, adapted.type().get()); + assertEquals(SqlStatementType.WRITING, adapted.type().get()); } @Test void typeChangeCalling() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.UNKNOWN) .setName(repositories.allowedCallPrefixes().get(0) + "Something") .build(); final var adapted = configurer.type(original); assertTrue(adapted.type().isPresent()); - assertEquals(SqlType.CALLING, adapted.type().get()); - } - - @Test - void typeChangeUnknown() { - final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.UNKNOWN) - .setName("question" + "Something") - .build(); - final var adapted = configurer.type(original); - assertTrue(adapted.type().isPresent()); - assertEquals(SqlType.UNKNOWN, adapted.type().get()); + assertEquals(SqlStatementType.CALLING, adapted.type().get()); } @Test @@ -86,16 +72,16 @@ class DefaultMethodSettingsConfigurerTest { final var original = SqlConfiguration.usingDefaults() .setReturningMode(ReturningMode.MULTIPLE) .build(); - final var adapted = configurer.returningMode(original); + final var adapted = DefaultMethodSettingsConfigurer.returningMode(original); assertEquals(original.returningMode(), adapted.returningMode()); } @Test void returningModeChangeReading() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.READING) + .setType(SqlStatementType.READING) .build(); - final var adapted = configurer.returningMode(original); + final var adapted = DefaultMethodSettingsConfigurer.returningMode(original); assertTrue(adapted.returningMode().isPresent()); assertEquals(ReturningMode.MULTIPLE, adapted.returningMode().get()); } @@ -103,9 +89,9 @@ class DefaultMethodSettingsConfigurerTest { @Test void returningModeChangeCalling() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .build(); - final var adapted = configurer.returningMode(original); + final var adapted = DefaultMethodSettingsConfigurer.returningMode(original); assertTrue(adapted.returningMode().isPresent()); assertEquals(ReturningMode.SINGLE, adapted.returningMode().get()); } @@ -113,22 +99,19 @@ class DefaultMethodSettingsConfigurerTest { @Test void returningModeChangeWriting() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.WRITING) + .setType(SqlStatementType.WRITING) .build(); - final var adapted = configurer.returningMode(original); + final var adapted = DefaultMethodSettingsConfigurer.returningMode(original); assertTrue(adapted.returningMode().isPresent()); assertEquals(ReturningMode.NONE, adapted.returningMode().get()); } @Test - void returningModeChangeUnknown() { + void returningModeRemainUnknown() { final var original = SqlConfiguration.usingDefaults() - .setReturningMode(ReturningMode.NONE) - .setType(SqlType.UNKNOWN) .build(); - final var adapted = configurer.returningMode(original); - assertTrue(adapted.returningMode().isPresent()); - assertEquals(ReturningMode.NONE, adapted.returningMode().get()); + final var adapted = DefaultMethodSettingsConfigurer.returningMode(original); + assertTrue(adapted.returningMode().isEmpty()); } @Test @@ -210,7 +193,7 @@ class DefaultMethodSettingsConfigurerTest { @Test void keepSettings() { final var original = SqlConfiguration.usingDefaults() - .setType(SqlType.CALLING) + .setType(SqlStatementType.CALLING) .setReturningMode(ReturningMode.MULTIPLE) .setCatchAndRethrow(false) .setInjectConverters(true) @@ -227,7 +210,6 @@ class DefaultMethodSettingsConfigurerTest { void changeSettings() { final var original = SqlConfiguration.usingDefaults() .setName(repositories.allowedCallPrefixes().get(0) + "Something") - .setType(SqlType.UNKNOWN) // .setCatchAndRethrow(false) // do NOT set value // .setInjectConverters(true) // do NOT set value // .setThrowOnMultipleResultsForSingle(true) // value is NOT set @@ -235,7 +217,7 @@ class DefaultMethodSettingsConfigurerTest { .build(); final var adapted = configurer.configureSettings(original); assertAll( - () -> assertEquals(SqlType.CALLING, adapted.type().get()), + () -> assertEquals(SqlStatementType.CALLING, adapted.type().get()), () -> assertEquals(ReturningMode.SINGLE, adapted.returningMode().get()), () -> assertEquals(repositories.catchAndRethrow(), adapted.catchAndRethrow().get()), () -> assertEquals(repositories.injectConverters(), adapted.injectConverters().get()), diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactoryTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactoryTest.java index 28b0e1e7..55cb7d71 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactoryTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationFactoryTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.configuration.ReturningMode; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.ConverterConfiguration; import wtf.metio.yosql.models.immutables.RuntimeConfiguration; import wtf.metio.yosql.testing.configs.RuntimeConfigurations; @@ -55,7 +55,7 @@ class DefaultSqlConfigurationFactoryTest { assertAll("Configuration", () -> assertEquals("read", configuration.name().get(), "name"), () -> assertEquals("com.example.persistence.PersonRepository", configuration.repository().get(), "repository"), - () -> assertEquals(SqlType.READING, configuration.type().get(), "type"), + () -> assertEquals(SqlStatementType.READING, configuration.type().get(), "type"), () -> assertEquals(ReturningMode.MULTIPLE, configuration.returningMode().get(), "returningMode")); } @@ -74,7 +74,7 @@ class DefaultSqlConfigurationFactoryTest { assertAll("Configuration", () -> assertEquals("insert", configuration.name().get(), "name"), () -> assertEquals("com.example.persistence.PersonRepository", configuration.repository().get(), "repository"), - () -> assertEquals(SqlType.WRITING, configuration.type().get(), "type"), + () -> assertEquals(SqlStatementType.WRITING, configuration.type().get(), "type"), () -> assertEquals(ReturningMode.NONE, configuration.returningMode().get(), "returningMode")); } @@ -92,7 +92,7 @@ class DefaultSqlConfigurationFactoryTest { // then assertAll("Configuration", () -> assertEquals("dropPersons", configuration.name().get(), "name"), - () -> assertEquals(SqlType.WRITING, configuration.type().get(), "type"), + () -> assertEquals(SqlStatementType.WRITING, configuration.type().get(), "type"), () -> assertEquals(ReturningMode.NONE, configuration.returningMode().get(), "returningMode")); } @@ -126,13 +126,13 @@ class DefaultSqlConfigurationFactoryTest { // then assertAll("Configuration", () -> assertEquals("findItemByName", configuration.name().get(), "name"), - () -> assertEquals(SqlType.READING, configuration.type().get(), "type"), + () -> assertEquals(SqlStatementType.READING, configuration.type().get(), "type"), () -> assertEquals(ReturningMode.MULTIPLE, configuration.returningMode().get(), "returningMode"), () -> assertTrue(configuration.resultRowConverter().isPresent(), "resultRowConverter"), - () -> assertEquals("itemConverter", configuration.resultRowConverter().get().alias(), "alias"), - () -> assertEquals("asUserType", configuration.resultRowConverter().get().methodName(), "methodName"), - () -> assertEquals("com.example.ItemConverter", configuration.resultRowConverter().get().converterType(), "converterType"), - () -> assertEquals("com.example.Item", configuration.resultRowConverter().get().resultType(), "resultType")); + () -> assertEquals("itemConverter", configuration.resultRowConverter().get().alias().get(), "alias"), + () -> assertEquals("asUserType", configuration.resultRowConverter().get().methodName().get(), "methodName"), + () -> assertEquals("com.example.ItemConverter", configuration.resultRowConverter().get().converterType().get(), "converterType"), + () -> assertEquals("com.example.Item", configuration.resultRowConverter().get().resultType().get(), "resultType")); } @Test @@ -171,20 +171,20 @@ class DefaultSqlConfigurationFactoryTest { // then assertAll("Configuration", () -> assertEquals("findItemByName", configuration.name().get(), "name"), - () -> assertEquals(SqlType.READING, configuration.type().get(), "type"), + () -> assertEquals(SqlStatementType.READING, configuration.type().get(), "type"), () -> assertEquals(ReturningMode.MULTIPLE, configuration.returningMode().get(), "returningMode"), () -> assertTrue(configuration.resultRowConverter().isPresent(), "resultRowConverter"), - () -> assertEquals("itemConverter", configuration.resultRowConverter().get().alias(), "alias"), - () -> assertEquals("asUserType", configuration.resultRowConverter().get().methodName(), "methodName"), - () -> assertEquals("com.example.ItemConverter", configuration.resultRowConverter().get().converterType(), "converterType"), - () -> assertEquals("com.example.Item", configuration.resultRowConverter().get().resultType(), "resultType")); + () -> assertEquals("itemConverter", configuration.resultRowConverter().get().alias().get(), "alias"), + () -> assertEquals("asUserType", configuration.resultRowConverter().get().methodName().get(), "methodName"), + () -> assertEquals("com.example.ItemConverter", configuration.resultRowConverter().get().converterType().get(), "converterType"), + () -> assertEquals("com.example.Item", configuration.resultRowConverter().get().resultType().get(), "resultType")); } - private SqlConfigurationFactory factory() { + private static SqlConfigurationFactory factory() { return factory(RuntimeConfigurations.defaults()); } - private SqlConfigurationFactory factory(final RuntimeConfiguration runtimeConfiguration) { + private static SqlConfigurationFactory factory(final RuntimeConfiguration runtimeConfiguration) { return FilesObjectMother.sqlConfigurationFactory( runtimeConfiguration.repositories(), runtimeConfiguration.converter()); diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParserTest.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParserTest.java index 271c4b78..5fe154f5 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParserTest.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/DefaultSqlConfigurationParserTest.java @@ -10,8 +10,9 @@ package wtf.metio.yosql.codegen.files; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import wtf.metio.yosql.codegen.orchestration.OrchestrationObjectMother; import wtf.metio.yosql.models.configuration.ReturningMode; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import static org.junit.jupiter.api.Assertions.*; @@ -22,7 +23,7 @@ class DefaultSqlConfigurationParserTest { @BeforeEach void setUp() { - parser = new DefaultSqlConfigurationParser(); + parser = new DefaultSqlConfigurationParser(OrchestrationObjectMother.executionErrors()); } @Test @@ -66,23 +67,13 @@ class DefaultSqlConfigurationParserTest { } @Test - void shouldParseTypeUnknown() { - final var yaml = """ - type: UNKNOWN - """; - final var config = parser.parseConfig(yaml); - assertTrue(config.type().isPresent()); - assertEquals(SqlType.UNKNOWN, config.type().get()); - } - - @Test void shouldParseTypeReading() { final var yaml = """ type: READING """; final var config = parser.parseConfig(yaml); assertTrue(config.type().isPresent()); - assertEquals(SqlType.READING, config.type().get()); + assertEquals(SqlStatementType.READING, config.type().get()); } @Test @@ -92,7 +83,7 @@ class DefaultSqlConfigurationParserTest { """; final var config = parser.parseConfig(yaml); assertTrue(config.type().isPresent()); - assertEquals(SqlType.WRITING, config.type().get()); + assertEquals(SqlStatementType.WRITING, config.type().get()); } @Test @@ -102,17 +93,7 @@ class DefaultSqlConfigurationParserTest { """; final var config = parser.parseConfig(yaml); assertTrue(config.type().isPresent()); - assertEquals(SqlType.CALLING, config.type().get()); - } - - @Test - void shouldParseTypeUnknownCaseInsensitive() { - final var yaml = """ - type: unknown - """; - final var config = parser.parseConfig(yaml); - assertTrue(config.type().isPresent()); - assertEquals(SqlType.UNKNOWN, config.type().get()); + assertEquals(SqlStatementType.CALLING, config.type().get()); } @Test @@ -122,7 +103,7 @@ class DefaultSqlConfigurationParserTest { """; final var config = parser.parseConfig(yaml); assertTrue(config.type().isPresent()); - assertEquals(SqlType.READING, config.type().get()); + assertEquals(SqlStatementType.READING, config.type().get()); } @Test @@ -132,7 +113,7 @@ class DefaultSqlConfigurationParserTest { """; final var config = parser.parseConfig(yaml); assertTrue(config.type().isPresent()); - assertEquals(SqlType.WRITING, config.type().get()); + assertEquals(SqlStatementType.WRITING, config.type().get()); } @Test @@ -142,7 +123,7 @@ class DefaultSqlConfigurationParserTest { """; final var config = parser.parseConfig(yaml); assertTrue(config.type().isPresent()); - assertEquals(SqlType.CALLING, config.type().get()); + assertEquals(SqlStatementType.CALLING, config.type().get()); } @Test @@ -335,8 +316,8 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertEquals(1, config.parameters().size()); assertAll( - () -> assertEquals("name", config.parameters().get(0).name()), - () -> assertEquals("java.lang.String", config.parameters().get(0).type())); + () -> assertEquals("name", config.parameters().get(0).name().get()), + () -> assertEquals("java.lang.String", config.parameters().get(0).type().get())); } @Test @@ -353,12 +334,12 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertEquals(3, config.parameters().size()); assertAll( - () -> assertEquals("string", config.parameters().get(0).name()), - () -> assertEquals("java.lang.String", config.parameters().get(0).type()), - () -> assertEquals("bool", config.parameters().get(1).name()), - () -> assertEquals("boolean", config.parameters().get(1).type()), - () -> assertEquals("number", config.parameters().get(2).name()), - () -> assertEquals("int", config.parameters().get(2).type())); + () -> assertEquals("string", config.parameters().get(0).name().get()), + () -> assertEquals("java.lang.String", config.parameters().get(0).type().get()), + () -> assertEquals("bool", config.parameters().get(1).name().get()), + () -> assertEquals("boolean", config.parameters().get(1).type().get()), + () -> assertEquals("number", config.parameters().get(2).name().get()), + () -> assertEquals("int", config.parameters().get(2).type().get())); } @Test @@ -370,10 +351,10 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertTrue(config.resultRowConverter().isPresent()); assertAll( - () -> assertEquals("converterAlias", config.resultRowConverter().get().alias()), - () -> assertEquals("", config.resultRowConverter().get().methodName()), - () -> assertEquals("", config.resultRowConverter().get().converterType()), - () -> assertEquals("", config.resultRowConverter().get().resultType())); + () -> assertEquals("converterAlias", config.resultRowConverter().get().alias().get()), + () -> assertTrue(config.resultRowConverter().get().methodName().isEmpty()), + () -> assertTrue(config.resultRowConverter().get().converterType().isEmpty()), + () -> assertTrue(config.resultRowConverter().get().resultType().isEmpty())); } @Test @@ -385,10 +366,10 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertTrue(config.resultRowConverter().isPresent()); assertAll( - () -> assertEquals("", config.resultRowConverter().get().alias()), - () -> assertEquals("someMethod", config.resultRowConverter().get().methodName()), - () -> assertEquals("", config.resultRowConverter().get().converterType()), - () -> assertEquals("", config.resultRowConverter().get().resultType())); + () -> assertTrue(config.resultRowConverter().get().alias().isEmpty()), + () -> assertEquals("someMethod", config.resultRowConverter().get().methodName().get()), + () -> assertTrue(config.resultRowConverter().get().converterType().isEmpty()), + () -> assertTrue(config.resultRowConverter().get().resultType().isEmpty())); } @Test @@ -400,10 +381,10 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertTrue(config.resultRowConverter().isPresent()); assertAll( - () -> assertEquals("", config.resultRowConverter().get().alias()), - () -> assertEquals("", config.resultRowConverter().get().methodName()), - () -> assertEquals("com.example.MyConverter", config.resultRowConverter().get().converterType()), - () -> assertEquals("", config.resultRowConverter().get().resultType())); + () -> assertTrue(config.resultRowConverter().get().alias().isEmpty()), + () -> assertTrue(config.resultRowConverter().get().methodName().isEmpty()), + () -> assertEquals("com.example.MyConverter", config.resultRowConverter().get().converterType().get()), + () -> assertTrue(config.resultRowConverter().get().resultType().isEmpty())); } @Test @@ -415,10 +396,10 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertTrue(config.resultRowConverter().isPresent()); assertAll( - () -> assertEquals("", config.resultRowConverter().get().alias()), - () -> assertEquals("", config.resultRowConverter().get().methodName()), - () -> assertEquals("", config.resultRowConverter().get().converterType()), - () -> assertEquals("com.example.MyResult", config.resultRowConverter().get().resultType())); + () -> assertTrue(config.resultRowConverter().get().alias().isEmpty()), + () -> assertTrue(config.resultRowConverter().get().methodName().isEmpty()), + () -> assertTrue(config.resultRowConverter().get().converterType().isEmpty()), + () -> assertEquals("com.example.MyResult", config.resultRowConverter().get().resultType().get())); } @Test @@ -433,10 +414,88 @@ class DefaultSqlConfigurationParserTest { final var config = parser.parseConfig(yaml); assertTrue(config.resultRowConverter().isPresent()); assertAll( - () -> assertEquals("converterAlias", config.resultRowConverter().get().alias()), - () -> assertEquals("someMethod", config.resultRowConverter().get().methodName()), - () -> assertEquals("com.example.MyConverter", config.resultRowConverter().get().converterType()), - () -> assertEquals("com.example.MyResult", config.resultRowConverter().get().resultType())); + () -> assertEquals("converterAlias", config.resultRowConverter().get().alias().get()), + () -> assertEquals("someMethod", config.resultRowConverter().get().methodName().get()), + () -> assertEquals("com.example.MyConverter", config.resultRowConverter().get().converterType().get()), + () -> assertEquals("com.example.MyResult", config.resultRowConverter().get().resultType().get())); + } + + @Test + void shouldParseAnnotation() { + final var yaml = """ + annotations: + - type: com.example.MyAnnotation + members: + - key: some + value: here + type: java.lang.String + """; + final var config = parser.parseConfig(yaml); + assertFalse(config.annotations().isEmpty()); + assertAll("annotation", + () -> assertEquals("com.example.MyAnnotation", config.annotations().get(0).type()), + () -> assertAll("members", + () -> assertFalse(config.annotations().get(0).members().isEmpty()), + () -> assertEquals("some", config.annotations().get(0).members().get(0).key()), + () -> assertEquals("here", config.annotations().get(0).members().get(0).value()), + () -> assertEquals("java.lang.String", config.annotations().get(0).members().get(0).type()))); + } + + @Test + void shouldParseAnnotations() { + final var yaml = """ + annotations: + - type: com.example.MyAnnotation + members: + - key: some + value: here + type: java.lang.String + - type: com.example.OtherAnnotation + members: + - key: another + value: 12345 + type: int + """; + final var config = parser.parseConfig(yaml); + assertFalse(config.annotations().isEmpty()); + assertAll("annotation", + () -> assertEquals("com.example.MyAnnotation", config.annotations().get(0).type()), + () -> assertEquals("com.example.OtherAnnotation", config.annotations().get(1).type()), + () -> assertAll("members", + () -> assertFalse(config.annotations().get(0).members().isEmpty()), + () -> assertEquals("some", config.annotations().get(0).members().get(0).key()), + () -> assertEquals("here", config.annotations().get(0).members().get(0).value()), + () -> assertEquals("java.lang.String", config.annotations().get(0).members().get(0).type()), + () -> assertEquals("another", config.annotations().get(1).members().get(0).key()), + () -> assertEquals("12345", config.annotations().get(1).members().get(0).value()), + () -> assertEquals("int", config.annotations().get(1).members().get(0).type()))); + } + + @Test + void shouldParseAnnotationMembers() { + final var yaml = """ + annotations: + - type: com.example.MyAnnotation + members: + - key: some + value: here + type: java.lang.String + - key: another + value: 12345 + type: int + """; + final var config = parser.parseConfig(yaml); + assertFalse(config.annotations().isEmpty()); + assertAll("annotation", + () -> assertEquals("com.example.MyAnnotation", config.annotations().get(0).type()), + () -> assertAll("members", + () -> assertFalse(config.annotations().get(0).members().isEmpty()), + () -> assertEquals("some", config.annotations().get(0).members().get(0).key()), + () -> assertEquals("here", config.annotations().get(0).members().get(0).value()), + () -> assertEquals("java.lang.String", config.annotations().get(0).members().get(0).type()), + () -> assertEquals("another", config.annotations().get(0).members().get(1).key()), + () -> assertEquals("12345", config.annotations().get(0).members().get(1).value()), + () -> assertEquals("int", config.annotations().get(0).members().get(1).type()))); } } diff --git a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/FilesObjectMother.java b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/FilesObjectMother.java index e38e14e6..9075bc9a 100644 --- a/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/FilesObjectMother.java +++ b/yosql-codegen/src/test/java/wtf/metio/yosql/codegen/files/FilesObjectMother.java @@ -44,8 +44,8 @@ public final class FilesObjectMother { LoggingObjectMother.messages()); } - public static MethodConverterConfigurer methodConverterConfigurer(final ConverterConfiguration converter) { - return new DefaultMethodConverterConfigurer(converter); + public static MethodResultRowConverterConfigurer methodConverterConfigurer(final ConverterConfiguration converter) { + return new DefaultMethodResultRowConverterConfigurer(converter); } public static RepositoryNameConfigurer repositoryNameConfigurer(final RepositoriesConfiguration repositories) { @@ -56,7 +56,7 @@ public final class FilesObjectMother { } public static SqlConfigurationParser sqlConfigurationParser() { - return new DefaultSqlConfigurationParser(); + return new DefaultSqlConfigurationParser(OrchestrationObjectMother.executionErrors()); } public static SqlConfigurationFactory sqlConfigurationFactory( diff --git a/yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql b/yosql-examples/yosql-examples-common/src/main/java/wtf/metio/yosql/example/common/CustomAnnotation.java similarity index 82% copy from yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql copy to yosql-examples/yosql-examples-common/src/main/java/wtf/metio/yosql/example/common/CustomAnnotation.java index 64793037..b9a1b43f 100644 --- a/yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql +++ b/yosql-examples/yosql-examples-common/src/main/java/wtf/metio/yosql/example/common/CustomAnnotation.java @@ -5,8 +5,7 @@ * in the LICENSE file. */ --- --- -select * -from companies -; +package wtf.metio.yosql.example.common; + +public @interface CustomAnnotation { +} diff --git a/yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql b/yosql-examples/yosql-examples-common/src/main/java/wtf/metio/yosql/example/common/CustomAnnotationWithData.java similarity index 57% copy from yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql copy to yosql-examples/yosql-examples-common/src/main/java/wtf/metio/yosql/example/common/CustomAnnotationWithData.java index 34eeae22..bb4b2200 100644 --- a/yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql +++ b/yosql-examples/yosql-examples-common/src/main/java/wtf/metio/yosql/example/common/CustomAnnotationWithData.java @@ -5,15 +5,17 @@ * in the LICENSE file. */ --- --- parameters: --- - name: min --- type: int --- - name: max --- type: int --- -select * -from companies -where id < :max - and id > :min -; +package wtf.metio.yosql.example.common; + +public @interface CustomAnnotationWithData { + + char someChar(); + boolean someBool(); + byte someByte(); + short someShort(); + int someInt(); + long someLong(); + float someFloat(); + double someDouble(); + +} diff --git a/yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql b/yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql index 34eeae22..e0786c21 100644 --- a/yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql +++ b/yosql-examples/yosql-examples-common/src/main/yosql/company/findCompanies.sql @@ -11,9 +11,11 @@ -- type: int -- - name: max -- type: int +-- annotations: +-- - type: wtf.metio.yosql.example.common.CustomAnnotation -- select * -from companies -where id < :max - and id > :min +from companies +where id < :max + and id > :min ; diff --git a/yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql b/yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql index 64793037..31459d71 100644 --- a/yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql +++ b/yosql-examples/yosql-examples-common/src/main/yosql/company/queryAllCompanies.sql @@ -6,6 +6,33 @@ */ -- +-- annotations: +-- - type: wtf.metio.yosql.example.common.CustomAnnotationWithData +-- members: +-- - key: someChar +-- value: a +-- type: char +-- - key: someBool +-- value: true +-- type: boolean +-- - key: someByte +-- value: 123 +-- type: byte +-- - key: someShort +-- value: 123 +-- type: short +-- - key: someInt +-- value: 123 +-- type: int +-- - key: someLong +-- value: 123 +-- type: long +-- - key: someFloat +-- value: 3.14f +-- type: float +-- - key: someDouble +-- value: 3.14 +-- type: double -- select * from companies diff --git a/yosql-examples/yosql-examples-gradle/yosql-examples-gradle-jdbc-java8/build.gradle.kts b/yosql-examples/yosql-examples-gradle/yosql-examples-gradle-jdbc-java8/build.gradle.kts index 3019303e..fe5cd0e8 100644 --- a/yosql-examples/yosql-examples-gradle/yosql-examples-gradle-jdbc-java8/build.gradle.kts +++ b/yosql-examples/yosql-examples-gradle/yosql-examples-gradle-jdbc-java8/build.gradle.kts @@ -29,6 +29,20 @@ yosql { useTextBlocks.set(false) useVar.set(false) } + annotations { + repositoryAnnotations { + register("javax.inject.Singleton") + } + constructorAnnotations { + register("javax.inject.Named") { + members { + register("value") { + value.set("Something") + } + } + } + } + } converter { mapConverterClass.set("${group}.converter.ToMapConverter") rowConverters { @@ -48,4 +62,7 @@ dependencies { implementation("wtf.metio.yosql.examples:yosql-examples-common:${version}") { because("we want to re-use the same example app across all example projects") } + implementation("javax.inject:javax.inject:1") { + because("we want to showcase annotations on classes/methods") + } } diff --git a/yosql-examples/yosql-examples-maven/yosql-examples-maven-jdbc-java8/pom.xml b/yosql-examples/yosql-examples-maven/yosql-examples-maven-jdbc-java8/pom.xml index f2284ded..b9390d2f 100644 --- a/yosql-examples/yosql-examples-maven/yosql-examples-maven-jdbc-java8/pom.xml +++ b/yosql-examples/yosql-examples-maven/yosql-examples-maven-jdbc-java8/pom.xml @@ -44,6 +44,11 @@ yosql-examples-common ${project.version} + + javax.inject + javax.inject + 1 + @@ -61,6 +66,32 @@ false false + + + + javax.inject.Singleton + + + + + javax.inject.Inject + + + javax.inject.Named + + + value + Something + + + + + + + javax.inject.Inject + + + wtf.metio.yosql.example.maven.jdbc.java8.persistence true diff --git a/yosql-internals/yosql-internals-javapoet-utils/src/main/java/wtf/metio/yosql/internals/javapoet/TypicalTypes.java b/yosql-internals/yosql-internals-javapoet-utils/src/main/java/wtf/metio/yosql/internals/javapoet/TypicalTypes.java index 7ad73b36..254f3107 100644 --- a/yosql-internals/yosql-internals-javapoet-utils/src/main/java/wtf/metio/yosql/internals/javapoet/TypicalTypes.java +++ b/yosql-internals/yosql-internals-javapoet-utils/src/main/java/wtf/metio/yosql/internals/javapoet/TypicalTypes.java @@ -21,16 +21,19 @@ public final class TypicalTypes { public static final ClassName INJECT = ClassName.get("javax.inject", "Inject"); + public static final ClassName MAVEN_PARAMETER = ClassName.get("org.apache.maven.plugins.annotations", "Parameter"); + public static final ClassName GRADLE_PROPERTY = ClassName.get("org.gradle.api.provider", "Property"); - public static final ClassName GRADLE_LIST_PROPERTY = ClassName.bestGuess("org.gradle.api.provider.ListProperty"); - public static final ClassName GRADLE_INPUT = ClassName.bestGuess("org.gradle.api.tasks.Input"); - public static final ClassName GRADLE_INPUT_DIRECTORY = ClassName.bestGuess("org.gradle.api.tasks.InputDirectory"); - public static final ClassName GRADLE_OUTPUT_DIRECTORY = ClassName.bestGuess("org.gradle.api.tasks.OutputDirectory"); - public static final ClassName GRADLE_CONTAINERS = ClassName.bestGuess("org.gradle.api.NamedDomainObjectContainer"); - public static final ClassName GRADLE_DIRECTORY = ClassName.bestGuess("org.gradle.api.file.DirectoryProperty"); - public static final ClassName GRADLE_LAYOUT = ClassName.bestGuess("org.gradle.api.file.ProjectLayout"); - public static final ClassName GRADLE_OBJECTS = ClassName.bestGuess("org.gradle.api.model.ObjectFactory"); - public static final ClassName GRADLE_NAMED = ClassName.bestGuess("org.gradle.api.Named"); + public static final ClassName GRADLE_LIST_PROPERTY = ClassName.get("org.gradle.api.provider", "ListProperty"); + public static final ClassName GRADLE_INPUT = ClassName.get("org.gradle.api.tasks", "Input"); + public static final ClassName GRADLE_INPUT_DIRECTORY = ClassName.get("org.gradle.api.tasks", "InputDirectory"); + public static final ClassName GRADLE_OUTPUT_DIRECTORY = ClassName.get("org.gradle.api.tasks", "OutputDirectory"); + public static final ClassName GRADLE_CONTAINERS = ClassName.get("org.gradle.api", "NamedDomainObjectContainer"); + public static final ClassName GRADLE_DIRECTORY = ClassName.get("org.gradle.api.file", "DirectoryProperty"); + public static final ClassName GRADLE_LAYOUT = ClassName.get("org.gradle.api.file", "ProjectLayout"); + public static final ClassName GRADLE_OBJECTS = ClassName.get("org.gradle.api.model", "ObjectFactory"); + public static final ClassName GRADLE_NAMED = ClassName.get("org.gradle.api", "Named"); + public static final TypeName GRADLE_STRING_PROPERTY = gradlePropertyOf(ClassName.get(String.class)); public static final TypeName ARRAY_OF_INTS = ArrayTypeName.of(int.class); diff --git a/yosql-internals/yosql-internals-jdk-utils/src/main/java/wtf/metio/yosql/internals/jdk/Buckets.java b/yosql-internals/yosql-internals-jdk-utils/src/main/java/wtf/metio/yosql/internals/jdk/Buckets.java index e16a2e2e..0024d107 100644 --- a/yosql-internals/yosql-internals-jdk-utils/src/main/java/wtf/metio/yosql/internals/jdk/Buckets.java +++ b/yosql-internals/yosql-internals-jdk-utils/src/main/java/wtf/metio/yosql/internals/jdk/Buckets.java @@ -8,10 +8,14 @@ package wtf.metio.yosql.internals.jdk; import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; /** - * Utility methods that handle {@link java.util.Collection Collections}. The class is called "Buckets" because - * "Collections" is way too common. + * Utility methods that handle {@link Collection collections} and {@link Stream streams}. The class is called "Buckets" + * because 'Collections' is way too common. */ public final class Buckets { @@ -23,6 +27,18 @@ public final class Buckets { return collection != null && !collection.isEmpty(); } + /** + * Allows to use {@link Stream#distinct()} with a key. + * + * @param keyExtractor The function to extract the key from an object. + * @return A filter to use with @{@link Stream#filter(Predicate)}. + * @param The type of the object in the stream. + */ + public static Predicate distinctByKey(final Function keyExtractor) { + final var seen = ConcurrentHashMap.newKeySet(); + return object -> seen.add(keyExtractor.apply(object)); + } + private Buckets() { // utility class } diff --git a/yosql-models/yosql-models-configuration/pom.xml b/yosql-models/yosql-models-configuration/pom.xml index 8ad7ff02..80740c13 100644 --- a/yosql-models/yosql-models-configuration/pom.xml +++ b/yosql-models/yosql-models-configuration/pom.xml @@ -40,11 +40,21 @@ + wtf.metio.yosql.internals + yosql-internals-jdk-utils + ${project.version} + + + org.immutables value provided + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + com.squareup javapoet diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/Annotation.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/Annotation.java new file mode 100644 index 00000000..0a90802d --- /dev/null +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/Annotation.java @@ -0,0 +1,90 @@ +/* + * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, + * including this file, may be copied, modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ +package wtf.metio.yosql.models.configuration; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.immutables.value.Value; +import wtf.metio.yosql.internals.jdk.Buckets; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Configuration for an extra annotation that is to be placed on a constructor or method in generated code. + */ +@Value.Immutable +@JsonSerialize( + as = ImmutableAnnotation.class +) +@JsonDeserialize( + as = ImmutableAnnotation.class +) +public interface Annotation { + + //region builders + + static ImmutableAnnotation.TypeBuildStage builder() { + return ImmutableAnnotation.builder(); + } + + static ImmutableAnnotation copyOf(final Annotation annotation) { + return ImmutableAnnotation.copyOf(annotation); + } + + //endregion + + //region utils + + static List mergeAnnotations( + final List first, + final List second) { + if (first == null || first.isEmpty()) { + return second; + } + return Stream.concat(copyAttributes(first, second), copyAttributes(second, first)) + .filter(Buckets.distinctByKey(Annotation::type)) + .collect(Collectors.toList()); + } + + private static Stream copyAttributes( + final List first, + final List second) { + return first.stream() + .map(annotation -> second.stream() + .filter(other -> annotation.type().equals(other.type())) + .findFirst() + .map(other -> Annotation.copyOf(annotation) + .withMembers(mergeMembers(annotation.members(), other.members()))) + .orElseGet(() -> Annotation.copyOf(annotation))); + } + + private static List mergeMembers( + final List first, + final List second) { + if (first == null || first.isEmpty()) { + return second; + } + return Stream.concat(first.stream(), second.stream()) + .filter(Buckets.distinctByKey(AnnotationMember::key)) + .collect(Collectors.toList()); + } + + //endregion + + /** + * @return The fully-qualified type name of this annotation. + */ + String type(); + + /** + * @return The members of this annotation. + */ + List members(); + +} diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMember.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMember.java new file mode 100644 index 00000000..db7bdebb --- /dev/null +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMember.java @@ -0,0 +1,55 @@ +/* + * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, + * including this file, may be copied, modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ +package wtf.metio.yosql.models.configuration; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.immutables.value.Value; + +/** + * Configuration for annotation members that are placed on a constructor or method in generated code. + */ +@Value.Immutable +@JsonSerialize( + as = ImmutableAnnotationMember.class +) +@JsonDeserialize( + as = ImmutableAnnotationMember.class +) +public interface AnnotationMember { + + //region builders + + static ImmutableAnnotationMember.KeyBuildStage builder() { + return ImmutableAnnotationMember.builder(); + } + + static ImmutableAnnotationMember copyOf(final AnnotationMember member) { + return ImmutableAnnotationMember.copyOf(member); + } + + //endregion + + /** + * @return The key or name of the annotation member. + */ + String key(); + + /** + * @return The value of the annotation member. + */ + String value(); + + /** + * @return The fully-qualified type of the annotation member. + */ + @Value.Default + default String type() { + return "java.lang.String"; + } + +} diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationApis.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/GeneratedAnnotationApis.java similarity index 79% rename from yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationApis.java rename to yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/GeneratedAnnotationApis.java index e92a9c23..ffdaad1c 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationApis.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/GeneratedAnnotationApis.java @@ -9,12 +9,7 @@ package wtf.metio.yosql.models.configuration; /** * Options for the logging API used in the generated code. */ -public enum AnnotationApis { - - /** - * Automatically select an appropriate implementation based on project metadata. - */ - AUTO("please.report.this.bug"), +public enum GeneratedAnnotationApis { /** * Uses the javax.annotation API. @@ -28,7 +23,7 @@ public enum AnnotationApis { public final String annotationClass; - AnnotationApis(String annotationClass) { + GeneratedAnnotationApis(String annotationClass) { this.annotationClass = annotationClass; } diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMembers.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/GeneratedAnnotationMembers.java similarity index 95% rename from yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMembers.java rename to yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/GeneratedAnnotationMembers.java index 60f9530c..68450646 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/AnnotationMembers.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/GeneratedAnnotationMembers.java @@ -10,7 +10,7 @@ package wtf.metio.yosql.models.configuration; /** * Options for members of the "@Generated" annotation. */ -public enum AnnotationMembers { +public enum GeneratedAnnotationMembers { /** * Use all available annotation members. diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/LoggingApis.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/LoggingApis.java index fae9f596..44572312 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/LoggingApis.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/LoggingApis.java @@ -12,11 +12,6 @@ package wtf.metio.yosql.models.configuration; public enum LoggingApis { /** - * Automatically select an appropriate implementation based on project metadata. - */ - AUTO, - - /** * Disables logging in any of the generated files. */ NONE, diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ParameterConverter.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ParameterConverter.java index 1000658a..652487c7 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ParameterConverter.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ParameterConverter.java @@ -6,9 +6,17 @@ */ package wtf.metio.yosql.models.configuration; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.immutables.value.Value; @Value.Immutable +@JsonSerialize( + as = ImmutableParameterConverter.class +) +@JsonDeserialize( + as = ImmutableParameterConverter.class +) public interface ParameterConverter { static ImmutableParameterConverter.AliasBuildStage builder() { diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ResultRowConverter.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ResultRowConverter.java index 480902ab..cf6aed84 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ResultRowConverter.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/ResultRowConverter.java @@ -6,28 +6,63 @@ */ package wtf.metio.yosql.models.configuration; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.squareup.javapoet.TypeName; import de.xn__ho_hia.javapoet.TypeGuesser; import org.immutables.value.Value; +import java.util.Optional; + @Value.Immutable +@JsonSerialize( + as = ImmutableResultRowConverter.class +) +@JsonDeserialize( + as = ImmutableResultRowConverter.class +) public interface ResultRowConverter { - static ImmutableResultRowConverter.AliasBuildStage builder() { + //region builders + + static ImmutableResultRowConverter.Builder builder() { return ImmutableResultRowConverter.builder(); } - String alias(); + //endregion + + /** + * @return The (short) alias of this converter. + */ + Optional alias(); + + /** + * @return The fully-qualified type name of this converter. + */ + Optional converterType(); - String converterType(); + /** + * @return The name of the method to use while converting values. + */ + Optional methodName(); - String methodName(); + /** + * @return The fully-qualified result type of this converter. + */ + Optional resultType(); - String resultType(); + //region derived @Value.Lazy - default TypeName resultTypeName() { - return TypeGuesser.guessTypeName(resultType()); + default Optional resultTypeName() { + return resultType().map(TypeGuesser::guessTypeName); } + @Value.Lazy + default Optional converterTypeName() { + return converterType().map(TypeGuesser::guessTypeName); + } + + //endregion + } diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlParameter.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlParameter.java index d4868fc9..c00990d8 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlParameter.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlParameter.java @@ -6,33 +6,79 @@ */ package wtf.metio.yosql.models.configuration; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.squareup.javapoet.TypeName; +import de.xn__ho_hia.javapoet.TypeGuesser; import org.immutables.value.Value; +import wtf.metio.yosql.internals.jdk.Buckets; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Represents a single input parameter of a SQL statement. */ @Value.Immutable +@JsonSerialize( + as = ImmutableSqlParameter.class +) +@JsonDeserialize( + as = ImmutableSqlParameter.class +) public interface SqlParameter { - static ImmutableSqlParameter.NameBuildStage builder() { + //region builders + + static ImmutableSqlParameter.Builder builder() { return ImmutableSqlParameter.builder(); } - static ImmutableSqlParameter copy(final SqlParameter parameter) { + static ImmutableSqlParameter copyOf(final SqlParameter parameter) { return ImmutableSqlParameter.copyOf(parameter); } + //endregion + + //region utils + + static List mergeParameters( + final List first, + final List second) { + if (first == null || first.isEmpty()) { + return second; + } + return Stream.concat(copyAttributes(first, second), copyAttributes(second, first)) + .filter(Buckets.distinctByKey(SqlParameter::name)) + .collect(Collectors.toList()); + } + + private static Stream copyAttributes(final List first, final List second) { + return first.stream() + .map(param -> second.stream() + .filter(other -> param.name().equals(other.name())) + .findFirst() + .map(other -> SqlParameter.copyOf(param) + .withType(param.type().or(other::type)) + .withIndices(param.indices().or(other::indices)) + .withConverter(param.converter().or(other::converter))) + .orElseGet(() -> SqlParameter.copyOf(param))); + } + + //endregion + /** * @return The name of the parameter. */ - String name(); + Optional name(); /** * @return The fully-qualified type name. */ - String type(); + Optional type(); /** * @return The fully-qualified name of the converter to use. @@ -42,14 +88,28 @@ public interface SqlParameter { /** * @return The indices in the SQL statement that match this parameter. */ - int[] indices(); - + @JsonIgnore + Optional indices(); + + // TODO: add parameter type (in, out, inout) + // TODO: add sql type (see java.sql.Types) + // TODO: add scale for sql numeric/decimal types + + //region derived + + @Value.Lazy + default Optional typeName() { + return type().map(TypeGuesser::guessTypeName); + } + /** * @return true in case this statement has indices, false otherwise. */ @Value.Lazy default boolean hasIndices() { - return indices() != null && indices().length > 0; + return indices().map(values -> values.length > 0).orElse(Boolean.FALSE); } + //endregion + } diff --git a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlType.java b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlStatementType.java similarity index 89% rename from yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlType.java rename to yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlStatementType.java index 0f9d87c1..3a441c05 100644 --- a/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlType.java +++ b/yosql-models/yosql-models-configuration/src/main/java/wtf/metio/yosql/models/configuration/SqlStatementType.java @@ -9,7 +9,7 @@ package wtf.metio.yosql.models.configuration; /** * Enumeration of possible SQL statement types. */ -public enum SqlType { +public enum SqlStatementType { /** * Statement reads data from a database. @@ -26,9 +26,4 @@ public enum SqlType { */ CALLING, - /** - * Statement type is unknown. - */ - UNKNOWN - } diff --git a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/AnnotationTest.java b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/AnnotationTest.java new file mode 100644 index 00000000..023bbb57 --- /dev/null +++ b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/AnnotationTest.java @@ -0,0 +1,79 @@ +/* + * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, + * including this file, may be copied, modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +package wtf.metio.yosql.models.configuration; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +class AnnotationTest { + + @Test + void mergeAnnotationsFirst() { + final List first = List.of(Annotation.builder().setType("com.example.MyAnnotation").build()); + final List second = List.of(); + + final var merged = Annotation.mergeAnnotations(first, second); + + assertIterableEquals(first, merged); + } + + @Test + void mergeAnnotationsSecond() { + final List first = List.of(); + final List second = List.of(Annotation.builder().setType("com.example.MyAnnotation").build()); + + final var merged = Annotation.mergeAnnotations(first, second); + + assertIterableEquals(second, merged); + } + + @Test + void mergeAnnotationsDuplicates() { + final List first = List.of(Annotation.builder().setType("com.example.MyAnnotation").build()); + final List second = List.of(Annotation.builder().setType("com.example.MyAnnotation").build()); + + final var merged = Annotation.mergeAnnotations(first, second); + + assertIterableEquals(first, merged); + assertIterableEquals(second, merged); + } + + @Test + void mergeAnnotationsWithMembersFirst() { + final List first = List.of(Annotation.builder() + .setType("com.example.MyAnnotation") + .addMembers(AnnotationMember.builder().setKey("value").setValue("some").build()) + .build()); + final List second = List.of(Annotation.builder() + .setType("com.example.MyAnnotation") + .build()); + + final var merged = Annotation.mergeAnnotations(first, second); + + assertIterableEquals(first, merged); + } + + @Test + void mergeAnnotationsWithMembersSecond() { + final List first = List.of(Annotation.builder() + .setType("com.example.MyAnnotation") + .build()); + final List second = List.of(Annotation.builder() + .setType("com.example.MyAnnotation") + .addMembers(AnnotationMember.builder().setKey("value").setValue("some").build()) + .build()); + + final var merged = Annotation.mergeAnnotations(first, second); + + assertIterableEquals(second, merged); + } + +} diff --git a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/SqlParameterTest.java b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/SqlParameterTest.java new file mode 100644 index 00000000..8422067b --- /dev/null +++ b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/configuration/SqlParameterTest.java @@ -0,0 +1,174 @@ +/* + * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, + * including this file, may be copied, modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +package wtf.metio.yosql.models.configuration; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +class SqlParameterTest { + + @Test + void mergeParametersFirst() { + final List first = List.of(SqlParameter.builder().setName("first").build()); + final List second = List.of(); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertIterableEquals(first, merged); + } + + @Test + void mergeParametersSecond() { + final List first = List.of(); + final List second = List.of(SqlParameter.builder().setName("second").build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertIterableEquals(second, merged); + } + + @Test + void mergeParametersMixed() { + final List parameters = List.of( + SqlParameter.builder().setName("first").build(), + SqlParameter.builder().setName("second").build()); + final List first = List.of(SqlParameter.builder().setName("first").build()); + final List second = List.of(SqlParameter.builder().setName("second").build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertIterableEquals(parameters, merged); + } + + @Test + void mergeParametersMixedDuplicatedFirst() { + final List parameters = List.of( + SqlParameter.builder().setName("first").build(), + SqlParameter.builder().setName("second").build()); + final List first = List.of(SqlParameter.builder().setName("first").build()); + + final var merged = SqlParameter.mergeParameters(parameters, first); + + assertIterableEquals(parameters, merged); + } + + @Test + void mergeParametersMixedDuplicatedSecond() { + final List parameters = List.of( + SqlParameter.builder().setName("first").build(), + SqlParameter.builder().setName("second").build()); + final List second = List.of(SqlParameter.builder().setName("second").build()); + + final var merged = SqlParameter.mergeParameters(parameters, second); + + assertIterableEquals(parameters, merged); + } + + @Test + void mergeParametersDuplicated() { + final List first = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build()); + final List second = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertEquals(1, merged.size()); + assertEquals("name", merged.get(0).name().orElse("")); + assertEquals("java.lang.String", merged.get(0).type().orElse("")); + } + + @Test + void mergeParametersDuplicatedNamesMissingTypeFirst() { + final List first = List.of(SqlParameter.builder() + .setName("name") + .setIndices(new int[]{1}) + .build()); + final List second = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertEquals(1, merged.size()); + assertEquals("name", merged.get(0).name().orElse("")); + assertEquals("java.lang.String", merged.get(0).type().orElse("")); + } + + @Test + void mergeParametersDuplicatedNamesMissingTypeSecond() { + final List first = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build()); + final List second = List.of(SqlParameter.builder() + .setName("name") + .setIndices(new int[]{1}) + .build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertEquals(1, merged.size()); + assertEquals("name", merged.get(0).name().orElse("")); + assertEquals("java.lang.String", merged.get(0).type().orElse("")); + } + + @Test + void mergeParametersDuplicatedNamesMissingIndicesFirst() { + final List first = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .build()); + final List second = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{7}) + .build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertEquals(1, merged.size()); + assertEquals("name", merged.get(0).name().orElse("")); + assertEquals("java.lang.String", merged.get(0).type().orElse("")); + assertEquals(7, merged.get(0).indices().orElseThrow()[0]); + } + + @Test + void mergeParametersDuplicatedNamesMissingIndicesSecond() { + final List first = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{7}) + .build()); + final List second = List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .build()); + + final var merged = SqlParameter.mergeParameters(first, second); + + assertEquals(1, merged.size()); + assertEquals("name", merged.get(0).name().orElse("")); + assertEquals("java.lang.String", merged.get(0).type().orElse("")); + assertEquals(7, merged.get(0).indices().orElseThrow()[0]); + } + +} diff --git a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/AnnotationApisTest.java b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/GeneratedAnnotationApisTest.java similarity index 64% rename from yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/AnnotationApisTest.java rename to yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/GeneratedAnnotationApisTest.java index ac40ee15..c44064c9 100644 --- a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/AnnotationApisTest.java +++ b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/GeneratedAnnotationApisTest.java @@ -8,20 +8,20 @@ package wtf.metio.yosql.models.constants.api; import wtf.metio.yosql.internals.junit5.EnumTCK; -import wtf.metio.yosql.models.configuration.AnnotationApis; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationApis; import java.util.stream.Stream; -class AnnotationApisTest implements EnumTCK { +class GeneratedAnnotationApisTest implements EnumTCK { @Override - public Class getEnumClass() { - return AnnotationApis.class; + public Class getEnumClass() { + return GeneratedAnnotationApis.class; } @Override public Stream validValues() { - return Stream.of("AUTO", "ANNOTATION_API", "PROCESSING_API"); + return Stream.of("ANNOTATION_API", "PROCESSING_API"); } } diff --git a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/LoggingApisTest.java b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/LoggingApisTest.java index 53d870fb..ed21fdaa 100644 --- a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/LoggingApisTest.java +++ b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/api/LoggingApisTest.java @@ -21,7 +21,7 @@ final class LoggingApisTest implements EnumTCK { @Override public Stream validValues() { - return Stream.of("AUTO", "NONE", "JUL", "SYSTEM", "LOG4J", "SLF4J", "TI", "TINYLOG"); + return Stream.of("NONE", "JUL", "SYSTEM", "LOG4J", "SLF4J", "TI", "TINYLOG"); } } diff --git a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/AnnotationMembersTest.java b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/GeneratedAnnotationMembersTest.java similarity index 71% rename from yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/AnnotationMembersTest.java rename to yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/GeneratedAnnotationMembersTest.java index e3c7140d..b00ab5e1 100644 --- a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/AnnotationMembersTest.java +++ b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/configuration/GeneratedAnnotationMembersTest.java @@ -8,15 +8,15 @@ package wtf.metio.yosql.models.constants.configuration; import wtf.metio.yosql.internals.junit5.EnumTCK; -import wtf.metio.yosql.models.configuration.AnnotationMembers; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationMembers; import java.util.stream.Stream; -final class AnnotationMembersTest implements EnumTCK { +final class GeneratedAnnotationMembersTest implements EnumTCK { @Override - public Class getEnumClass() { - return AnnotationMembers.class; + public Class getEnumClass() { + return GeneratedAnnotationMembers.class; } @Override diff --git a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/SqlTypeTest.java b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/SqlStatementTypeTest.java similarity index 71% rename from yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/SqlTypeTest.java rename to yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/SqlStatementTypeTest.java index 27b64edd..5f3a5867 100644 --- a/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/SqlTypeTest.java +++ b/yosql-models/yosql-models-configuration/src/test/java/wtf/metio/yosql/models/constants/sql/SqlStatementTypeTest.java @@ -8,20 +8,20 @@ package wtf.metio.yosql.models.constants.sql; import wtf.metio.yosql.internals.junit5.EnumTCK; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import java.util.stream.Stream; -final class SqlTypeTest implements EnumTCK { +final class SqlStatementTypeTest implements EnumTCK { @Override - public Class getEnumClass() { - return SqlType.class; + public Class getEnumClass() { + return SqlStatementType.class; } @Override public Stream validValues() { - return Stream.of("READING", "WRITING", "CALLING", "UNKNOWN"); + return Stream.of("READING", "WRITING", "CALLING"); } @Override diff --git a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/AbstractFieldsBasedGenerator.java b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/AbstractFieldsBasedGenerator.java index 73606b7b..7970bfb9 100644 --- a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/AbstractFieldsBasedGenerator.java +++ b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/AbstractFieldsBasedGenerator.java @@ -92,6 +92,11 @@ public abstract class AbstractFieldsBasedGenerator implements Generator { .add(".set$L($T.forName($L))\n", Strings.upperCase(setting.name()), Charset.class, setting.name()) .build(); } + if (usesAnnotations(setting)) { + return CodeBlock.builder() + .add(".set$L(createAnnotations($L))\n", Strings.upperCase(setting.name()), setting.name()) + .build(); + } return CodeBlock.of(".set$L($L)\n", Strings.upperCase(setting.name()), setting.name()); } diff --git a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/Generator.java b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/Generator.java index bda01e2e..848a802b 100644 --- a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/Generator.java +++ b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/Generator.java @@ -9,6 +9,7 @@ package wtf.metio.yosql.model.generator; import com.squareup.javapoet.*; import wtf.metio.yosql.internals.javapoet.TypicalTypes; +import wtf.metio.yosql.models.configuration.Annotation; import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.meta.ConfigurationGroup; import wtf.metio.yosql.models.meta.ConfigurationSetting; @@ -83,4 +84,8 @@ public interface Generator extends Function return setting.type().equals(TypicalTypes.listOf(ResultRowConverter.class)); } + default boolean usesAnnotations(final ConfigurationSetting setting) { + return setting.type().equals(TypicalTypes.listOf(Annotation.class)); + } + } diff --git a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/GradleGenerator.java b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/GradleGenerator.java index 7abe99a0..a7be46ec 100644 --- a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/GradleGenerator.java +++ b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/GradleGenerator.java @@ -9,8 +9,6 @@ package wtf.metio.yosql.model.generator; import com.squareup.javapoet.*; import wtf.metio.yosql.internals.javapoet.TypicalTypes; -import wtf.metio.yosql.internals.jdk.Strings; -import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.meta.ConfigurationGroup; import wtf.metio.yosql.models.meta.ConfigurationSetting; @@ -21,6 +19,8 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; +import static wtf.metio.yosql.internals.jdk.Strings.upperCase; + public final class GradleGenerator extends AbstractMethodsBasedGenerator { private final String immutablesBasePackage; @@ -31,11 +31,7 @@ public final class GradleGenerator extends AbstractMethodsBasedGenerator { @Override public Stream apply(final ConfigurationGroup group) { - if ("Converter".equalsIgnoreCase(group.name())) { - return Stream.of(configGroupClass(group), - rowConverterClass(true), rowConverterClass(false)); - } - return Stream.of(configGroupClass(group)); + return Stream.concat(Stream.of(configGroupClass(group)), group.gradleTypes().stream()); } private TypeSpec configGroupClass(final ConfigurationGroup group) { @@ -50,60 +46,6 @@ public final class GradleGenerator extends AbstractMethodsBasedGenerator { .build(); } - private TypeSpec rowConverterClass(boolean defaultConverter) { - final var gradleStringProperty = TypicalTypes.gradlePropertyOf(ClassName.get(String.class)); - final var className = defaultConverter ? "DefaultRowConverter" : "RowConverter"; - final var classBuilder = TypeSpec.classBuilder(ClassName.bestGuess(className)) - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .addJavadoc("Configures a single ResultRowConverter.") - .addMethod(MethodSpec.constructorBuilder() - .addJavadoc("Required by Gradle") - .addAnnotation(TypicalTypes.INJECT) - .addModifiers(Modifier.PUBLIC) - .build()); - if (defaultConverter) { - classBuilder.addMethod(MethodSpec.methodBuilder("getAlias") - .addJavadoc("@return The short alias for the converter.") - .addAnnotation(TypicalTypes.GRADLE_INPUT) - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .returns(gradleStringProperty) - .build()); - } else { - classBuilder.addSuperinterface(TypicalTypes.GRADLE_NAMED); - } - return classBuilder - .addMethod(MethodSpec.methodBuilder("getConverterType") - .addJavadoc("@return The fully-qualified name of the converter class.") - .addAnnotation(TypicalTypes.GRADLE_INPUT) - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .returns(gradleStringProperty) - .build()) - .addMethod(MethodSpec.methodBuilder("getMethodName") - .addJavadoc("@return The name of the method to call.") - .addAnnotation(TypicalTypes.GRADLE_INPUT) - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .returns(gradleStringProperty) - .build()) - .addMethod(MethodSpec.methodBuilder("getResultType") - .addJavadoc("@return The fully-qualified name of the converter class.") - .addAnnotation(TypicalTypes.GRADLE_INPUT) - .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .returns(gradleStringProperty) - .build()) - .addMethod(MethodSpec.methodBuilder("asRowConverter") - .returns(ResultRowConverter.class) - .addStatement(CodeBlock.builder() - .add("return $T.builder()$>", ResultRowConverter.class) - .add(defaultConverter ? "\n.setAlias(getAlias().get())" : "\n.setAlias(getName())") - .add("\n.setConverterType(getConverterType().get())") - .add("\n.setMethodName(getMethodName().get())") - .add("\n.setResultType(getResultType().get())") - .add("\n.build()$<") - .build()) - .build()) - .build(); - } - private List properties(final ConfigurationGroup group) { return group.settings().stream() .map(this::defaultMethod) @@ -122,7 +64,7 @@ public final class GradleGenerator extends AbstractMethodsBasedGenerator { .ifPresent(s -> builder.addParameter(ParameterSpec.builder(TypicalTypes.GRADLE_OBJECTS, "objects").build())); group.settings().stream() .filter(setting -> valueOf(setting).isPresent()) - .filter(setting -> !"rowConverters".equals(setting.name())) + .filter(setting -> !typeOf(setting).toString().startsWith(TypicalTypes.GRADLE_CONTAINERS.canonicalName())) .forEach(setting -> builder.addStatement(conventionValue(setting))); group.settings().stream() .filter(setting -> "defaultConverter".equals(setting.name())) @@ -189,8 +131,8 @@ public final class GradleGenerator extends AbstractMethodsBasedGenerator { .build(); } - private String propertyName(final ConfigurationSetting setting) { - return "get" + Strings.upperCase(setting.name()); + private static String propertyName(final ConfigurationSetting setting) { + return "get" + upperCase(setting.name()); } private TypeName gradleReturnType(final ConfigurationSetting setting) { @@ -198,7 +140,8 @@ public final class GradleGenerator extends AbstractMethodsBasedGenerator { if (type.isPrimitive()) { return TypicalTypes.gradlePropertyOf(type.box()); } - if (type.toString().startsWith(TypicalTypes.GRADLE_CONTAINERS.canonicalName())) { + if (type.toString().startsWith(TypicalTypes.GRADLE_CONTAINERS.canonicalName()) + || type.toString().startsWith(TypicalTypes.GRADLE_LIST_PROPERTY.canonicalName())) { return type; } if (type.toString().startsWith(ClassName.get(List.class).canonicalName())) { @@ -226,19 +169,24 @@ public final class GradleGenerator extends AbstractMethodsBasedGenerator { private CodeBlock methodConfiguration(final ConfigurationSetting setting) { if (usesResultRowConverter(setting)) { return CodeBlock.builder() - .add(".set$L($L().get().asRowConverter())\n", Strings.upperCase(setting.name()), propertyName(setting)) + .add(".set$L($L().get().asRowConverter())\n", upperCase(setting.name()), propertyName(setting)) .build(); } if (usesResultRowConverters(setting)) { return CodeBlock.builder() - .add(".set$L($L())\n", Strings.upperCase(setting.name()), "createRowConverters") + .add(".set$L($L())\n", upperCase(setting.name()), "createRowConverters") .build(); } if (usesNioPath(setting)) { return CodeBlock.builder() - .add(".set$L($L().get().getAsFile().toPath())\n", Strings.upperCase(setting.name()), propertyName(setting)) + .add(".set$L($L().get().getAsFile().toPath())\n", upperCase(setting.name()), propertyName(setting)) + .build(); + } + if (usesAnnotations(setting)) { + return CodeBlock.builder() + .add(".set$L(createAnnotations($L().stream().toList()))\n", upperCase(setting.name()), propertyName(setting)) .build(); } - return CodeBlock.of(".set$L($L().get())\n", Strings.upperCase(setting.name()), propertyName(setting)); + return CodeBlock.of(".set$L($L().get())\n", upperCase(setting.name()), propertyName(setting)); } } diff --git a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/MavenGenerator.java b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/MavenGenerator.java index 00d7ede1..acc4d48a 100644 --- a/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/MavenGenerator.java +++ b/yosql-models/yosql-models-generator/src/main/java/wtf/metio/yosql/model/generator/MavenGenerator.java @@ -8,7 +8,6 @@ package wtf.metio.yosql.model.generator; import com.squareup.javapoet.*; -import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.meta.ConfigurationGroup; import wtf.metio.yosql.models.meta.ConfigurationSetting; @@ -27,10 +26,7 @@ public final class MavenGenerator extends AbstractFieldsBasedGenerator { @Override public Stream apply(final ConfigurationGroup group) { - if ("Converter".equalsIgnoreCase(group.name())) { - return Stream.of(configGroupClass(group), rowConverterClass()); - } - return Stream.of(configGroupClass(group)); + return Stream.concat(Stream.of(configGroupClass(group)), group.mavenTypes().stream()); } private TypeSpec configGroupClass(final ConfigurationGroup group) { @@ -44,53 +40,6 @@ public final class MavenGenerator extends AbstractFieldsBasedGenerator { .build(); } - private TypeSpec rowConverterClass() { - final var mavenParameter = ClassName.bestGuess("org.apache.maven.plugins.annotations.Parameter"); - return TypeSpec.classBuilder(ClassName.bestGuess("RowConverter")) - .addModifiers(Modifier.PUBLIC) - .addField(FieldSpec.builder(String.class, "alias") - .addAnnotation(AnnotationSpec.builder(mavenParameter) - .addMember("required", "true") - .addMember("defaultValue", "$S", "") - .build()) - .initializer("$S", "") - .build()) - .addField(FieldSpec.builder(String.class, "converterType") - .addAnnotation(AnnotationSpec.builder(mavenParameter) - .addMember("required", "true") - .addMember("defaultValue", "$S", "") - .build()) - .initializer("$S", "") - .build()) - .addField(FieldSpec.builder(String.class, "methodName") - .addAnnotation(AnnotationSpec.builder(mavenParameter) - .addMember("required", "true") - .addMember("defaultValue", "$S", "") - .build()) - .initializer("$S", "") - .build()) - .addField(FieldSpec.builder(String.class, "resultType") - .addAnnotation(AnnotationSpec.builder(mavenParameter) - .addMember("required", "true") - .addMember("defaultValue", "$S", "") - .build()) - .initializer("$S", "") - .build()) - .addMethod(MethodSpec.methodBuilder("asRowConverter") - .addModifiers(Modifier.FINAL) - .returns(ResultRowConverter.class) - .addStatement(CodeBlock.builder() - .add("return $T.builder()", ResultRowConverter.class) - .add("$>\n.setAlias(alias)") - .add("\n.setConverterType(converterType)") - .add("\n.setMethodName(methodName)") - .add("\n.setResultType(resultType)") - .add("\n.build()$<") - .build()) - .build()) - .build(); - } - private MethodSpec asConfiguration(final ConfigurationGroup group) { return asConfiguration(group, immutablesBasePackage); } diff --git a/yosql-models/yosql-models-immutables/src/main/java/wtf/metio/yosql/models/immutables/SqlStatement.java b/yosql-models/yosql-models-immutables/src/main/java/wtf/metio/yosql/models/immutables/SqlStatement.java index 87724849..364a69b2 100644 --- a/yosql-models/yosql-models-immutables/src/main/java/wtf/metio/yosql/models/immutables/SqlStatement.java +++ b/yosql-models/yosql-models-immutables/src/main/java/wtf/metio/yosql/models/immutables/SqlStatement.java @@ -10,13 +10,10 @@ import org.immutables.value.Value; import wtf.metio.yosql.internals.jdk.Buckets; import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.configuration.ReturningMode; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import java.nio.file.Path; import java.util.List; -import java.util.Map; -import java.util.stream.Collector; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -33,17 +30,7 @@ public interface SqlStatement { //endregion - static Collector>> groupByName() { - return Collectors.groupingBy(SqlStatement::getName); - } - - static Collector>> groupByRepositoryClass() { - return Collectors.groupingBy(SqlStatement::getRepositoryClass); - } - - static Collector>> groupByRepositoryInterface() { - return Collectors.groupingBy(SqlStatement::getRepositoryInterface); - } + //region utils static Stream resultConverters( final List statements, @@ -61,13 +48,25 @@ public interface SqlStatement { .orElse(Boolean.FALSE); } + //endregion + /** + * @return The file system path to the source file of this SQL statement. + */ Path getSourcePath(); + /** + * @return The parsed configuration of this SQL statement. + */ SqlConfiguration getConfiguration(); + /** + * @return The raw SQL statement. + */ String getRawStatement(); + //region derived + @Value.Lazy default String getName() { return getConfiguration().name().orElse(""); @@ -86,21 +85,21 @@ public interface SqlStatement { @Value.Lazy default boolean isReading() { return getConfiguration().type() - .map(type -> SqlType.READING == type) + .map(type -> SqlStatementType.READING == type) .orElse(Boolean.FALSE); } @Value.Lazy default boolean isWriting() { return getConfiguration().type() - .map(type -> SqlType.WRITING == type) + .map(type -> SqlStatementType.WRITING == type) .orElse(Boolean.FALSE); } @Value.Lazy default boolean isCalling() { return getConfiguration().type() - .map(type -> SqlType.CALLING == type) + .map(type -> SqlStatementType.CALLING == type) .orElse(Boolean.FALSE); } @@ -126,4 +125,6 @@ public interface SqlStatement { return isWriting() && getConfiguration().generateStandardApi().orElse(Boolean.FALSE); } + //endregion + } diff --git a/yosql-models/yosql-models-immutables/src/test/java/wtf/metio/yosql/models/immutables/SqlConfigurationTest.java b/yosql-models/yosql-models-immutables/src/test/java/wtf/metio/yosql/models/immutables/SqlConfigurationTest.java index fedd83a2..144ef437 100644 --- a/yosql-models/yosql-models-immutables/src/test/java/wtf/metio/yosql/models/immutables/SqlConfigurationTest.java +++ b/yosql-models/yosql-models-immutables/src/test/java/wtf/metio/yosql/models/immutables/SqlConfigurationTest.java @@ -7,8 +7,12 @@ package wtf.metio.yosql.models.immutables; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import wtf.metio.yosql.models.configuration.*; + +import java.util.List; @DisplayName("SqlConfiguration") class SqlConfigurationTest { @@ -18,4 +22,806 @@ class SqlConfigurationTest { // TODO: write test that ensures that the name of a SqlStatement is transferred to its SqlConfiguration(s) } -} \ No newline at end of file + @Test + void mergeRepositoryFirst() { + final var first = SqlConfiguration.usingDefaults() + .setRepository("com.example.Repository") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.repository(), merged.repository()); + } + + @Test + void mergeRepositorySecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setRepository("com.example.Repository") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.repository(), merged.repository()); + } + + @Test + void mergeRepositoryMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.repository().isEmpty()); + } + + @Test + void mergeRepositoryInterfaceFirst() { + final var first = SqlConfiguration.usingDefaults() + .setRepositoryInterface("com.example.Repository") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.repositoryInterface(), merged.repositoryInterface()); + } + + @Test + void mergeRepositoryInterfaceSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setRepositoryInterface("com.example.Repository") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.repositoryInterface(), merged.repositoryInterface()); + } + + @Test + void mergeRepositoryInterfaceMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.repositoryInterface().isEmpty()); + } + + @Test + void mergeNameFirst() { + final var first = SqlConfiguration.usingDefaults() + .setName("name") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.name(), merged.name()); + } + + @Test + void mergeNameSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setName("name") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.name(), merged.name()); + } + + @Test + void mergeNameMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.name().isEmpty()); + } + + @Test + void mergeDescriptionFirst() { + final var first = SqlConfiguration.usingDefaults() + .setDescription("some description") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.description(), merged.description()); + } + + @Test + void mergeDescriptionSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setDescription("some description") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.description(), merged.description()); + } + + @Test + void mergeDescriptionMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.description().isEmpty()); + } + + @Test + void mergeVendorFirst() { + final var first = SqlConfiguration.usingDefaults() + .setVendor("H2 Database") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.vendor(), merged.vendor()); + } + + @Test + void mergeVendorSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setVendor("H2 Database") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.vendor(), merged.vendor()); + } + + @Test + void mergeVendorMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.vendor().isEmpty()); + } + + @Test + void mergeTypeFirst() { + final var first = SqlConfiguration.usingDefaults() + .setType(SqlStatementType.READING) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.type(), merged.type()); + } + + @Test + void mergeTypeSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setType(SqlStatementType.READING) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.type(), merged.type()); + } + + @Test + void mergeTypeMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.type().isEmpty()); + } + + @Test + void mergeReturningModeFirst() { + final var first = SqlConfiguration.usingDefaults() + .setReturningMode(ReturningMode.SINGLE) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.returningMode(), merged.returningMode()); + } + + @Test + void mergeReturningModeSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setReturningMode(ReturningMode.SINGLE) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.returningMode(), merged.returningMode()); + } + + @Test + void mergeReturningModeMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.returningMode().isEmpty()); + } + + @Test + void mergeStandardPrefixFirst() { + final var first = SqlConfiguration.usingDefaults() + .setStandardPrefix("prefix") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.standardPrefix(), merged.standardPrefix()); + } + + @Test + void mergeStandardPrefixSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setStandardPrefix("prefix") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.standardPrefix(), merged.standardPrefix()); + } + + @Test + void mergeStandardPrefixMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.standardPrefix().isEmpty()); + } + + @Test + void mergeStandardSuffixFirst() { + final var first = SqlConfiguration.usingDefaults() + .setStandardSuffix("suffix") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.standardSuffix(), merged.standardSuffix()); + } + + @Test + void mergeStandardSuffixSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setStandardSuffix("suffix") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.standardSuffix(), merged.standardSuffix()); + } + + @Test + void mergeStandardSuffixMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.standardSuffix().isEmpty()); + } + + @Test + void mergeBatchPrefixFirst() { + final var first = SqlConfiguration.usingDefaults() + .setBatchPrefix("prefix") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.batchPrefix(), merged.batchPrefix()); + } + + @Test + void mergeBatchPrefixSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setBatchPrefix("prefix") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.batchPrefix(), merged.batchPrefix()); + } + + @Test + void mergeBatchPrefixMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.batchPrefix().isEmpty()); + } + + @Test + void mergeBatchSuffixFirst() { + final var first = SqlConfiguration.usingDefaults() + .setBatchSuffix("suffix") + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.batchSuffix(), merged.batchSuffix()); + } + + @Test + void mergeBatchSuffixSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setBatchSuffix("suffix") + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.batchSuffix(), merged.batchSuffix()); + } + + @Test + void mergeBatchSuffixMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.batchSuffix().isEmpty()); + } + + @Test + void mergeGenerateStandardApiFirst() { + final var first = SqlConfiguration.usingDefaults() + .setGenerateStandardApi(true) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.generateStandardApi(), merged.generateStandardApi()); + } + + @Test + void mergeGenerateStandardApiSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setGenerateStandardApi(true) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.generateStandardApi(), merged.generateStandardApi()); + } + + @Test + void mergeGenerateStandardApiMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.generateStandardApi().isEmpty()); + } + + @Test + void mergeGenerateBatchApiFirst() { + final var first = SqlConfiguration.usingDefaults() + .setGenerateBatchApi(true) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.generateBatchApi(), merged.generateBatchApi()); + } + + @Test + void mergeGenerateBatchApiSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setGenerateBatchApi(true) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.generateBatchApi(), merged.generateBatchApi()); + } + + @Test + void mergeGenerateBatchApiMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.generateStandardApi().isEmpty()); + } + + @Test + void mergeUsePreparedStatementFirst() { + final var first = SqlConfiguration.usingDefaults() + .setUsePreparedStatement(true) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.usePreparedStatement(), merged.usePreparedStatement()); + } + + @Test + void mergeUsePreparedStatementSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setUsePreparedStatement(true) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.usePreparedStatement(), merged.usePreparedStatement()); + } + + @Test + void mergeUsePreparedStatementMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.usePreparedStatement().isEmpty()); + } + + @Test + void mergeCatchAndRethrowFirst() { + final var first = SqlConfiguration.usingDefaults() + .setCatchAndRethrow(true) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.catchAndRethrow(), merged.catchAndRethrow()); + } + + @Test + void mergeCatchAndRethrowSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setCatchAndRethrow(true) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.catchAndRethrow(), merged.catchAndRethrow()); + } + + @Test + void mergeCatchAndRethrowMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.catchAndRethrow().isEmpty()); + } + + @Test + void mergeThrowOnMultipleResultsForSingleFirst() { + final var first = SqlConfiguration.usingDefaults() + .setThrowOnMultipleResultsForSingle(true) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.throwOnMultipleResultsForSingle(), merged.throwOnMultipleResultsForSingle()); + } + + @Test + void mergeThrowOnMultipleResultsForSingleSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setThrowOnMultipleResultsForSingle(true) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.throwOnMultipleResultsForSingle(), merged.throwOnMultipleResultsForSingle()); + } + + @Test + void mergeThrowOnMultipleResultsForSingleMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.throwOnMultipleResultsForSingle().isEmpty()); + } + + @Test + void mergeInjectConvertersFirst() { + final var first = SqlConfiguration.usingDefaults() + .setInjectConverters(true) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.injectConverters(), merged.injectConverters()); + } + + @Test + void mergeInjectConvertersSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setInjectConverters(true) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.injectConverters(), merged.injectConverters()); + } + + @Test + void mergeInjectConvertersMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.injectConverters().isEmpty()); + } + + @Test + void mergeResultRowConverterFirst() { + final var first = SqlConfiguration.usingDefaults() + .setResultRowConverter(ResultRowConverter.builder().build()) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.resultRowConverter(), merged.resultRowConverter()); + } + + @Test + void mergeResultRowConverterSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setResultRowConverter(ResultRowConverter.builder().build()) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.resultRowConverter(), merged.resultRowConverter()); + } + + @Test + void mergeResultRowConverterMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.resultRowConverter().isEmpty()); + } + + @Test + void mergeParametersFirst() { + final var first = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder().setName("first").build())) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.parameters(), merged.parameters()); + } + + @Test + void mergeParametersSecond() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder().setName("second").build())) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.parameters(), merged.parameters()); + } + + @Test + void mergeParametersMixed() { + final var parameters = List.of( + SqlParameter.builder().setName("first").build(), + SqlParameter.builder().setName("second").build()); + final var first = SqlConfiguration.usingDefaults() + .setParameters(List.of(parameters.get(0))) + .build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(List.of(parameters.get(1))) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(parameters, merged.parameters()); + } + + @Test + void mergeParametersMixedDuplicatedFirst() { + final List parameters = List.of( + SqlParameter.builder().setName("first").build(), + SqlParameter.builder().setName("second").build()); + final var first = SqlConfiguration.usingDefaults() + .setParameters(parameters) + .build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder().setName("second").build())) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(parameters, merged.parameters()); + } + + @Test + void mergeParametersMixedDuplicatedSecond() { + final List parameters = List.of( + SqlParameter.builder().setName("first").build(), + SqlParameter.builder().setName("second").build()); + final var first = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder().setName("first").build())) + .build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(parameters) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(parameters, merged.parameters()); + } + + @Test + void mergeParametersDuplicated() { + final var first = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build())) + .build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build())) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(1, merged.parameters().size()); + Assertions.assertEquals("name", merged.parameters().get(0).name().orElse("")); + Assertions.assertEquals("java.lang.String", merged.parameters().get(0).type().orElse("")); + } + + @Test + void mergeParametersDuplicatedNamesMissingTypeFirst() { + final var first = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder() + .setName("name") + .setIndices(new int[]{1}) + .build())) + .build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build())) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(1, merged.parameters().size()); + Assertions.assertEquals("name", merged.parameters().get(0).name().orElse("")); + Assertions.assertEquals("java.lang.String", merged.parameters().get(0).type().orElse("")); + } + + @Test + void mergeParametersDuplicatedNamesMissingTypeSecond() { + final var first = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder() + .setName("name") + .setType("java.lang.String") + .setIndices(new int[]{1}) + .build())) + .build(); + final var second = SqlConfiguration.usingDefaults() + .setParameters(List.of(SqlParameter.builder() + .setName("name") + .setIndices(new int[]{1}) + .build())) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(1, merged.parameters().size()); + Assertions.assertEquals("name", merged.parameters().get(0).name().orElse("")); + Assertions.assertEquals("java.lang.String", merged.parameters().get(0).type().orElse("")); + } + + @Test + void mergeParametersMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.parameters().isEmpty()); + } + + @Test + void mergeAnnotationsMissing() { + final var first = SqlConfiguration.usingDefaults().build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertTrue(merged.annotations().isEmpty()); + } + + @Test + void mergeAnnotationsFirst() { + final var first = SqlConfiguration.usingDefaults() + .setAnnotations(List.of(Annotation.builder().setType("com.example.MyAnnotation").build())) + .build(); + final var second = SqlConfiguration.usingDefaults().build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(first.annotations(), merged.annotations()); + } + + @Test + void mergeAnnotationsSecond() { + final var first = SqlConfiguration.usingDefaults() + .build(); + final var second = SqlConfiguration.usingDefaults() + .setAnnotations(List.of(Annotation.builder().setType("com.example.MyAnnotation").build())) + .build(); + + final var merged = SqlConfiguration.merge(first, second); + + Assertions.assertEquals(second.annotations(), merged.annotations()); + } + +} diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/ConfigurationGroup.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/ConfigurationGroup.java index aabf8ed5..2d61066f 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/ConfigurationGroup.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/ConfigurationGroup.java @@ -9,6 +9,7 @@ package wtf.metio.yosql.models.meta; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeSpec; import org.immutables.value.Value; import java.util.Collections; @@ -48,6 +49,21 @@ public interface ConfigurationGroup { */ List tags(); + /** + * @return The optional list of additional types for Maven. + */ + List mavenTypes(); + + /** + * @return The optional list of additional types for Gradle. + */ + List gradleTypes(); + + /** + * @return The optional list of additional types for the CLI. + */ + List cliTypes(); + //region derived @Value.Lazy diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AbstractConfigurationGroup.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AbstractConfigurationGroup.java new file mode 100644 index 00000000..d562ae08 --- /dev/null +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AbstractConfigurationGroup.java @@ -0,0 +1,87 @@ +/* + * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql, + * including this file, may be copied, modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +package wtf.metio.yosql.models.meta.data; + +import com.squareup.javapoet.*; +import wtf.metio.yosql.internals.javapoet.TypicalTypes; + +import javax.lang.model.element.Modifier; + +abstract class AbstractConfigurationGroup { + + protected static final String MAVEN_PACKAGE = "wtf.metio.yosql.tooling.maven"; + protected static final String GRADLE_PACKAGE = "wtf.metio.yosql.tooling.gradle"; + + protected static ClassName mavenType(final String className) { + return ClassName.get(MAVEN_PACKAGE, className); + } + + protected static ClassName gradleType(final String className) { + return ClassName.get(GRADLE_PACKAGE, className); + } + + protected static FieldSpec mavenStringParameter(final String name) { + return mavenStringParameter(name, ""); + } + + protected static FieldSpec mavenStringParameter(final String name, final String defaultValue) { + return FieldSpec.builder(ClassName.get(String.class), name) + .addAnnotation(mavenParameter(defaultValue)) + .initializer("$S", defaultValue) + .build(); + } + + protected static FieldSpec mavenParameter(final TypeName type, final String name) { + return FieldSpec.builder(type, name) + .addAnnotation(mavenParameter("")) + .build(); + } + + private static AnnotationSpec mavenParameter(final String defaultValue) { + return AnnotationSpec.builder(TypicalTypes.MAVEN_PARAMETER) + .addMember("required", "true") + .addMember("defaultValue", "$S", defaultValue) + .build(); + } + + protected static MethodSpec gradleConstructor() { + return MethodSpec.constructorBuilder() + .addJavadoc("Required by Gradle") + .addAnnotation(TypicalTypes.INJECT) + .addModifiers(Modifier.PUBLIC) + .build(); + } + + protected static MethodSpec gradleStringProperty(final String name, final String description) { + return MethodSpec.methodBuilder(name) + .addJavadoc("@return " + description + ".") + .addAnnotation(TypicalTypes.GRADLE_INPUT) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .returns(TypicalTypes.GRADLE_STRING_PROPERTY) + .build(); + } + + protected static MethodSpec gradleListProperty(final TypeName type, final String name, final String description) { + return MethodSpec.methodBuilder(name) + .addJavadoc("@return " + description + ".") + .addAnnotation(TypicalTypes.GRADLE_INPUT) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .returns(TypicalTypes.gradleListPropertyOf(type)) + .build(); + } + + protected static MethodSpec gradleNamedProperty(final TypeName type, final String name, final String description) { + return MethodSpec.methodBuilder(name) + .addJavadoc("@return " + description + ".") + .addAnnotation(TypicalTypes.GRADLE_INPUT) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .returns(TypicalTypes.gradleContainerOf(type)) + .build(); + } + +} diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AllConfigurations.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AllConfigurations.java index bfcda92d..da7f1061 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AllConfigurations.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/AllConfigurations.java @@ -28,4 +28,8 @@ public final class AllConfigurations { Resources.configurationGroup()); } + private AllConfigurations() { + // factory class + } + } diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Annotations.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Annotations.java index 40e2ab27..2bcbda7a 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Annotations.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Annotations.java @@ -7,18 +7,39 @@ package wtf.metio.yosql.models.meta.data; -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.TypeName; -import wtf.metio.yosql.models.configuration.AnnotationApis; -import wtf.metio.yosql.models.configuration.AnnotationMembers; +import com.squareup.javapoet.*; +import wtf.metio.yosql.internals.javapoet.TypicalTypes; +import wtf.metio.yosql.models.configuration.Annotation; +import wtf.metio.yosql.models.configuration.AnnotationMember; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationApis; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationMembers; import wtf.metio.yosql.models.meta.ConfigurationExample; import wtf.metio.yosql.models.meta.ConfigurationGroup; import wtf.metio.yosql.models.meta.ConfigurationSetting; -public final class Annotations { - - public static final String DEFAULT_COMMENT = "DO NOT MODIFY - automatically generated by YoSQL"; - public static final AnnotationMembers DEFAULT_MEMBERS = AnnotationMembers.WITHOUT_DATE; +import javax.lang.model.element.Modifier; +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +import static wtf.metio.yosql.internals.jdk.Strings.upperCase; + +public final class Annotations extends AbstractConfigurationGroup { + + private static final String DEFAULT_COMMENT = "DO NOT MODIFY - automatically generated by YoSQL"; + private static final GeneratedAnnotationMembers DEFAULT_MEMBERS = GeneratedAnnotationMembers.WITHOUT_DATE; + private static final String ANNOTATION_SPEC = "AnnotationSpec"; + private static final ClassName MAVEN_ANNOTATION_TYPE = mavenType(ANNOTATION_SPEC); + private static final ClassName GRADLE_ANNOTATION_TYPE = gradleType(ANNOTATION_SPEC); + private static final String ANNOTATION_MEMBER_SPEC = "AnnotationMemberSpec"; + private static final ClassName MAVEN_MEMBER_TYPE = mavenType(ANNOTATION_MEMBER_SPEC); + private static final ClassName GRADLE_MEMBER_TYPE = gradleType(ANNOTATION_MEMBER_SPEC); + private static final String AS_ANNOTATION = "asAnnotation"; + private static final String AS_ANNOTATION_MEMBER = "asAnnotationMember"; + private static final String TYPE = "type"; + private static final String MEMBERS = "members"; + private static final String KEY = "key"; + private static final String VALUE = "value"; public static ConfigurationGroup configurationGroup() { return ConfigurationGroup.builder() @@ -35,6 +56,13 @@ public final class Annotations { .addSettings(fieldComment()) .addSettings(methodComment()) .addSettings(generatorName()) + .addSettings(repositoryAnnotations()) + .addSettings(constructorAnnotations()) + .addSettings(methodAnnotations()) + .addMavenTypes(mavenAnnotationSpecType(), mavenAnnotationMemberSpecType()) + .setMavenMethods(List.of(createMavenAnnotations())) + .addGradleTypes(gradleAnnotationSpecType(), gradleAnnotationMemberSpecType()) + .setGradleMethods(List.of(createGradleAnnotations())) .build(); } @@ -42,8 +70,8 @@ public final class Annotations { return ConfigurationSetting.builder() .setName("annotationApi") .setDescription("The annotation API to use.") - .setType(TypeName.get(AnnotationApis.class)) - .setValue(AnnotationApis.PROCESSING_API) + .setType(TypeName.get(GeneratedAnnotationApis.class)) + .setValue(GeneratedAnnotationApis.PROCESSING_API) .addExamples(ConfigurationExample.builder() .setValue("PROCESSING_API") .setDescription("The default value of the `annotationApi` configuration option is `PROCESSING_API`. Setting the option to `PROCESSING_API` therefore produces the same code generated as the default configuration.") @@ -262,7 +290,7 @@ public final class Annotations { return ConfigurationSetting.builder() .setName("classMembers") .setDescription("The annotation members to use for classes.") - .setType(TypeName.get(AnnotationMembers.class)) + .setType(TypeName.get(GeneratedAnnotationMembers.class)) .setValue(DEFAULT_MEMBERS) .addExamples(ConfigurationExample.builder() .setValue("WITHOUT_DATE") @@ -374,7 +402,7 @@ public final class Annotations { return ConfigurationSetting.builder() .setName("fieldMembers") .setDescription("The annotation members to use for fields.") - .setType(TypeName.get(AnnotationMembers.class)) + .setType(TypeName.get(GeneratedAnnotationMembers.class)) .setValue(DEFAULT_MEMBERS) .addExamples(ConfigurationExample.builder() .setValue("WITHOUT_DATE") @@ -498,7 +526,7 @@ public final class Annotations { return ConfigurationSetting.builder() .setName("methodMembers") .setDescription("The annotation members to use for methods.") - .setType(TypeName.get(AnnotationMembers.class)) + .setType(TypeName.get(GeneratedAnnotationMembers.class)) .setValue(DEFAULT_MEMBERS) .addExamples(ConfigurationExample.builder() .setValue("WITHOUT_DATE") @@ -580,7 +608,7 @@ public final class Annotations { public void someMethod() { // ... some code } - + // ... rest of generated code (same as above) }""") @@ -834,6 +862,147 @@ public final class Annotations { .build(); } + private static ConfigurationSetting repositoryAnnotations() { + return ConfigurationSetting.builder() + .setName("repositoryAnnotations") + .setDescription("The additional annotations to be placed on generated repository classes.") + .setType(TypicalTypes.listOf(Annotation.class)) + .setValue(CodeBlock.builder().add("$T.of()", List.class).build()) + .setCliValue("") + .setMavenValue("") + .setMavenType(TypicalTypes.listOf(MAVEN_ANNOTATION_TYPE)) + .setGradleType(TypicalTypes.gradleContainerOf(GRADLE_ANNOTATION_TYPE)) + .build(); + } + + private static ConfigurationSetting constructorAnnotations() { + return ConfigurationSetting.builder() + .setName("constructorAnnotations") + .setDescription("The additional annotations to be placed on generated constructors.") + .setType(TypicalTypes.listOf(Annotation.class)) + .setValue(CodeBlock.builder().add("$T.of()", List.class).build()) + .setCliValue("") + .setMavenValue("") + .setMavenType(TypicalTypes.listOf(MAVEN_ANNOTATION_TYPE)) + .setGradleType(TypicalTypes.gradleContainerOf(GRADLE_ANNOTATION_TYPE)) + .build(); + } + + private static ConfigurationSetting methodAnnotations() { + return ConfigurationSetting.builder() + .setName("methodAnnotations") + .setDescription("The additional annotations to be placed on generated methods.") + .setType(TypicalTypes.listOf(Annotation.class)) + .setValue(CodeBlock.builder().add("$T.of()", List.class).build()) + .setCliValue("") + .setMavenValue("") + .setMavenType(TypicalTypes.listOf(MAVEN_ANNOTATION_TYPE)) + .setGradleType(TypicalTypes.gradleContainerOf(GRADLE_ANNOTATION_TYPE)) + .build(); + } + + private static TypeSpec mavenAnnotationSpecType() { + return TypeSpec.classBuilder(ANNOTATION_SPEC) + .addModifiers(Modifier.PUBLIC) + .addField(mavenStringParameter(TYPE)) + .addField(mavenParameter(TypicalTypes.listOf(MAVEN_MEMBER_TYPE), MEMBERS)) + .addMethod(MethodSpec.methodBuilder(AS_ANNOTATION) + .addModifiers(Modifier.FINAL) + .returns(Annotation.class) + .addStatement(CodeBlock.builder() + .add("return $T.builder()", Annotation.class) + .add("$>\n.set$L($L)", upperCase(TYPE), TYPE) + .add("\n.addAll$L($T.ofNullable($L).flatMap($T::stream).map($T::$L).toList())", + upperCase(MEMBERS), Stream.class, MEMBERS, Collection.class, MAVEN_MEMBER_TYPE, AS_ANNOTATION_MEMBER) + .add("\n.build()$<") + .build()) + .build()) + .build(); + } + + private static TypeSpec mavenAnnotationMemberSpecType() { + return TypeSpec.classBuilder(ANNOTATION_MEMBER_SPEC) + .addModifiers(Modifier.PUBLIC) + .addField(mavenStringParameter(TYPE, "java.lang.String")) + .addField(mavenStringParameter(KEY)) + .addField(mavenStringParameter(VALUE)) + .addMethod(MethodSpec.methodBuilder(AS_ANNOTATION_MEMBER) + .addModifiers(Modifier.FINAL) + .returns(AnnotationMember.class) + .addStatement(CodeBlock.builder() + .add("return $T.builder()", AnnotationMember.class) + .add("$>\n.set$L($L)", upperCase(KEY), KEY) + .add("\n.set$L($L)", upperCase(VALUE), VALUE) + .add("\n.set$L($L)", upperCase(TYPE), TYPE) + .add("\n.build()$<") + .build()) + .build()) + .build(); + } + + private static MethodSpec createMavenAnnotations() { + return MethodSpec.methodBuilder("createAnnotations") + .addModifiers(Modifier.FINAL) + .returns(TypicalTypes.listOf(Annotation.class)) + .addParameter(ParameterSpec.builder(TypicalTypes.listOf(MAVEN_ANNOTATION_TYPE), "specs", Modifier.FINAL).build()) + .addStatement("return $T.ofNullable($L).flatMap($T::stream).map($T::$L).toList()", + Stream.class, "specs", Collection.class, MAVEN_ANNOTATION_TYPE, AS_ANNOTATION) + .build(); + } + + private static TypeSpec gradleAnnotationSpecType() { + return TypeSpec.classBuilder(ANNOTATION_SPEC) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addJavadoc("Configures a single Annotation.") + .addSuperinterface(TypicalTypes.GRADLE_NAMED) + .addMethod(gradleConstructor()) + .addMethod(gradleNamedProperty(GRADLE_MEMBER_TYPE, "get" + upperCase(MEMBERS), "The annotation members")) + .addMethod(MethodSpec.methodBuilder(AS_ANNOTATION) + .addModifiers(Modifier.FINAL) + .returns(Annotation.class) + .addStatement(CodeBlock.builder() + .add("return $T.builder()", Annotation.class) + .add("$>\n.set$L(getName())", upperCase(TYPE)) + .add("\n.addAll$L(get$L().stream().map($T::$L).toList())", + upperCase(MEMBERS), upperCase(MEMBERS), GRADLE_MEMBER_TYPE, AS_ANNOTATION_MEMBER) + .add("\n.build()$<") + .build()) + .build()) + .build(); + } + + private static TypeSpec gradleAnnotationMemberSpecType() { + return TypeSpec.classBuilder(ANNOTATION_MEMBER_SPEC) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addJavadoc("Configures a single AnnotationMember.") + .addSuperinterface(TypicalTypes.GRADLE_NAMED) + .addMethod(gradleConstructor()) + .addMethod(gradleStringProperty("get" + upperCase(VALUE), "The value of the annotation member")) + .addMethod(gradleStringProperty("get" + upperCase(TYPE), "The fully-qualified type of the annotation member")) + .addMethod(MethodSpec.methodBuilder(AS_ANNOTATION_MEMBER) + .addModifiers(Modifier.FINAL) + .returns(AnnotationMember.class) + .addStatement(CodeBlock.builder() + .add("return $T.builder()", AnnotationMember.class) + .add("$>\n.set$L(getName())", upperCase(KEY)) + .add("\n.set$L(get$L().get())", upperCase(VALUE), upperCase(VALUE)) + .add("\n.set$L(get$L().getOrElse($S))", upperCase(TYPE), upperCase(TYPE), "java.lang.String") + .add("\n.build()$<") + .build()) + .build()) + .build(); + } + + private static MethodSpec createGradleAnnotations() { + return MethodSpec.methodBuilder("createAnnotations") + .addModifiers(Modifier.FINAL) + .returns(TypicalTypes.listOf(Annotation.class)) + .addParameter(ParameterSpec.builder(TypicalTypes.listOf(GRADLE_ANNOTATION_TYPE), "specs", Modifier.FINAL).build()) + .addStatement("return $T.ofNullable($L).flatMap($T::stream).map($T::$L).toList()", + Stream.class, "specs", Collection.class, GRADLE_ANNOTATION_TYPE, AS_ANNOTATION) + .build(); + } + private Annotations() { // data class } diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Converter.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Converter.java index 7e133ec0..20742781 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Converter.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Converter.java @@ -22,7 +22,24 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -public final class Converter { +import static wtf.metio.yosql.internals.jdk.Strings.upperCase; + +public final class Converter extends AbstractConfigurationGroup { + + private static final String ROW_CONVERTER = "RowConverter"; + private static final String AS_ROW_CONVERTER = "asRowConverter"; + private static final String CREATE_ROW_CONVERTERS = "createRowConverters"; + private static final String CREATE_ROW_CONVERTER = "createRowConverter"; + private static final String ROW_CONVERTERS = "rowConverters"; + private static final String MAP_CONVERTER_ALIAS = "mapConverterAlias"; + private static final String MAP_CONVERTER_METHOD = "mapConverterMethod"; + private static final String MAP_CONVERTER_CLASS = "mapConverterClass"; + private static final String DEFAULT_ROW_CONVERTER = "DefaultRowConverter"; + private static final String DEFAULT_CONVERTER = "defaultConverter"; + private static final String ALIAS = "alias"; + private static final String CONVERTER_TYPE = "converterType"; + private static final String METHOD_NAME = "methodName"; + private static final String RESULT_TYPE = "resultType"; public static ConfigurationGroup configurationGroup() { return ConfigurationGroup.builder() @@ -37,17 +54,19 @@ public final class Converter { .setCliMethods(List.of(createCliRowConverters(), createCliRowConverter(), createCliAsRowConverter())) .setGradleMethods(List.of(createGradleRowConverters(), createGradleRowConverter())) .setMavenMethods(List.of(createMavenRowConverters(), createMavenRowConverter())) + .addMavenTypes(mavenRowConverterType()) + .addGradleTypes(gradleRowConverterType(true), gradleRowConverterType(false)) .build(); } private static ConfigurationSetting defaultConverter() { return ConfigurationSetting.builder() - .setName("defaultConverter") + .setName(DEFAULT_CONVERTER) .setDescription("The default converter to use, if no other is specified on a query itself.") .setType(TypeName.get(ResultRowConverter.class)) .setCliType(ClassName.get(String.class)) - .setGradleType(ClassName.bestGuess("wtf.metio.yosql.tooling.gradle.DefaultRowConverter")) - .setMavenType(ClassName.bestGuess("wtf.metio.yosql.tooling.maven.RowConverter")) + .setGradleType(gradleType(DEFAULT_ROW_CONVERTER)) + .setMavenType(mavenType(ROW_CONVERTER)) .setCliValue("") .setMavenValue("") .build(); @@ -55,16 +74,14 @@ public final class Converter { private static ConfigurationSetting rowConverters() { return ConfigurationSetting.builder() - .setName("rowConverters") + .setName(ROW_CONVERTERS) .setDescription("The converters configured by the user.") .setType(TypicalTypes.listOf(ResultRowConverter.class)) .setCliType(TypicalTypes.listOf(ClassName.get(String.class))) - .setMavenType(TypicalTypes.listOf(ClassName.bestGuess("wtf.metio.yosql.tooling.maven.RowConverter"))) - .setGradleType(TypicalTypes.gradleContainerOf(ClassName.bestGuess("wtf.metio.yosql.tooling.gradle.RowConverter"))) + .setMavenType(TypicalTypes.listOf(mavenType(ROW_CONVERTER))) + .setGradleType(TypicalTypes.gradleContainerOf(gradleType(ROW_CONVERTER))) .setMavenValue("") - .setValue(CodeBlock.builder() - .add("$T.of()", List.class) - .build()) + .setValue(CodeBlock.builder().add("$T.of()", List.class).build()) .build(); } @@ -79,7 +96,7 @@ public final class Converter { private static ConfigurationSetting mapConverterClass() { return ConfigurationSetting.builder() - .setName("mapConverterClass") + .setName(MAP_CONVERTER_CLASS) .setDescription("The fully-qualified class name of the ToMap converter.") .setType(ClassName.get(String.class)) .setValue("com.example.persistence.converter.ToMapConverter") @@ -88,7 +105,7 @@ public final class Converter { private static ConfigurationSetting mapConverterMethod() { return ConfigurationSetting.builder() - .setName("mapConverterMethod") + .setName(MAP_CONVERTER_METHOD) .setDescription("The name of the method to generate/call in the ToMap converter.") .setType(ClassName.get(String.class)) .setValue("apply") @@ -97,7 +114,7 @@ public final class Converter { private static ConfigurationSetting mapConverterAlias() { return ConfigurationSetting.builder() - .setName("mapConverterAlias") + .setName(MAP_CONVERTER_ALIAS) .setDescription("The name of the alias referencing the ToMap converter.") .setType(ClassName.get(String.class)) .setValue("toMap") @@ -105,13 +122,13 @@ public final class Converter { } private static MethodSpec createCliRowConverters() { - return MethodSpec.methodBuilder("createRowConverters") + return MethodSpec.methodBuilder(CREATE_ROW_CONVERTERS) .addModifiers(Modifier.FINAL) .returns(TypicalTypes.listOf(ResultRowConverter.class)) .addStatement(CodeBlock.builder() - .add("return $T.ofNullable(rowConverters)", Stream.class) + .add("return $T.ofNullable($L)", Stream.class, ROW_CONVERTERS) .add("$>$>\n.flatMap($T::stream)", List.class) - .add("\n.map(this::asRowConverter)") + .add("\n.map(this::$L)", AS_ROW_CONVERTER) .add("\n.filter($T::nonNull)", Objects.class) .add("\n.collect($T.toList())$<$<", Collectors.class) .build()) @@ -119,19 +136,19 @@ public final class Converter { } private static MethodSpec createCliRowConverter() { - return MethodSpec.methodBuilder("createRowConverter") + return MethodSpec.methodBuilder(CREATE_ROW_CONVERTER) .addModifiers(Modifier.FINAL) .returns(ResultRowConverter.class) .addStatement(CodeBlock.builder() - .add("return $T.ofNullable(defaultConverter)", Optional.class) + .add("return $T.ofNullable($L)", Optional.class, DEFAULT_CONVERTER) .add("$>$>\n.map($T::strip)", String.class) .add("\n.filter($T.not($T::isBlank))", Predicate.class, Strings.class) - .add("\n.map(this::asRowConverter)") + .add("\n.map(this::$L)", AS_ROW_CONVERTER) .add("\n.filter($T::nonNull)", Objects.class) - .add("\n.orElse(ResultRowConverter.builder()") - .add("$>\n.setAlias(mapConverterAlias)") - .add("\n.setConverterType(mapConverterClass)") - .add("\n.setMethodName(mapConverterMethod)") + .add("\n.orElse($T.builder()", ResultRowConverter.class) + .add("$>\n.setAlias($L)", MAP_CONVERTER_ALIAS) + .add("\n.setConverterType($L)", MAP_CONVERTER_CLASS) + .add("\n.setMethodName($L)", MAP_CONVERTER_METHOD) .add("\n.setResultType($S)", "java.util.Map") .add("\n.build())$<$<$<") .build()) @@ -139,7 +156,7 @@ public final class Converter { } private static MethodSpec createCliAsRowConverter() { - return MethodSpec.methodBuilder("asRowConverter") + return MethodSpec.methodBuilder(AS_ROW_CONVERTER) .addModifiers(Modifier.FINAL) .returns(ResultRowConverter.class) .addParameter(String.class, "converterDefinition", Modifier.FINAL) @@ -160,40 +177,40 @@ public final class Converter { } private static MethodSpec createGradleRowConverters() { - return MethodSpec.methodBuilder("createRowConverters") + return MethodSpec.methodBuilder(CREATE_ROW_CONVERTERS) .addModifiers(Modifier.PRIVATE) .returns(TypicalTypes.listOf(ResultRowConverter.class)) .addStatement(CodeBlock.builder() - .add("return getRowConverters().stream()", Stream.class) - .add("$>\n.map($T::asRowConverter)", ClassName.bestGuess("wtf.metio.yosql.tooling.gradle.RowConverter")) + .add("return get$L().stream()", upperCase(ROW_CONVERTERS)) + .add("$>\n.map($T::$L)", gradleType(ROW_CONVERTER), AS_ROW_CONVERTER) .add("\n.collect($T.toList())$<", Collectors.class) .build()) .build(); } private static MethodSpec createGradleRowConverter() { - final var defaultConverterType = ClassName.bestGuess("wtf.metio.yosql.tooling.gradle.DefaultRowConverter"); - return MethodSpec.methodBuilder("createRowConverter") + final var defaultConverterType = gradleType(DEFAULT_ROW_CONVERTER); + return MethodSpec.methodBuilder(CREATE_ROW_CONVERTER) .addModifiers(Modifier.PRIVATE) .addParameter(ParameterSpec.builder(TypicalTypes.GRADLE_OBJECTS, "objects", Modifier.FINAL).build()) .returns(defaultConverterType) .addStatement("final var defaultConverter = objects.newInstance($T.class)", defaultConverterType) - .addStatement("defaultConverter.getAlias().set(getMapConverterAlias())") - .addStatement("defaultConverter.getConverterType().set(getMapConverterClass())") - .addStatement("defaultConverter.getMethodName().set(getMapConverterMethod())") + .addStatement("defaultConverter.getAlias().set(get$L())", upperCase(MAP_CONVERTER_ALIAS)) + .addStatement("defaultConverter.getConverterType().set(get$L())", upperCase(MAP_CONVERTER_CLASS)) + .addStatement("defaultConverter.getMethodName().set(get$L())", upperCase(MAP_CONVERTER_METHOD)) .addStatement("defaultConverter.getResultType().set($S)", "java.util.Map") .addStatement("return defaultConverter") .build(); } private static MethodSpec createMavenRowConverters() { - return MethodSpec.methodBuilder("createRowConverters") + return MethodSpec.methodBuilder(CREATE_ROW_CONVERTERS) .addModifiers(Modifier.FINAL) .returns(TypicalTypes.listOf(ResultRowConverter.class)) .addStatement(CodeBlock.builder() - .add("return $T.ofNullable(rowConverters)", Stream.class) + .add("return $T.ofNullable($L)", Stream.class, ROW_CONVERTERS) .add("$>$>\n.flatMap($T::stream)", List.class) - .add("\n.map($T::asRowConverter)", ClassName.bestGuess("wtf.metio.yosql.tooling.maven.RowConverter")) + .add("\n.map($T::$L)", mavenType(ROW_CONVERTER), AS_ROW_CONVERTER) .add("\n.filter($T::nonNull)", Objects.class) .add("\n.collect($T.toList())$<$<", Collectors.class) .build()) @@ -201,22 +218,73 @@ public final class Converter { } private static MethodSpec createMavenRowConverter() { - return MethodSpec.methodBuilder("createRowConverter") + return MethodSpec.methodBuilder(CREATE_ROW_CONVERTER) .addModifiers(Modifier.FINAL) .returns(ResultRowConverter.class) .addStatement(CodeBlock.builder() - .add("return $T.ofNullable(defaultConverter)", Optional.class) - .add("$>$>\n.map($T::asRowConverter)", ClassName.bestGuess("wtf.metio.yosql.tooling.maven.RowConverter")) - .add("\n.orElse(ResultRowConverter.builder()") - .add("$>\n.setAlias(mapConverterAlias)") - .add("\n.setConverterType(mapConverterClass)") - .add("\n.setMethodName(mapConverterMethod)") + .add("return $T.ofNullable($L)", Optional.class, DEFAULT_CONVERTER) + .add("$>$>\n.map($T::$L)", mavenType(ROW_CONVERTER), AS_ROW_CONVERTER) + .add("\n.orElse($T.builder()", ResultRowConverter.class) + .add("$>\n.setAlias($L)", MAP_CONVERTER_ALIAS) + .add("\n.setConverterType($L)", MAP_CONVERTER_CLASS) + .add("\n.setMethodName($L)", MAP_CONVERTER_METHOD) .add("\n.setResultType($S)", "java.util.Map") .add("\n.build())$<$<$<") .build()) .build(); } + private static TypeSpec mavenRowConverterType() { + return TypeSpec.classBuilder(ROW_CONVERTER) + .addModifiers(Modifier.PUBLIC) + .addField(mavenStringParameter(ALIAS)) + .addField(mavenStringParameter(CONVERTER_TYPE)) + .addField(mavenStringParameter(METHOD_NAME)) + .addField(mavenStringParameter(RESULT_TYPE)) + .addMethod(MethodSpec.methodBuilder(AS_ROW_CONVERTER) + .addModifiers(Modifier.FINAL) + .returns(ResultRowConverter.class) + .addStatement(CodeBlock.builder() + .add("return $T.builder()", ResultRowConverter.class) + .add("$>\n.setAlias($L)", ALIAS) + .add("\n.setConverterType($L)", CONVERTER_TYPE) + .add("\n.setMethodName($L)", METHOD_NAME) + .add("\n.setResultType($L)", RESULT_TYPE) + .add("\n.build()$<") + .build()) + .build()) + .build(); + } + + private static TypeSpec gradleRowConverterType(boolean defaultConverter) { + final var className = defaultConverter ? DEFAULT_ROW_CONVERTER : ROW_CONVERTER; + final var classBuilder = TypeSpec.classBuilder(className) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addJavadoc("Configures a single ResultRowConverter.") + .addMethod(gradleConstructor()); + if (defaultConverter) { + classBuilder.addMethod(gradleStringProperty("getAlias", "The short alias for the converter")); + } else { + classBuilder.addSuperinterface(TypicalTypes.GRADLE_NAMED); + } + return classBuilder + .addMethod(gradleStringProperty("getConverterType", "The fully-qualified name of the converter class")) + .addMethod(gradleStringProperty("getMethodName", "The name of the method to call")) + .addMethod(gradleStringProperty("getResultType", "The fully-qualified name of the converter class")) + .addMethod(MethodSpec.methodBuilder(AS_ROW_CONVERTER) + .returns(ResultRowConverter.class) + .addStatement(CodeBlock.builder() + .add("return $T.builder()$>", ResultRowConverter.class) + .add(defaultConverter ? "\n.setAlias(getAlias().get())" : "\n.setAlias(getName())") + .add("\n.setConverterType(getConverterType().get())") + .add("\n.setMethodName(getMethodName().get())") + .add("\n.setResultType(getResultType().get())") + .add("\n.build()$<") + .build()) + .build()) + .build(); + } + private Converter() { // data class } diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Repositories.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Repositories.java index f09e98a7..fd7a9501 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Repositories.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Repositories.java @@ -201,6 +201,7 @@ public final class Repositories { .setDescription("Generate standard methods") .setType(TypeName.get(boolean.class)) .setValue(true) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -210,6 +211,7 @@ public final class Repositories { .setDescription("Generate batch methods") .setType(TypeName.get(boolean.class)) .setValue(true) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -219,6 +221,7 @@ public final class Repositories { .setDescription("Should `PreparedStatement`s be used instead of `Statement`s") .setType(TypeName.get(boolean.class)) .setValue(true) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -228,6 +231,7 @@ public final class Repositories { .setDescription("Catch exceptions during SQL execution and re-throw them as RuntimeExceptions") .setType(TypeName.get(boolean.class)) .setValue(true) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -237,6 +241,7 @@ public final class Repositories { .setDescription("Throw an exception in case a statement using `ReturningMode.SINGLE` produces more than 1 result.") .setType(TypeName.get(boolean.class)) .setValue(false) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -246,6 +251,7 @@ public final class Repositories { .setDescription("Toggles whether converters should be injected as constructor parameters.") .setType(TypeName.get(boolean.class)) .setValue(false) + .addTags(Tags.FRONT_MATTER) .addExamples(ConfigurationExample.builder() .setValue("false") .setDescription("The default value of the `injectConverters` configuration option is `false`. It produces code similar to this:") @@ -298,6 +304,7 @@ public final class Repositories { .setDescription("The method prefix to use for generated standard methods.") .setType(ClassName.get(String.class)) .setValue("") + .addTags(Tags.FRONT_MATTER) .build(); } @@ -307,6 +314,7 @@ public final class Repositories { .setDescription("The method suffix to use for generated standard methods.") .setType(ClassName.get(String.class)) .setValue("") + .addTags(Tags.FRONT_MATTER) .build(); } @@ -316,6 +324,7 @@ public final class Repositories { .setDescription("The method prefix to use for generated batch methods.") .setType(ClassName.get(String.class)) .setValue("") + .addTags(Tags.FRONT_MATTER) .build(); } @@ -325,6 +334,7 @@ public final class Repositories { .setDescription("The method suffix to use for generated batch methods.") .setType(ClassName.get(String.class)) .setValue("Batch") + .addTags(Tags.FRONT_MATTER) .build(); } diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Sql.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Sql.java index 10840d60..e9b18a76 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Sql.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Sql.java @@ -14,10 +14,7 @@ import com.squareup.javapoet.*; import org.immutables.value.Value; import wtf.metio.yosql.internals.javapoet.TypicalTypes; import wtf.metio.yosql.internals.jdk.Strings; -import wtf.metio.yosql.models.configuration.ResultRowConverter; -import wtf.metio.yosql.models.configuration.ReturningMode; -import wtf.metio.yosql.models.configuration.SqlParameter; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.*; import wtf.metio.yosql.models.meta.ConfigurationGroup; import wtf.metio.yosql.models.meta.ConfigurationSetting; @@ -39,11 +36,10 @@ public final class Sql { .setImmutableAnnotations(extraTypeAnnotations()) .addAllSettings(settings()) .addAllSettings(withExtraAnnotations(stringRepositorySettings())) - .addAllSettings(withExtraAnnotations(booleanRepositorySettings())) + .addAllSettings(withExtraAnnotations(booleanRepositorySettings())) // TODO: remove injectConverters from this list .setImmutableMethods(List.of( fromStatements(), merge(), - mergeParameters(), converter(), batchName(), standardName(), @@ -54,14 +50,15 @@ public final class Sql { private static List settings() { return List.of( repository(), - repositoryInterface(), + repositoryInterface(), // TODO: add JsonIgnore on this one? name(), description(), vendor(), type(), returningMode(), resultRowConverter(), - parameters()); + parameters(), + annotations()); } private static List stringRepositorySettings() { @@ -107,6 +104,7 @@ public final class Sql { .setDescription("The fully qualified name of the target repository class.") .setType(TypeName.get(String.class)) .setImmutableAnnotations(List.of(jsonProperty("repository"))) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -124,6 +122,7 @@ public final class Sql { .setDescription("The name of the SQL statement") .setType(TypeName.get(String.class)) .setImmutableAnnotations(List.of(jsonProperty("name"))) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -133,6 +132,7 @@ public final class Sql { .setDescription("The description for the SQL statement") .setType(TypeName.get(String.class)) .setImmutableAnnotations(List.of(jsonProperty("description"))) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -142,6 +142,7 @@ public final class Sql { .setDescription("The vendor name of the database the SQL statement is intended for") .setType(TypeName.get(String.class)) .setImmutableAnnotations(List.of(jsonProperty("vendor"))) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -149,8 +150,9 @@ public final class Sql { return ConfigurationSetting.builder() .setName("type") .setDescription("The type of the SQL statement.") - .setType(TypeName.get(SqlType.class)) + .setType(TypeName.get(SqlStatementType.class)) .setImmutableAnnotations(List.of(jsonProperty("type"))) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -160,6 +162,7 @@ public final class Sql { .setDescription("The returning mode of the SQL statement.") .setType(TypeName.get(ReturningMode.class)) .setImmutableAnnotations(List.of(jsonProperty("returning"))) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -168,6 +171,7 @@ public final class Sql { .setName("resultRowConverter") .setDescription("The alias or fully-qualified name of the converter to use") .setType(TypeName.get(ResultRowConverter.class)) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -177,6 +181,17 @@ public final class Sql { .setDescription("The parameters of the SQL statement.") .setType(TypicalTypes.listOf(TypeName.get(SqlParameter.class))) .setValue(CodeBlock.builder().add("$T.of()", List.class).build()) + .addTags(Tags.FRONT_MATTER) + .build(); + } + + private static ConfigurationSetting annotations() { + return ConfigurationSetting.builder() + .setName("annotations") + .setDescription("The additional annotations to be placed on generated methods.") + .setType(TypicalTypes.listOf(Annotation.class)) + .setValue(CodeBlock.builder().add("$T.of()", List.class).build()) + .addTags(Tags.FRONT_MATTER) .build(); } @@ -205,9 +220,10 @@ public final class Sql { .addParameter(ParameterSpec.builder(configuration, "first", Modifier.FINAL).build()) .addParameter(ParameterSpec.builder(configuration, "second", Modifier.FINAL).build()) .returns(configuration) - .addStatement("var merged = $T.copyOf($L)", configuration, "first") - .addCode(withAllSettings()) - .addStatement("return merged") + .addStatement(CodeBlock.builder() + .add("return $T.copyOf($L)", configuration, "first") + .add(withAllSettings()) + .build()) .build(); } @@ -224,55 +240,25 @@ public final class Sql { } private static void addSetting(final CodeBlock.Builder builder, final ConfigurationSetting setting) { - if (TypeName.get(Boolean.class).equals(setting.type()) - || TypeName.get(String.class).equals(setting.type()) - || TypeName.get(SqlType.class).equals(setting.type()) - || TypeName.get(ReturningMode.class).equals(setting.type())) { - builder.beginControlFlow("if (first.$L().or(() -> second.$L()).isPresent())", - setting.name(), setting.name()); - builder.addStatement("merged = merged.with$L(first.$L().or(() -> second.$L()).get())", - Strings.upperCase(setting.name()), setting.name(), setting.name()); - builder.endControlFlow(); - } else if (TypeName.get(ResultRowConverter.class).equals(setting.type())) { - builder.addStatement("merged = merged.with$L(first.$L().or(second::resultRowConverter))", - Strings.upperCase(setting.name()), setting.name()); - } else if (TypicalTypes.listOf(TypeName.get(SqlParameter.class)).equals(setting.type())) { - builder.addStatement("merged = merged.with$L(mergeParameters(first.$L(), second.$L()))", + if (TypicalTypes.listOf(TypeName.get(SqlParameter.class)).equals(setting.type())) { + builder.add("$>$>\n.with$L($T.mergeParameters(first.$L(), second.$L()))$<$<", + Strings.upperCase(setting.name()), SqlParameter.class, setting.name(), setting.name()); + } else if (TypicalTypes.listOf(TypeName.get(Annotation.class)).equals(setting.type())) { + builder.add("$>$>\n.with$L($T.mergeAnnotations(first.$L(), second.$L()))$<$<", + Strings.upperCase(setting.name()), Annotation.class, setting.name(), setting.name()); + } else { + builder.add("$>$>\n.with$L(first.$L().or(second::$L))$<$<", Strings.upperCase(setting.name()), setting.name(), setting.name()); } } - private static MethodSpec mergeParameters() { - final var listOfParameters = TypicalTypes.listOf(TypeName.get(SqlParameter.class)); - return MethodSpec.methodBuilder("mergeParameters") - .addModifiers(Modifier.PRIVATE, Modifier.STATIC) - .addParameter(ParameterSpec.builder(listOfParameters, "first", Modifier.FINAL).build()) - .addParameter(ParameterSpec.builder(listOfParameters, "second", Modifier.FINAL).build()) - .returns(listOfParameters) - .beginControlFlow("if (first == null || first.isEmpty())") - .addStatement("return second") - .endControlFlow() - .addCode("return first.stream()") - .addCode("$>\n.map(param -> second.stream()") - .addCode("$>\n.filter(op -> param.name().equals(op.name()))$<") - .addCode("\n.findFirst()") - .addCode("\n.map(other -> $T.builder()", SqlParameter.class) - .addCode("$>\n.setName(param.name())") - .addCode("\n.setType($T.class.getName().equals(param.type()) ? other.type() : param.type())", Object.class) - .addCode("\n.setIndices(param.indices() == null ? other.indices() : param.indices())") - .addCode("\n.setConverter(param.converter().or(other::converter))") - .addCode("\n.build())$<") - .addCode("\n.orElse($T.copy(param)))$<", SqlParameter.class) - .addStatement("\n.collect($T.toList())", Collectors.class) - .build(); - } - private static MethodSpec converter() { final var parameterType = TypicalTypes.supplierOf(TypicalTypes.optionalOf(ResultRowConverter.class)); return MethodSpec.methodBuilder("converter") .addModifiers(Modifier.DEFAULT, Modifier.PUBLIC) .addParameter(ParameterSpec.builder(parameterType, "defaultConverter").build()) .returns(ResultRowConverter.class) + .addAnnotation(Value.Lazy.class) .addStatement(CodeBlock.builder() .add("return resultRowConverter()") .add("$>\n.or(defaultConverter)") diff --git a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Tags.java b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Tags.java index 0526b728..54d900cf 100644 --- a/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Tags.java +++ b/yosql-models/yosql-models-meta/src/main/java/wtf/metio/yosql/models/meta/data/Tags.java @@ -16,5 +16,10 @@ public final class Tags { public static final String FIELDS = "fields"; public static final String METHODS = "methods"; public static final String THREADS = "threads"; + public static final String FRONT_MATTER = "frontmatter"; // TODO: tag all settings that can be changed in the frontmatter and link to sitemap/tags in website + + private Tags() { + // constants class + } } diff --git a/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/AnnotationsConfigurations.java b/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/AnnotationsConfigurations.java index 6914d9da..af4008ec 100644 --- a/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/AnnotationsConfigurations.java +++ b/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/AnnotationsConfigurations.java @@ -7,7 +7,7 @@ package wtf.metio.yosql.testing.configs; -import wtf.metio.yosql.models.configuration.AnnotationApis; +import wtf.metio.yosql.models.configuration.GeneratedAnnotationApis; import wtf.metio.yosql.models.immutables.AnnotationsConfiguration; /** @@ -25,7 +25,7 @@ public final class AnnotationsConfigurations { public static AnnotationsConfiguration generated() { return AnnotationsConfiguration.copyOf(defaults()) - .withAnnotationApi(AnnotationApis.ANNOTATION_API); + .withAnnotationApi(GeneratedAnnotationApis.ANNOTATION_API); } private AnnotationsConfigurations() { diff --git a/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/SqlConfigurations.java b/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/SqlConfigurations.java index face9cdf..19327a0c 100644 --- a/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/SqlConfigurations.java +++ b/yosql-testing/yosql-testing-configs/src/main/java/wtf/metio/yosql/testing/configs/SqlConfigurations.java @@ -10,7 +10,7 @@ package wtf.metio.yosql.testing.configs; import wtf.metio.yosql.models.configuration.ResultRowConverter; import wtf.metio.yosql.models.configuration.ReturningMode; import wtf.metio.yosql.models.configuration.SqlParameter; -import wtf.metio.yosql.models.configuration.SqlType; +import wtf.metio.yosql.models.configuration.SqlStatementType; import wtf.metio.yosql.models.immutables.SqlConfiguration; import wtf.metio.yosql.models.immutables.SqlStatement; @@ -53,7 +53,7 @@ public final class SqlConfigurations { public static SqlConfiguration sqlConfiguration() { final var config = SqlConfiguration.builder(); config.setName("queryData"); - config.setType(SqlType.READING); + config.setType(SqlStatementType.READING); config.setReturningMode(ReturningMode.MULTIPLE); config.setRepository("com.example.persistence.DataRepository"); config.setCatchAndRethrow(true); diff --git a/yosql-tooling/pom.xml b/yosql-tooling/pom.xml index 05d60568..b457d771 100644 --- a/yosql-tooling/pom.xml +++ b/yosql-tooling/pom.xml @@ -44,7 +44,8 @@ yosql-tooling-dagger yosql-tooling-maven - yosql-tooling-cli + + @@ -53,4 +54,4 @@ - \ No newline at end of file + diff --git a/yosql-tooling/yosql-tooling-dagger/src/main/java/wtf/metio/yosql/tooling/dagger/files/DefaultFilesModule.java b/yosql-tooling/yosql-tooling-dagger/src/main/java/wtf/metio/yosql/tooling/dagger/files/DefaultFilesModule.java index 45584595..0e206789 100644 --- a/yosql-tooling/yosql-tooling-dagger/src/main/java/wtf/metio/yosql/tooling/dagger/files/DefaultFilesModule.java +++ b/yosql-tooling/yosql-tooling-dagger/src/main/java/wtf/metio/yosql/tooling/dagger/files/DefaultFilesModule.java @@ -27,8 +27,8 @@ public class DefaultFilesModule { @Provides @Singleton - SqlConfigurationParser provideSqlConfigurationParser() { - return new DefaultSqlConfigurationParser(); + SqlConfigurationParser provideSqlConfigurationParser(final ExecutionErrors errors) { + return new DefaultSqlConfigurationParser(errors); } @Provides @@ -71,8 +71,8 @@ public class DefaultFilesModule { @Provides @Singleton - MethodConverterConfigurer provideMethodConverterConfigurer(final RuntimeConfiguration runtimeConfiguration) { - return new DefaultMethodConverterConfigurer(runtimeConfiguration.converter()); + MethodResultRowConverterConfigurer provideMethodConverterConfigurer(final RuntimeConfiguration runtimeConfiguration) { + return new DefaultMethodResultRowConverterConfigurer(runtimeConfiguration.converter()); } @Provides @@ -93,7 +93,7 @@ public class DefaultFilesModule { final MethodNameValidator methodNameValidator, final MethodApiConfigurer methodApis, final MethodParameterConfigurer methodParameters, - final MethodConverterConfigurer methodConverter, + final MethodResultRowConverterConfigurer methodConverter, final RepositoryNameConfigurer repositoryName) { return new DefaultSqlConfigurationFactory( logger, @@ -109,16 +109,6 @@ public class DefaultFilesModule { @Provides @Singleton - FileResolver provideSqlFileResolver( - @Reader final LocLogger logger, - final ParserPreconditions preconditions, - final RuntimeConfiguration runtimeConfiguration, - final ExecutionErrors errors) { - return new DefaultFileResolver(logger, preconditions, runtimeConfiguration.files(), errors); - } - - @Provides - @Singleton SqlStatementParser provideSqlFileParser( @Parser final LocLogger logger, final SqlConfigurationFactory factory, @@ -130,9 +120,17 @@ public class DefaultFilesModule { @Provides @Singleton FileParser provideFileParser( - final FileResolver fileResolver, + @Reader final LocLogger logger, + final ParserPreconditions preconditions, + final RuntimeConfiguration runtimeConfiguration, + final ExecutionErrors errors, final SqlStatementParser fileParser) { - return new DefaultFileParser(fileResolver, fileParser); + return new DefaultFileParser( + logger, + preconditions, + runtimeConfiguration.files(), + errors, + fileParser); } @Provides diff --git a/yosql-tooling/yosql-tooling-gradle/src/main/java/wtf/metio/yosql/tooling/gradle/YoSqlPlugin.java b/yosql-tooling/yosql-tooling-gradle/src/main/java/wtf/metio/yosql/tooling/gradle/YoSqlPlugin.java index 8bdd142e..db49641b 100644 --- a/yosql-tooling/yosql-tooling-gradle/src/main/java/wtf/metio/yosql/tooling/gradle/YoSqlPlugin.java +++ b/yosql-tooling/yosql-tooling-gradle/src/main/java/wtf/metio/yosql/tooling/gradle/YoSqlPlugin.java @@ -23,17 +23,13 @@ public class YoSqlPlugin implements Plugin { @Override public void apply(final Project project) { - final var extension = createExtension(project); + final var extension = project.getExtensions().create("yosql", YoSqlExtension.class); configureConventions(extension, project.getLayout(), project.getObjects()); registerTask(project, extension); configureSourceSets(project, extension); } - private YoSqlExtension createExtension(final Project project) { - return project.getExtensions().create("yosql", YoSqlExtension.class); - } - - private void configureConventions( + private static void configureConventions( final YoSqlExtension extension, final ProjectLayout layout, final ObjectFactory objects) { @@ -47,14 +43,14 @@ public class YoSqlPlugin implements Plugin { extension.getResources().configureConventions(); } - private void registerTask(final Project project, final YoSqlExtension extension) { + private static void registerTask(final Project project, final YoSqlExtension extension) { final var generate = project.getTasks().register("generateJavaCode", GenerateCodeTask.class, new GenerateTaskConfiguration(extension)); project.getTasks().withType(JavaCompile.class, task -> task.doFirst("yosql", new GenerateCodeAction(generate))); } - private void configureSourceSets(final Project project, final YoSqlExtension extension) { + private static void configureSourceSets(final Project project, final YoSqlExtension extension) { project.getPlugins().withType(JavaPlugin.class, plugin -> project.getExtensions() .getByType(JavaPluginExtension.class) .getSourceSets() -- 2.11.4.GIT