├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── beyt │ └── jdq │ ├── annotation │ ├── EnableJpaDynamicQuery.java │ ├── EnableJpaDynamicQueryArgumentResolvers.java │ └── model │ │ ├── JdqField.java │ │ ├── JdqIgnoreField.java │ │ ├── JdqModel.java │ │ └── JdqSubModel.java │ ├── config │ ├── ArgumentResolversInitConfig.java │ ├── DeserializerConfig.java │ └── EntityManagerProviderConfig.java │ ├── deserializer │ ├── BasicDeserializer.java │ ├── IDeserializer.java │ └── JacksonDeserializer.java │ ├── dto │ ├── Criteria.java │ ├── CriteriaList.java │ ├── DynamicQuery.java │ └── enums │ │ ├── CriteriaOperator.java │ │ ├── JoinType.java │ │ └── Order.java │ ├── exception │ ├── DynamicQueryIllegalArgumentException.java │ ├── DynamicQueryNoAvailableEnumException.java │ ├── DynamicQueryNoAvailableOperationException.java │ ├── DynamicQueryNoAvailableOrOperationUsageException.java │ ├── DynamicQueryNoAvailableParenthesesOperationUsageException.java │ ├── DynamicQueryNoAvailableValueException.java │ ├── DynamicQueryNoFirstValueException.java │ └── DynamicQueryValueSerializeException.java │ ├── provider │ └── IEntityManagerProvider.java │ ├── query │ ├── DynamicQueryManager.java │ ├── DynamicSpecification.java │ ├── builder │ │ ├── QueryBuilder.java │ │ ├── QuerySimplifier.java │ │ └── interfaces │ │ │ ├── DistinctWhereOrderByPage.java │ │ │ ├── OrderByPage.java │ │ │ ├── PageableResult.java │ │ │ ├── Result.java │ │ │ └── WhereOrderByPage.java │ └── rule │ │ ├── sort │ │ ├── ISortFilterRule.java │ │ ├── SortFilterAscRule.java │ │ └── SortFilterDescRule.java │ │ ├── specification │ │ ├── ISpecificationFilterRule.java │ │ ├── SpecificationFilterDoesNotContainRule.java │ │ ├── SpecificationFilterDoubleLikeRule.java │ │ ├── SpecificationFilterEqualRule.java │ │ ├── SpecificationFilterGreaterThanOrEqualToRule.java │ │ ├── SpecificationFilterGreaterThanRule.java │ │ ├── SpecificationFilterLeftLikeRule.java │ │ ├── SpecificationFilterLessThanOrEqualToRule.java │ │ ├── SpecificationFilterLessThanRule.java │ │ ├── SpecificationFilterNotEqualRule.java │ │ ├── SpecificationFilterRightLikeRule.java │ │ └── SpecificationFilterSpecifiedRule.java │ │ └── top │ │ ├── IPageFilterRule.java │ │ ├── PageFilterAscRule.java │ │ ├── PageFilterDescRule.java │ │ ├── TopFilterAscRule.java │ │ └── TopFilterDescRule.java │ ├── repository │ ├── DynamicSpecificationRepository.java │ ├── DynamicSpecificationRepositoryFactoryBean.java │ ├── DynamicSpecificationRepositoryImpl.java │ └── JpaDynamicQueryRepository.java │ ├── resolver │ ├── CriteriaListArgumentResolver.java │ └── DynamicQueryArgumentResolver.java │ └── util │ ├── ApplicationContextUtil.java │ ├── ListConsumer.java │ ├── ReflectionUtil.java │ ├── SpecificationUtil.java │ ├── StringUtil.java │ └── field │ ├── FieldUtil.java │ └── helper │ ├── BooleanFieldHelper.java │ ├── DateFieldHelper.java │ ├── DoubleFieldHelper.java │ ├── EnumFieldHelper.java │ ├── IFieldHelper.java │ ├── InstantFieldHelper.java │ ├── IntegerFieldHelper.java │ ├── LocalDateFieldHelper.java │ ├── LongFieldHelper.java │ ├── StringFieldHelper.java │ ├── TimestampFieldHelper.java │ └── ZonedDateTimeFieldHelper.java └── test ├── java └── com │ └── beyt │ └── jdq │ ├── BaseTestInstance.java │ ├── TestApplication.java │ ├── TestUtil.java │ ├── context │ └── DBSelectionContext.java │ ├── controller │ └── PresentationTestController.java │ ├── deserializer │ └── DateTimeDeserializer.java │ ├── interceptor │ └── DatabaseSelectionInterceptor.java │ ├── presetation │ ├── S10_Argument_Resolvers.java │ ├── S11_Additional_Features.java │ ├── S1_Operators.java │ ├── S2_Multi_Value_Operators.java │ ├── S3_AND_OR_Operator.java │ ├── S4_SCOPE_Operator.java │ ├── S5_Join.java │ ├── S6_Advenced_Join.java │ ├── S7_Select_Distinct_Order.java │ ├── S8_Advenced_Projection.java │ └── S9_Query_Builder.java │ ├── query │ ├── DynamicQueryManagerTest.java │ └── DynamicSpecificationTest.java │ ├── resolver │ └── ArgumentResolversTests.java │ ├── testenv │ ├── config │ │ └── DynamicSpecificationRepositoryConfiguration.java │ ├── controller │ │ └── TestController.java │ ├── entity │ │ ├── Customer.java │ │ ├── User.java │ │ ├── authorization │ │ │ ├── AdminUser.java │ │ │ ├── Authorization.java │ │ │ ├── Role.java │ │ │ └── RoleAuthorization.java │ │ └── school │ │ │ ├── Address.java │ │ │ ├── Course.java │ │ │ ├── Department.java │ │ │ └── Student.java │ └── repository │ │ ├── AddressRepository.java │ │ ├── AdminUserRepository.java │ │ ├── AuthorizationRepository.java │ │ ├── CourseRepository.java │ │ ├── CustomerRepository.java │ │ ├── DepartmentRepository.java │ │ ├── RoleAuthorizationRepository.java │ │ ├── RoleRepository.java │ │ ├── StudentRepository.java │ │ ├── UserRepository.java │ │ └── field │ │ └── FieldUtilTest.java │ └── util │ └── PresentationUtil.java └── resources └── config ├── application.yml ├── data.sql └── init.sql /.gitignore: -------------------------------------------------------------------------------- 1 | ###################### 2 | # Project Specific 3 | ###################### 4 | /src/main/webapp/content/css/main.css 5 | /src/test/javascript/coverage/ 6 | 7 | ###################### 8 | # Node 9 | ###################### 10 | /node/ 11 | node_tmp/ 12 | node_modules/ 13 | npm-debug.log.* 14 | /.awcache/* 15 | /.cache-loader/* 16 | 17 | ###################### 18 | # SASS 19 | ###################### 20 | .sass-cache/ 21 | 22 | ###################### 23 | # Eclipse 24 | ###################### 25 | *.pydevproject 26 | .project 27 | .metadata 28 | tmp/ 29 | tmp/**/* 30 | *.tmp 31 | *.bak 32 | *.swp 33 | *~.nib 34 | local.properties 35 | .classpath 36 | .settings/ 37 | .loadpath 38 | .factorypath 39 | /src/main/resources/rebel.xml 40 | 41 | # External tool builders 42 | .externalToolBuilders/** 43 | 44 | # Locally stored "Eclipse launch configurations" 45 | *.launch 46 | 47 | # CDT-specific 48 | .cproject 49 | 50 | # PDT-specific 51 | .buildpath 52 | 53 | # STS-specific 54 | /.sts4-cache/* 55 | 56 | ###################### 57 | # IntelliJ 58 | ###################### 59 | .idea/ 60 | *.iml 61 | *.iws 62 | *.ipr 63 | *.ids 64 | *.orig 65 | classes/ 66 | out/ 67 | 68 | ###################### 69 | # Visual Studio Code 70 | ###################### 71 | .vscode/ 72 | 73 | ###################### 74 | # Maven 75 | ###################### 76 | /log/ 77 | 78 | ###################### 79 | # Gradle 80 | ###################### 81 | .gradle/ 82 | /build/ 83 | 84 | ###################### 85 | # Package Files 86 | ###################### 87 | *.jar 88 | *.war 89 | *.ear 90 | *.db 91 | 92 | ###################### 93 | # Windows 94 | ###################### 95 | # Windows image file caches 96 | Thumbs.db 97 | 98 | # Folder config file 99 | Desktop.ini 100 | 101 | ###################### 102 | # Mac OSX 103 | ###################### 104 | .DS_Store 105 | .svn 106 | 107 | # Thumbnails 108 | ._* 109 | 110 | # Files that might appear on external disk 111 | .Spotlight-V100 112 | .Trashes 113 | 114 | ###################### 115 | # Directories 116 | ###################### 117 | /bin/ 118 | /deploy/ 119 | 120 | ###################### 121 | # Logs 122 | ###################### 123 | *.log* 124 | 125 | ###################### 126 | # Others 127 | ###################### 128 | *.class 129 | *.*~ 130 | *~ 131 | .merge_file* 132 | 133 | ###################### 134 | # Gradle Wrapper 135 | ###################### 136 | !gradle/wrapper/gradle-wrapper.jar 137 | 138 | ###################### 139 | # Maven Wrapper 140 | ###################### 141 | !.mvn/wrapper/maven-wrapper.jar 142 | 143 | ###################### 144 | # ESLint 145 | ###################### 146 | .eslintcache 147 | 148 | */target/** 149 | 150 | /nexts/ 151 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 3.3.3 11 | 12 | 13 | 14 | io.github.tdilber 15 | spring-boot-starter-jpa-dynamic-query 16 | 0.3.0 17 | jar 18 | Spring Jpa Dynamic Query 19 | Spring Jpa Dynamic Query (JDQ) Project 20 | https://github.com/tdilber/spring-jpa-generic-criteria 21 | 22 | 23 | 24 | The Apache License, Version 2.0 25 | http://www.apache.org/licenses/LICENSE-2.0.txt 26 | 27 | 28 | 29 | 30 | 31 | Talha Dilber 32 | dilber.talha@gmail.com 33 | 34 | 35 | 36 | 37 | scm:git:git://github.com/tdilber/spring-jpa-generic-criteria.git 38 | scm:git:ssh://github.com:tdilber/spring-jpa-generic-criteria.git 39 | http://github.com/tdilber/spring-jpa-generic-criteria/tree/master 40 | 41 | 42 | 43 | 44 | 17 45 | UTF-8 46 | 47 | 48 | 49 | 50 | org.springframework 51 | spring-web 52 | 53 | 54 | org.springframework 55 | spring-webmvc 56 | 57 | 58 | com.fasterxml.jackson.core 59 | jackson-databind 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-autoconfigure 64 | 65 | 66 | org.springframework.data 67 | spring-data-commons 68 | 69 | 70 | org.springframework.data 71 | spring-data-jpa 72 | 73 | 74 | jakarta.persistence 75 | jakarta.persistence-api 76 | 77 | 78 | org.hibernate 79 | hibernate-core 80 | ${hibernate.version} 81 | 82 | 83 | org.projectlombok 84 | lombok 85 | true 86 | 87 | 88 | org.apache.commons 89 | commons-collections4 90 | 4.4 91 | 92 | 93 | org.apache.commons 94 | commons-lang3 95 | 96 | 97 | 98 | 99 | org.springframework.boot 100 | spring-boot-starter-test 101 | test 102 | 103 | 104 | org.springframework.boot 105 | spring-boot-starter-web 106 | test 107 | 108 | 109 | org.springframework.boot 110 | spring-boot-starter-data-jpa 111 | test 112 | 113 | 114 | com.h2database 115 | h2 116 | test 117 | 118 | 119 | com.google.code.gson 120 | gson 121 | test 122 | 123 | 124 | 125 | 126 | 127 | ossrh 128 | https://s01.oss.sonatype.org/content/repositories/snapshots 129 | 130 | 131 | ossrh 132 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 133 | 134 | 135 | 136 | 137 | 138 | 139 | org.apache.maven.plugins 140 | maven-source-plugin 141 | ${maven-source-plugin.version} 142 | 143 | 144 | attach-sources 145 | 146 | jar-no-fork 147 | 148 | 149 | 150 | 151 | 152 | org.apache.maven.plugins 153 | maven-javadoc-plugin 154 | ${maven-javadoc-plugin.version} 155 | 156 | 157 | attach-javadocs 158 | package 159 | 160 | jar 161 | 162 | 163 | 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-gpg-plugin 168 | 1.5 169 | 170 | 171 | sign-artifacts 172 | verify 173 | 174 | sign 175 | 176 | 177 | 178 | 179 | 180 | org.sonatype.central 181 | central-publishing-maven-plugin 182 | 0.3.0 183 | true 184 | 185 | central 186 | true 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/annotation/EnableJpaDynamicQuery.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.annotation; 2 | 3 | import com.beyt.jdq.config.DeserializerConfig; 4 | import com.beyt.jdq.config.EntityManagerProviderConfig; 5 | import com.beyt.jdq.util.ApplicationContextUtil; 6 | import org.springframework.context.annotation.Import; 7 | 8 | import java.lang.annotation.ElementType; 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.RetentionPolicy; 11 | import java.lang.annotation.Target; 12 | 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target({ElementType.TYPE}) 15 | @Import({ApplicationContextUtil.class, EntityManagerProviderConfig.class, DeserializerConfig.class}) 16 | public @interface EnableJpaDynamicQuery { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/annotation/EnableJpaDynamicQueryArgumentResolvers.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.annotation; 2 | 3 | import com.beyt.jdq.config.ArgumentResolversInitConfig; 4 | import com.beyt.jdq.resolver.CriteriaListArgumentResolver; 5 | import com.beyt.jdq.resolver.DynamicQueryArgumentResolver; 6 | import org.springframework.context.annotation.Import; 7 | 8 | import java.lang.annotation.ElementType; 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.RetentionPolicy; 11 | import java.lang.annotation.Target; 12 | 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Import({ArgumentResolversInitConfig.class, CriteriaListArgumentResolver.class, DynamicQueryArgumentResolver.class}) 15 | @Target({ElementType.TYPE}) 16 | @EnableJpaDynamicQuery 17 | public @interface EnableJpaDynamicQueryArgumentResolvers { 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/annotation/model/JdqField.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.annotation.model; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.FIELD}) 11 | public @interface JdqField { 12 | String value(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/annotation/model/JdqIgnoreField.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.annotation.model; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.FIELD}) 11 | public @interface JdqIgnoreField { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/annotation/model/JdqModel.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.annotation.model; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.TYPE}) 11 | public @interface JdqModel { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/annotation/model/JdqSubModel.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.annotation.model; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.FIELD}) 11 | public @interface JdqSubModel { 12 | String value() default ""; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/config/ArgumentResolversInitConfig.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.config; 2 | 3 | import com.beyt.jdq.resolver.CriteriaListArgumentResolver; 4 | import com.beyt.jdq.resolver.DynamicQueryArgumentResolver; 5 | import org.springframework.beans.factory.config.BeanDefinition; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Role; 8 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | import java.util.List; 12 | 13 | @Configuration 14 | @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 15 | public class ArgumentResolversInitConfig implements WebMvcConfigurer { 16 | 17 | private final CriteriaListArgumentResolver criteriaListArgumentResolver; 18 | private final DynamicQueryArgumentResolver dynamicQueryArgumentResolver; 19 | 20 | public ArgumentResolversInitConfig(CriteriaListArgumentResolver criteriaListArgumentResolver, DynamicQueryArgumentResolver dynamicQueryArgumentResolver) { 21 | this.criteriaListArgumentResolver = criteriaListArgumentResolver; 22 | this.dynamicQueryArgumentResolver = dynamicQueryArgumentResolver; 23 | } 24 | 25 | @Override 26 | public void addArgumentResolvers(List resolvers) { 27 | resolvers.add(criteriaListArgumentResolver); 28 | resolvers.add(dynamicQueryArgumentResolver); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/config/DeserializerConfig.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.config; 2 | 3 | import com.beyt.jdq.deserializer.BasicDeserializer; 4 | import com.beyt.jdq.deserializer.IDeserializer; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class DeserializerConfig { 11 | 12 | @Bean 13 | @ConditionalOnMissingBean 14 | public IDeserializer basicDeserializer() { 15 | return new BasicDeserializer(); 16 | // return new JacksonDeserializer();// TODO 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/config/EntityManagerProviderConfig.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.config; 2 | 3 | import com.beyt.jdq.provider.IEntityManagerProvider; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import jakarta.persistence.EntityManager; 9 | 10 | @Configuration 11 | public class EntityManagerProviderConfig { 12 | 13 | @Bean 14 | @ConditionalOnMissingBean 15 | public IEntityManagerProvider entityManagerProvider(EntityManager entityManager) { 16 | return () -> entityManager; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/deserializer/BasicDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.deserializer; 2 | 3 | import com.beyt.jdq.util.ReflectionUtil; 4 | 5 | public class BasicDeserializer implements IDeserializer { 6 | @Override 7 | public T deserialize(Object value, Class clazz) throws Exception { 8 | return ReflectionUtil.deserializeObject(value.toString(), clazz); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/deserializer/IDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.deserializer; 2 | 3 | public interface IDeserializer { 4 | T deserialize(Object value, Class clazz) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/deserializer/JacksonDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.deserializer; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.MapperFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.json.JsonMapper; 7 | 8 | public class JacksonDeserializer implements IDeserializer { 9 | 10 | public static final ObjectMapper mapper; 11 | 12 | static { 13 | mapper = JsonMapper.builder() 14 | .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) 15 | .build(); 16 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 17 | } 18 | 19 | @Override 20 | public T deserialize(Object value, Class clazz) throws Exception { 21 | if (value.getClass().isAssignableFrom(clazz)) { 22 | return (T) value; 23 | } 24 | 25 | if (clazz.isEnum()) { 26 | return (T) Enum.valueOf((Class) clazz, value.toString()); 27 | } 28 | return mapper.readValue(value.toString(), clazz); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/dto/Criteria.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.dto; 2 | 3 | 4 | import com.beyt.jdq.dto.enums.CriteriaOperator; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | import java.io.Serializable; 9 | import java.util.Arrays; 10 | import java.util.Collection; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by tdilber at 24-Aug-19 15 | */ 16 | @Getter 17 | @Setter 18 | public class Criteria implements Serializable { 19 | protected String key; 20 | protected CriteriaOperator operation; 21 | protected List values; 22 | 23 | public static Criteria of(String key, CriteriaOperator operation, Collection values) { 24 | return new Criteria(key, operation, values); 25 | } 26 | 27 | public static Criteria of(String key, CriteriaOperator operation, Object... values) { 28 | return new Criteria(key, operation, values); 29 | } 30 | 31 | public Criteria(String key, CriteriaOperator operation, Object... values) { 32 | this.key = key; 33 | this.operation = operation; 34 | this.values = values != null ? Arrays.asList(values) : null; 35 | } 36 | 37 | public static Criteria OR() { 38 | return Criteria.of("", CriteriaOperator.OR); 39 | } 40 | 41 | public Criteria() { 42 | 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | StringBuilder result = new StringBuilder("key: " + key + " Criteria Operation: " + operation.name() + " "); 48 | for (int i = 0; i < values.size(); i++) { 49 | result.append("value").append(i).append(": ").append(values.get(i)); 50 | } 51 | return result.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/dto/CriteriaList.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.dto; 2 | 3 | import com.beyt.jdq.dto.enums.CriteriaOperator; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import java.io.Serializable; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.Collection; 10 | import java.util.List; 11 | 12 | /** 13 | * Created by tdilber at 11/18/2020 14 | */ 15 | @Slf4j 16 | public class CriteriaList extends ArrayList implements Serializable { 17 | 18 | public static CriteriaList of(Criteria... criteria) { 19 | CriteriaList criteriaList = new CriteriaList(); 20 | criteriaList.addAll(Arrays.asList(criteria)); 21 | return criteriaList; 22 | } 23 | 24 | public static CriteriaList of(Collection criteria) { 25 | CriteriaList criteriaList = new CriteriaList(); 26 | criteriaList.addAll(criteria); 27 | return criteriaList; 28 | } 29 | 30 | public List getCriteriaListByKeyAndOperation(String key, CriteriaOperator operation) { 31 | ArrayList criterias = new ArrayList<>(); 32 | 33 | for (Criteria criteria : this) { 34 | if (criteria.key.equalsIgnoreCase(key) && criteria.operation.equals(operation)) { 35 | criterias.add(criteria); 36 | } 37 | } 38 | 39 | return criterias; 40 | } 41 | 42 | 43 | public List getCriteriaListByKey(String key) { 44 | ArrayList criterias = new ArrayList<>(); 45 | 46 | for (Criteria criteria : this) { 47 | if (criteria.key.equalsIgnoreCase(key)) { 48 | criterias.add(criteria); 49 | } 50 | } 51 | 52 | return criterias; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | StringBuilder result = new StringBuilder(); 58 | 59 | for (Criteria criteria : this) { 60 | result.append("{").append(criteria.toString()).append("}"); 61 | } 62 | 63 | return result.toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/dto/DynamicQuery.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.dto; 2 | 3 | import com.beyt.jdq.dto.enums.Order; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.data.util.Pair; 6 | 7 | import java.io.Serializable; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by tdilber at 30-Dec-20 13 | */ 14 | @Slf4j 15 | public class DynamicQuery implements Serializable { 16 | 17 | protected boolean distinct = false; 18 | protected Integer pageSize = null; 19 | protected Integer pageNumber = null; 20 | protected List> select = new ArrayList<>(); 21 | protected List where = new CriteriaList(); 22 | protected List> orderBy = new ArrayList<>(); 23 | 24 | public boolean isDistinct() { 25 | return distinct; 26 | } 27 | 28 | public void setDistinct(boolean distinct) { 29 | this.distinct = distinct; 30 | } 31 | 32 | public List> getSelect() { 33 | return select; 34 | } 35 | 36 | public void setSelect(List> select) { 37 | this.select = select; 38 | } 39 | 40 | public List getWhere() { 41 | return where; 42 | } 43 | 44 | public void setWhere(List where) { 45 | this.where = where; 46 | } 47 | 48 | public List> getOrderBy() { 49 | return orderBy; 50 | } 51 | 52 | public void setOrderBy(List> orderBy) { 53 | this.orderBy = orderBy; 54 | } 55 | 56 | public Integer getPageSize() { 57 | return pageSize; 58 | } 59 | 60 | public void setPageSize(Integer pageSize) { 61 | this.pageSize = pageSize; 62 | } 63 | 64 | public Integer getPageNumber() { 65 | return pageNumber; 66 | } 67 | 68 | public void setPageNumber(Integer pageNumber) { 69 | this.pageNumber = pageNumber; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/dto/enums/CriteriaOperator.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.dto.enums; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * Created by tdilber at 15-Sep-19 8 | */ 9 | public enum CriteriaOperator implements Serializable { 10 | CONTAIN(1, "İçeriyor (String)"), 11 | DOES_NOT_CONTAIN(2, "İçermiyor (String)"), 12 | END_WITH(3, "İle bitiyor (String)"), 13 | START_WITH(4, "İle başlıyor (String)"), 14 | SPECIFIED(5, "Not Null ise 'true', Null ise 'false'"), 15 | EQUAL(6, "Eşittir"), 16 | NOT_EQUAL(7, "Eşit Değildir"), 17 | GREATER_THAN(8, "Büyüktür"), 18 | GREATER_THAN_OR_EQUAL(9, "Büyüktür veya eşittir"), 19 | LESS_THAN(10, "Küçüktür"), 20 | LESS_THAN_OR_EQUAL(11, "Küçüktür veya eşittir"), 21 | OR(12, "Veya (Konulduğu yeri 2 ye Böler) (key ve values önemsizdir)"), 22 | PARENTHES(13, "Sub Criteria"); 23 | 24 | private int value = -1; 25 | private String meaning; 26 | 27 | CriteriaOperator(int value, String meaning) { 28 | this.value = value; 29 | this.meaning = meaning; 30 | } 31 | 32 | public int getValue() { 33 | return value; 34 | } 35 | 36 | public String getMeaning() { 37 | return meaning; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/dto/enums/JoinType.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.dto.enums; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by tdilber at 7/13/2020 7 | */ 8 | public enum JoinType implements Serializable { 9 | INNER('.', jakarta.persistence.criteria.JoinType.INNER), 10 | LEFT('<', jakarta.persistence.criteria.JoinType.LEFT), 11 | RIGHT('>', jakarta.persistence.criteria.JoinType.RIGHT); 12 | 13 | private Character separator; 14 | private jakarta.persistence.criteria.JoinType joinType; 15 | 16 | JoinType(Character separator, jakarta.persistence.criteria.JoinType joinType) { 17 | this.separator = separator; 18 | this.joinType = joinType; 19 | } 20 | 21 | public Character getSeparator() { 22 | return separator; 23 | } 24 | 25 | public jakarta.persistence.criteria.JoinType getJoinType() { 26 | return joinType; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/dto/enums/Order.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.dto.enums; 2 | 3 | import org.springframework.data.domain.Sort; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * {@code Order} defines ascending and descending order 9 | * 10 | * @author tiwe 11 | */ 12 | public enum Order implements Serializable { 13 | /** 14 | * Ascending order 15 | */ 16 | ASC(Sort.Direction.ASC), 17 | /** 18 | * Descending order 19 | */ 20 | DESC(Sort.Direction.DESC); 21 | 22 | Order(Sort.Direction direction) { 23 | this.direction = direction; 24 | } 25 | 26 | private final Sort.Direction direction; 27 | 28 | public Sort.Direction getDirection() { 29 | return direction; 30 | } 31 | 32 | public static Order of(String orderText) { 33 | if (orderText.equalsIgnoreCase("desc")) { 34 | return DESC; 35 | } else if (orderText.equalsIgnoreCase("asc")) { 36 | return ASC; 37 | } else { 38 | throw new IllegalArgumentException("Order Direction Text not valid!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryIllegalArgumentException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 14-Seo-2024 7 | */ 8 | @Slf4j 9 | public class DynamicQueryIllegalArgumentException extends IllegalArgumentException { 10 | 11 | public DynamicQueryIllegalArgumentException(String errorMessage) { 12 | super(errorMessage); 13 | log.error(errorMessage, this); 14 | } 15 | 16 | public DynamicQueryIllegalArgumentException(String errorMessage, Throwable err) { 17 | super(errorMessage, err); 18 | log.error(errorMessage, err); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryNoAvailableEnumException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryNoAvailableEnumException extends RuntimeException { 10 | 11 | public DynamicQueryNoAvailableEnumException(String errorMessage) { 12 | super(errorMessage); 13 | log.error(errorMessage, this); 14 | } 15 | 16 | public DynamicQueryNoAvailableEnumException(String errorMessage, Throwable err) { 17 | super(errorMessage, err); 18 | log.error(errorMessage, err); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryNoAvailableOperationException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryNoAvailableOperationException extends RuntimeException { 10 | 11 | public DynamicQueryNoAvailableOperationException(String errorMessage) { 12 | super(errorMessage); 13 | log.error(errorMessage, this); 14 | } 15 | 16 | public DynamicQueryNoAvailableOperationException(String errorMessage, Throwable err) { 17 | super(errorMessage, err); 18 | log.error(errorMessage, err); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryNoAvailableOrOperationUsageException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryNoAvailableOrOperationUsageException extends RuntimeException { 10 | 11 | public DynamicQueryNoAvailableOrOperationUsageException(String errorMessage) { 12 | super(errorMessage); 13 | log.error(errorMessage, this); 14 | } 15 | 16 | public DynamicQueryNoAvailableOrOperationUsageException(String errorMessage, Throwable err) { 17 | super(errorMessage, err); 18 | log.error(errorMessage, err); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryNoAvailableParenthesesOperationUsageException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryNoAvailableParenthesesOperationUsageException extends RuntimeException { 10 | 11 | public DynamicQueryNoAvailableParenthesesOperationUsageException(String errorMessage) { 12 | super(errorMessage); 13 | log.error(errorMessage, this); 14 | } 15 | 16 | public DynamicQueryNoAvailableParenthesesOperationUsageException(String errorMessage, Throwable err) { 17 | super(errorMessage, err); 18 | log.error(errorMessage, err); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryNoAvailableValueException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryNoAvailableValueException extends RuntimeException { 10 | public DynamicQueryNoAvailableValueException(String errorMessage) { 11 | super(errorMessage); 12 | log.error(errorMessage, this); 13 | } 14 | 15 | public DynamicQueryNoAvailableValueException(String errorMessage, Throwable err) { 16 | super(errorMessage, err); 17 | log.error(errorMessage, err); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryNoFirstValueException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryNoFirstValueException extends RuntimeException { 10 | 11 | public DynamicQueryNoFirstValueException(String errorMessage) { 12 | super(errorMessage); 13 | log.error(errorMessage, this); 14 | } 15 | 16 | public DynamicQueryNoFirstValueException(String errorMessage, Throwable err) { 17 | super(errorMessage, err); 18 | log.error(errorMessage, err); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/exception/DynamicQueryValueSerializeException.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.exception; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 24-Aug-19 7 | */ 8 | @Slf4j 9 | public class DynamicQueryValueSerializeException extends RuntimeException { 10 | public DynamicQueryValueSerializeException(String errorMessage) { 11 | super(errorMessage); 12 | log.error(errorMessage, this); 13 | } 14 | 15 | public DynamicQueryValueSerializeException(String errorMessage, Throwable err) { 16 | super(errorMessage, err); 17 | log.error(errorMessage, err); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/provider/IEntityManagerProvider.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.provider; 2 | 3 | import jakarta.persistence.EntityManager; 4 | 5 | public interface IEntityManagerProvider { 6 | EntityManager provide(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/DynamicSpecification.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.enums.CriteriaOperator; 5 | import com.beyt.jdq.dto.enums.JoinType; 6 | import com.beyt.jdq.exception.*; 7 | import com.beyt.jdq.util.ApplicationContextUtil; 8 | import com.beyt.jdq.util.SpecificationUtil; 9 | import org.apache.commons.lang3.tuple.ImmutableTriple; 10 | import org.apache.commons.lang3.tuple.Triple; 11 | import org.springframework.data.jpa.domain.Specification; 12 | import org.springframework.data.util.Pair; 13 | 14 | import jakarta.persistence.criteria.*; 15 | import java.util.*; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | 18 | /** 19 | * Created by tdilber at 24-Aug-19 20 | */ 21 | 22 | public class DynamicSpecification implements Specification { 23 | 24 | protected List criteriaList; 25 | protected Map, String, JoinType>, Join> joinMap = new ConcurrentHashMap<>(); 26 | 27 | public DynamicSpecification(List criteriaList) { 28 | this.criteriaList = criteriaList; 29 | this.joinMap = new ConcurrentHashMap<>(); 30 | } 31 | 32 | public DynamicSpecification(List criteriaList, Map, String, JoinType>, Join> joinMap) { 33 | this.criteriaList = criteriaList; 34 | this.joinMap = joinMap; 35 | } 36 | 37 | @Override 38 | public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder builder) { 39 | List predicateAndList = new ArrayList<>(); 40 | List predicateOrList = new ArrayList<>(); 41 | for (int i = 0; i < criteriaList.size(); i++) { 42 | if (criteriaList.get(i).getOperation() == CriteriaOperator.PARENTHES) { 43 | SpecificationUtil.checkHasFirstValue(criteriaList.get(i)); 44 | try { 45 | predicateAndList.add(new DynamicSpecification(((List) (criteriaList.get(i).getValues().get(0))), joinMap).toPredicate(root, query, builder)); 46 | } catch (Exception e) { 47 | throw new DynamicQueryNoAvailableParenthesesOperationUsageException( 48 | "There is No Available Paranthes Operation Usage in Criteria Key: " + criteriaList.get(i).getKey()); 49 | } 50 | } else if (criteriaList.get(i).getOperation() == CriteriaOperator.OR) { 51 | if (i == 0 || i + 1 == criteriaList.size()) { 52 | throw new DynamicQueryNoAvailableOrOperationUsageException( 53 | "There is No Available OR Operation Usage in Criteria Key: " + criteriaList.get(i).getKey()); 54 | } 55 | 56 | predicateOrList.add(builder.and(predicateAndList.toArray(new Predicate[0]))); 57 | predicateAndList.clear(); 58 | } else { 59 | predicateAndList.add(getPredicate(root, builder, criteriaList.get(i))); 60 | } 61 | } 62 | 63 | predicateOrList.add(builder.and(predicateAndList.toArray(new Predicate[0]))); 64 | 65 | return builder.or(predicateOrList.toArray(new Predicate[0])); 66 | } 67 | 68 | private Predicate getPredicate(Root root, CriteriaBuilder builder, Criteria criteria) { 69 | From localFrom = createLocalFrom(root, criteria.getKey()); 70 | return addPredicate(localFrom, builder, new Criteria(getFieldName(criteria.getKey()), criteria.getOperation(), criteria.getValues().toArray(new Object[0]))); 71 | } 72 | 73 | public From createLocalFrom(Root root, String key) { 74 | From localFrom = root; 75 | List> fieldJoins = getFieldJoins(key); 76 | 77 | for (Pair fieldJoin : fieldJoins) { 78 | localFrom = getJoin(localFrom, fieldJoin.getFirst(), fieldJoin.getSecond()); 79 | } 80 | 81 | return localFrom; 82 | } 83 | 84 | public static List> getFieldJoins(String key) { 85 | List> fieldJoins = new ArrayList<>(); 86 | 87 | String subKey = key; 88 | JoinType joinType = null; 89 | int index = -1; 90 | 91 | 92 | while (subKey.chars().anyMatch(c -> Arrays.stream(JoinType.values()).anyMatch(j -> j.getSeparator().charValue() == c))) { 93 | 94 | for (JoinType value : JoinType.values()) { 95 | int indexOf = subKey.indexOf(value.getSeparator()); 96 | if (indexOf > -1 && (index == -1 || indexOf < index)) { 97 | index = indexOf; 98 | joinType = value; 99 | } 100 | } 101 | 102 | if (Objects.nonNull(joinType)) { 103 | fieldJoins.add(Pair.of(subKey.substring(0, index), joinType)); 104 | subKey = subKey.substring(index + 1); 105 | } 106 | 107 | index = -1; 108 | joinType = null; 109 | } 110 | 111 | return fieldJoins; 112 | } 113 | 114 | public static String getFieldName(String key) { 115 | String[] splitedKey = key.split(">|<|\\."); 116 | return splitedKey[splitedKey.length - 1]; 117 | } 118 | 119 | protected Predicate addPredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 120 | if (!criteria.getOperation().equals(CriteriaOperator.SPECIFIED)) { 121 | try { 122 | criteria.setValues(deserialize(root.get(criteria.getKey()).getJavaType(), criteria.getValues())); 123 | } catch (Exception e) { 124 | throw new DynamicQueryNoAvailableEnumException("There is a " 125 | + root.get(criteria.getKey()).getJavaType().getSimpleName() + " Problem in Criteria Key: " 126 | + criteria.getKey(), e); 127 | } 128 | } 129 | 130 | if (DynamicQueryManager.specificationRuleMap.containsKey(criteria.getOperation())) { 131 | return DynamicQueryManager.specificationRuleMap 132 | .get(criteria.getOperation()).generatePredicate(root, builder, criteria); 133 | } else { 134 | throw new DynamicQueryNoAvailableOperationException("There is No Available Operation in Criteria Key: " 135 | + criteria.getKey()); 136 | } 137 | } 138 | 139 | protected Join getJoin(From from, String key, JoinType joinType) { 140 | Triple, String, JoinType> joinMapKey = new ImmutableTriple<>(from, key, joinType); 141 | if (joinMap.containsKey(joinMapKey)) { 142 | return joinMap.get(joinMapKey); 143 | } 144 | Join join = from.join(key, joinType.getJoinType()); 145 | joinMap.put(joinMapKey, join); 146 | return join; 147 | } 148 | 149 | protected List deserialize(Class clazz, List objects) throws Exception { 150 | List result = new ArrayList<>(); 151 | for (Object object : objects) { 152 | Object deserialized = null; 153 | try { 154 | deserialized = ApplicationContextUtil.getDeserializer().deserialize(object.toString(), clazz); 155 | } catch (Exception e) { 156 | throw new DynamicQueryValueSerializeException("There is a " 157 | + clazz.getSimpleName() + " Deserialization Problem in Criteria Value: " 158 | + object.toString()); 159 | } 160 | result.add(deserialized); 161 | } 162 | return result; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/QueryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.query.DynamicQueryManager; 6 | import com.beyt.jdq.query.builder.interfaces.*; 7 | import com.beyt.jdq.repository.DynamicSpecificationRepository; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.util.Pair; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | public class QueryBuilder implements DistinctWhereOrderByPage, WhereOrderByPage, OrderByPage, PageableResult, Result { 16 | protected final DynamicSpecificationRepository dynamicSpecificationRepository; 17 | protected final DynamicQuery dynamicQuery; 18 | 19 | public QueryBuilder(DynamicSpecificationRepository dynamicSpecificationRepository) { 20 | this.dynamicSpecificationRepository = dynamicSpecificationRepository; 21 | dynamicQuery = new DynamicQuery(); 22 | } 23 | 24 | public DistinctWhereOrderByPage select(QuerySimplifier.SelectRule... selectRules) { 25 | dynamicQuery.getSelect().addAll(Arrays.stream(selectRules).map(o -> Pair.of(o.getFieldName(), o.getAlias())).collect(Collectors.toList())); 26 | return this; 27 | } 28 | 29 | public WhereOrderByPage distinct(boolean distinct) { 30 | dynamicQuery.setDistinct(distinct); 31 | return this; 32 | } 33 | 34 | 35 | public OrderByPage where(Criteria... criteria) { 36 | dynamicQuery.getWhere().addAll(Arrays.asList(criteria)); 37 | return this; 38 | } 39 | 40 | 41 | public PageableResult orderBy(QuerySimplifier.OrderByRule... pairs) { 42 | dynamicQuery.getOrderBy().addAll(Arrays.stream(pairs).map(o -> Pair.of(o.getFieldName(), o.getOrderType())).collect(Collectors.toList())); 43 | return this; 44 | } 45 | 46 | public Result page(int pageNumber, int pageSize) { 47 | dynamicQuery.setPageSize(pageSize); 48 | dynamicQuery.setPageNumber(pageNumber); 49 | return this; 50 | } 51 | 52 | public List getResult() { 53 | return DynamicQueryManager.getEntityListBySelectableFilterAsList(dynamicSpecificationRepository, dynamicQuery); 54 | } 55 | 56 | public List getResult(Class resultValueClass) { 57 | return DynamicQueryManager.getEntityListBySelectableFilterWithReturnTypeAsList(dynamicSpecificationRepository, dynamicQuery, resultValueClass); 58 | } 59 | 60 | public Page getResultAsPage() { 61 | return DynamicQueryManager.getEntityListBySelectableFilterAsPage(dynamicSpecificationRepository, dynamicQuery); 62 | } 63 | 64 | public Page getResultAsPage(Class resultValueClass) { 65 | return DynamicQueryManager.getEntityListBySelectableFilterWithReturnTypeAsPage(dynamicSpecificationRepository, dynamicQuery, resultValueClass); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/QuerySimplifier.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.enums.CriteriaOperator; 5 | import com.beyt.jdq.dto.enums.Order; 6 | import com.beyt.jdq.query.DynamicSpecification; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | import java.util.Arrays; 12 | 13 | public class QuerySimplifier { 14 | public static final Criteria OR = Criteria.OR(); 15 | 16 | public static Field Field(String name) { 17 | return new Field(name); 18 | } 19 | 20 | public static Criteria Parantesis(Criteria... criterias) { 21 | return Criteria.of("", CriteriaOperator.PARENTHES, Arrays.asList(criterias)); 22 | } 23 | 24 | public static OrderByRule OrderBy(String fieldName, Order orderType) { 25 | return new OrderByRule(fieldName, orderType); 26 | } 27 | 28 | public static SelectRule Select(String fieldName, String alias) { 29 | return new SelectRule(fieldName, alias); 30 | } 31 | 32 | public static SelectRule Select(String fieldName) { 33 | return new SelectRule(fieldName, DynamicSpecification.getFieldName(fieldName)); 34 | } 35 | 36 | @Data 37 | @NoArgsConstructor 38 | @AllArgsConstructor 39 | public static class OrderByRule { 40 | private String fieldName; 41 | private Order orderType; 42 | } 43 | 44 | @Data 45 | @NoArgsConstructor 46 | @AllArgsConstructor 47 | public static class SelectRule { 48 | private String fieldName; 49 | private String alias; 50 | } 51 | 52 | public static class Field { 53 | private String name; 54 | 55 | public Field(String name) { 56 | this.name = name; 57 | } 58 | 59 | public Criteria eq(Object... values) { 60 | return Criteria.of(name, CriteriaOperator.EQUAL, values); 61 | } 62 | 63 | public Criteria notEq(Object... values) { 64 | return Criteria.of(name, CriteriaOperator.NOT_EQUAL, values); 65 | } 66 | 67 | public Criteria contain(Object... values) { 68 | return Criteria.of(name, CriteriaOperator.CONTAIN, values); 69 | } 70 | 71 | public Criteria doesNotContain(Object... values) { 72 | return Criteria.of(name, CriteriaOperator.DOES_NOT_CONTAIN, values); 73 | } 74 | 75 | public Criteria endWith(Object... values) { 76 | return Criteria.of(name, CriteriaOperator.END_WITH, values); 77 | } 78 | 79 | public Criteria startWith(Object... values) { 80 | return Criteria.of(name, CriteriaOperator.START_WITH, values); 81 | } 82 | 83 | public Criteria specified(boolean value) { 84 | return Criteria.of(name, CriteriaOperator.SPECIFIED, value); 85 | } 86 | 87 | public Criteria isNull() { 88 | return Criteria.of(name, CriteriaOperator.SPECIFIED, false); 89 | } 90 | 91 | public Criteria nonNull() { 92 | return Criteria.of(name, CriteriaOperator.SPECIFIED, true); 93 | } 94 | 95 | public Criteria greaterThan(Object value) { 96 | return Criteria.of(name, CriteriaOperator.GREATER_THAN, value); 97 | } 98 | 99 | public Criteria greaterThanOrEqual(Object value) { 100 | return Criteria.of(name, CriteriaOperator.GREATER_THAN_OR_EQUAL, value); 101 | } 102 | 103 | public Criteria lessThan(Object value) { 104 | return Criteria.of(name, CriteriaOperator.LESS_THAN, value); 105 | } 106 | 107 | public Criteria lessThanOrEqual(Object value) { 108 | return Criteria.of(name, CriteriaOperator.LESS_THAN_OR_EQUAL, value); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/interfaces/DistinctWhereOrderByPage.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder.interfaces; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.query.builder.QuerySimplifier; 5 | import org.springframework.data.domain.Page; 6 | 7 | import java.util.List; 8 | 9 | public interface DistinctWhereOrderByPage { 10 | WhereOrderByPage distinct(boolean distinct); 11 | 12 | OrderByPage where(Criteria... criteria); 13 | 14 | PageableResult orderBy(QuerySimplifier.OrderByRule... pairs); 15 | 16 | Result page(int pageNumber, int pageSize); 17 | 18 | List getResult(); 19 | 20 | Page getResultAsPage(); 21 | 22 | List getResult(Class resultValueClass); 23 | 24 | Page getResultAsPage(Class resultValueClass); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/interfaces/OrderByPage.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder.interfaces; 2 | 3 | import com.beyt.jdq.query.builder.QuerySimplifier; 4 | import org.springframework.data.domain.Page; 5 | 6 | import java.util.List; 7 | 8 | public interface OrderByPage { 9 | PageableResult orderBy(QuerySimplifier.OrderByRule... pairs); 10 | 11 | Result page(int pageNumber, int pageSize); 12 | 13 | List getResult(); 14 | 15 | Page getResultAsPage(); 16 | 17 | List getResult(Class resultValueClass); 18 | 19 | Page getResultAsPage(Class resultValueClass); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/interfaces/PageableResult.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder.interfaces; 2 | 3 | import org.springframework.data.domain.Page; 4 | 5 | import java.util.List; 6 | 7 | public interface PageableResult { 8 | Result page(int pageNumber, int pageSize); 9 | 10 | List getResult(); 11 | 12 | Page getResultAsPage(); 13 | 14 | List getResult(Class resultValueClass); 15 | 16 | Page getResultAsPage(Class resultValueClass); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/interfaces/Result.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder.interfaces; 2 | 3 | import org.springframework.data.domain.Page; 4 | 5 | import java.util.List; 6 | 7 | public interface Result { 8 | List getResult(); 9 | 10 | Page getResultAsPage(); 11 | 12 | List getResult(Class resultValueClass); 13 | 14 | Page getResultAsPage(Class resultValueClass); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/builder/interfaces/WhereOrderByPage.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.builder.interfaces; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.query.builder.QuerySimplifier; 5 | import org.springframework.data.domain.Page; 6 | 7 | import java.util.List; 8 | 9 | public interface WhereOrderByPage { 10 | OrderByPage where(Criteria... criteria); 11 | 12 | PageableResult orderBy(QuerySimplifier.OrderByRule... pairs); 13 | 14 | Result page(int pageNumber, int pageSize); 15 | 16 | List getResult(); 17 | 18 | Page getResultAsPage(); 19 | 20 | List getResult(Class resultValueClass); 21 | 22 | Page getResultAsPage(Class resultValueClass); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/sort/ISortFilterRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.sort; 2 | 3 | import org.springframework.data.domain.Sort; 4 | 5 | /** 6 | * Created by tdilber at 28-Aug-19 7 | */ 8 | public interface ISortFilterRule { 9 | Sort getSortFilterRule(String field); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/sort/SortFilterAscRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.sort; 2 | 3 | import org.springframework.data.domain.Sort; 4 | 5 | /** 6 | * Created by tdilber at 28-Aug-19 7 | */ 8 | public class SortFilterAscRule implements ISortFilterRule { 9 | 10 | @Override 11 | public Sort getSortFilterRule(String field) { 12 | return Sort.by(Sort.Direction.ASC, field); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/sort/SortFilterDescRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.sort; 2 | 3 | import org.springframework.data.domain.Sort; 4 | 5 | /** 6 | * Created by tdilber at 28-Aug-19 7 | */ 8 | public class SortFilterDescRule implements ISortFilterRule { 9 | 10 | @Override 11 | public Sort getSortFilterRule(String field) { 12 | return Sort.by(Sort.Direction.DESC, field); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/ISpecificationFilterRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | 4 | import com.beyt.jdq.dto.Criteria; 5 | 6 | import jakarta.persistence.criteria.CriteriaBuilder; 7 | import jakarta.persistence.criteria.Path; 8 | import jakarta.persistence.criteria.Predicate; 9 | 10 | /** 11 | * Created by tdilber at 25-Aug-19 12 | */ 13 | public interface ISpecificationFilterRule { 14 | Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterDoesNotContainRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.exception.DynamicQueryNoAvailableValueException; 5 | import com.beyt.jdq.util.SpecificationUtil; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import jakarta.persistence.criteria.CriteriaBuilder; 9 | import jakarta.persistence.criteria.Path; 10 | import jakarta.persistence.criteria.Predicate; 11 | 12 | /** 13 | * Created by tdilber at 25-Aug-19 14 | */ 15 | @Slf4j 16 | public class SpecificationFilterDoesNotContainRule implements ISpecificationFilterRule { 17 | 18 | @Override 19 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | Predicate[] predicates = new Predicate[criteria.getValues().size()]; 22 | for (int i = 0; i < criteria.getValues().size(); i++) { 23 | if (root.get(criteria.getKey()).getJavaType() == String.class) { 24 | predicates[i] = builder.notLike(root.get(criteria.getKey()), "%" + criteria.getValues().get(i) + "%"); 25 | } else { 26 | throw new DynamicQueryNoAvailableValueException("Need String Type: " + criteria.getKey()); 27 | } 28 | } 29 | 30 | return builder.and(predicates); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterDoubleLikeRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.exception.DynamicQueryNoAvailableValueException; 5 | import com.beyt.jdq.util.SpecificationUtil; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import jakarta.persistence.criteria.CriteriaBuilder; 9 | import jakarta.persistence.criteria.Path; 10 | import jakarta.persistence.criteria.Predicate; 11 | 12 | /** 13 | * Created by tdilber at 25-Aug-19 14 | */ 15 | @Slf4j 16 | public class SpecificationFilterDoubleLikeRule implements ISpecificationFilterRule { 17 | 18 | @Override 19 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | Predicate[] predicates = new Predicate[criteria.getValues().size()]; 22 | for (int i = 0; i < criteria.getValues().size(); i++) { 23 | if (root.get(criteria.getKey()).getJavaType() == String.class) { 24 | predicates[i] = builder.like(root.get(criteria.getKey()), "%" + criteria.getValues().get(i) + "%"); 25 | } else { 26 | throw new DynamicQueryNoAvailableValueException("Need String Type: " + criteria.getKey()); 27 | } 28 | } 29 | 30 | return builder.or(predicates); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterEqualRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.util.SpecificationUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import jakarta.persistence.criteria.CriteriaBuilder; 8 | import jakarta.persistence.criteria.Path; 9 | import jakarta.persistence.criteria.Predicate; 10 | 11 | /** 12 | * Created by tdilber at 25-Aug-19 13 | */ 14 | @Slf4j 15 | public class SpecificationFilterEqualRule implements ISpecificationFilterRule { 16 | 17 | @Override 18 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 19 | SpecificationUtil.checkHasFirstValue(criteria); 20 | Predicate[] predicates = new Predicate[criteria.getValues().size()]; 21 | for (int i = 0; i < criteria.getValues().size(); i++) { 22 | predicates[i] = builder.equal(root.get(criteria.getKey()), criteria.getValues().get(i)); 23 | } 24 | 25 | return builder.or(predicates); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterGreaterThanOrEqualToRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.util.SpecificationUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import jakarta.persistence.criteria.CriteriaBuilder; 8 | import jakarta.persistence.criteria.Path; 9 | import jakarta.persistence.criteria.Predicate; 10 | 11 | /** 12 | * Created by tdilber at 25-Aug-19 13 | */ 14 | @Slf4j 15 | public class SpecificationFilterGreaterThanOrEqualToRule implements ISpecificationFilterRule { 16 | @Override 17 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 18 | Predicate predicate; 19 | SpecificationUtil.checkHasFirstValue(criteria); 20 | predicate = builder.greaterThanOrEqualTo(root.get(criteria.getKey()), (Comparable) criteria.getValues().get(0)); 21 | 22 | return predicate; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterGreaterThanRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.util.SpecificationUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import jakarta.persistence.criteria.CriteriaBuilder; 8 | import jakarta.persistence.criteria.Path; 9 | import jakarta.persistence.criteria.Predicate; 10 | 11 | /** 12 | * Created by tdilber at 25-Aug-19 13 | */ 14 | @Slf4j 15 | public class SpecificationFilterGreaterThanRule implements ISpecificationFilterRule { 16 | @Override 17 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 18 | Predicate predicate; 19 | SpecificationUtil.checkHasFirstValue(criteria); 20 | predicate = builder.greaterThan(root.get(criteria.getKey()), (Comparable) criteria.getValues().get(0)); 21 | 22 | return predicate; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterLeftLikeRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.exception.DynamicQueryNoAvailableValueException; 5 | import com.beyt.jdq.util.SpecificationUtil; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import jakarta.persistence.criteria.CriteriaBuilder; 9 | import jakarta.persistence.criteria.Path; 10 | import jakarta.persistence.criteria.Predicate; 11 | 12 | /** 13 | * Created by tdilber at 25-Aug-19 14 | */ 15 | @Slf4j 16 | public class SpecificationFilterLeftLikeRule implements ISpecificationFilterRule { 17 | 18 | @Override 19 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | Predicate[] predicates = new Predicate[criteria.getValues().size()]; 22 | for (int i = 0; i < criteria.getValues().size(); i++) { 23 | if (root.get(criteria.getKey()).getJavaType() == String.class) { 24 | predicates[i] = builder.like(root.get(criteria.getKey()), "%" + criteria.getValues().get(i)); 25 | } else { 26 | throw new DynamicQueryNoAvailableValueException("Need String Type: " + criteria.getKey()); 27 | } 28 | } 29 | 30 | return builder.or(predicates); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterLessThanOrEqualToRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.util.SpecificationUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import jakarta.persistence.criteria.CriteriaBuilder; 8 | import jakarta.persistence.criteria.Path; 9 | import jakarta.persistence.criteria.Predicate; 10 | 11 | /** 12 | * Created by tdilber at 25-Aug-19 13 | */ 14 | @Slf4j 15 | public class SpecificationFilterLessThanOrEqualToRule implements ISpecificationFilterRule { 16 | 17 | @Override 18 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 19 | Predicate predicate; 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | predicate = builder.lessThanOrEqualTo(root.get(criteria.getKey()), (Comparable) criteria.getValues().get(0)); 22 | 23 | return predicate; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterLessThanRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.util.SpecificationUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import jakarta.persistence.criteria.CriteriaBuilder; 8 | import jakarta.persistence.criteria.Path; 9 | import jakarta.persistence.criteria.Predicate; 10 | 11 | /** 12 | * Created by tdilber at 25-Aug-19 13 | */ 14 | @Slf4j 15 | public class SpecificationFilterLessThanRule implements ISpecificationFilterRule { 16 | 17 | @Override 18 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 19 | Predicate predicate; 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | predicate = builder.lessThan(root.get(criteria.getKey()), (Comparable) criteria.getValues().get(0)); 22 | 23 | return predicate; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterNotEqualRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.util.SpecificationUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import jakarta.persistence.criteria.CriteriaBuilder; 8 | import jakarta.persistence.criteria.Path; 9 | import jakarta.persistence.criteria.Predicate; 10 | 11 | /** 12 | * Created by tdilber at 25-Aug-19 13 | */ 14 | @Slf4j 15 | public class SpecificationFilterNotEqualRule implements ISpecificationFilterRule { 16 | 17 | @Override 18 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 19 | SpecificationUtil.checkHasFirstValue(criteria); 20 | Predicate[] predicates = new Predicate[criteria.getValues().size()]; 21 | for (int i = 0; i < criteria.getValues().size(); i++) { 22 | predicates[i] = builder.notEqual(root.get(criteria.getKey()), criteria.getValues().get(i)); 23 | } 24 | 25 | return builder.and(predicates); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterRightLikeRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.exception.DynamicQueryNoAvailableValueException; 5 | import com.beyt.jdq.util.SpecificationUtil; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import jakarta.persistence.criteria.CriteriaBuilder; 9 | import jakarta.persistence.criteria.Path; 10 | import jakarta.persistence.criteria.Predicate; 11 | 12 | /** 13 | * Created by tdilber at 25-Aug-19 14 | */ 15 | @Slf4j 16 | public class SpecificationFilterRightLikeRule implements ISpecificationFilterRule { 17 | 18 | @Override 19 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | Predicate[] predicates = new Predicate[criteria.getValues().size()]; 22 | for (int i = 0; i < criteria.getValues().size(); i++) { 23 | if (root.get(criteria.getKey()).getJavaType() == String.class) { 24 | predicates[i] = builder.like(root.get(criteria.getKey()), criteria.getValues().get(i) + "%"); 25 | } else { 26 | throw new DynamicQueryNoAvailableValueException("Need String Type: " + criteria.getKey()); 27 | } 28 | } 29 | 30 | return builder.or(predicates); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/specification/SpecificationFilterSpecifiedRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.specification; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.exception.DynamicQueryNoAvailableValueException; 5 | import com.beyt.jdq.util.SpecificationUtil; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import jakarta.persistence.criteria.CriteriaBuilder; 9 | import jakarta.persistence.criteria.Path; 10 | import jakarta.persistence.criteria.Predicate; 11 | 12 | /** 13 | * Created by tdilber at 25-Aug-19 14 | */ 15 | @Slf4j 16 | public class SpecificationFilterSpecifiedRule implements ISpecificationFilterRule { 17 | 18 | @Override 19 | public Predicate generatePredicate(Path root, CriteriaBuilder builder, Criteria criteria) { 20 | SpecificationUtil.checkHasFirstValue(criteria); 21 | if (!criteria.getValues().get(0).toString().equalsIgnoreCase("true") && !criteria.getValues().get(0).toString().equalsIgnoreCase("false")) { 22 | throw new DynamicQueryNoAvailableValueException("Specified rule first value must be true or false. But you send " + criteria.getValues().get(0).toString()); 23 | } 24 | 25 | return criteria.getValues().get(0).toString().equalsIgnoreCase("true") ? builder.isNotNull(root.get(criteria.getKey())) : builder.isNull(root.get(criteria.getKey())); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/top/IPageFilterRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.top; 2 | 3 | import org.springframework.data.domain.Pageable; 4 | 5 | /** 6 | * Created by tdilber at 28-Aug-19 7 | */ 8 | public interface IPageFilterRule { 9 | Pageable generatePageRequest(int page, int size, String field); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/top/PageFilterAscRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.top; 2 | 3 | import org.springframework.data.domain.PageRequest; 4 | import org.springframework.data.domain.Pageable; 5 | import org.springframework.data.domain.Sort; 6 | 7 | /** 8 | * Created by tdilber at 28-Aug-19 9 | */ 10 | public class PageFilterAscRule implements IPageFilterRule { 11 | 12 | @Override 13 | public Pageable generatePageRequest(int page, int size, String field) { 14 | return PageRequest.of(page, size, Sort.Direction.ASC, field); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/top/PageFilterDescRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.top; 2 | 3 | import org.springframework.data.domain.PageRequest; 4 | import org.springframework.data.domain.Pageable; 5 | import org.springframework.data.domain.Sort; 6 | 7 | /** 8 | * Created by tdilber at 28-Aug-19 9 | */ 10 | public class PageFilterDescRule implements IPageFilterRule { 11 | 12 | @Override 13 | public Pageable generatePageRequest(int page, int size, String field) { 14 | return PageRequest.of(page, size, Sort.Direction.DESC, field); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/top/TopFilterAscRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.top; 2 | 3 | import org.springframework.data.domain.PageRequest; 4 | import org.springframework.data.domain.Pageable; 5 | import org.springframework.data.domain.Sort; 6 | 7 | /** 8 | * Created by tdilber at 28-Aug-19 9 | */ 10 | public class TopFilterAscRule implements IPageFilterRule { 11 | 12 | @Override 13 | public Pageable generatePageRequest(int page, int size, String field) { 14 | return PageRequest.of(0, size, Sort.Direction.ASC, field); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/query/rule/top/TopFilterDescRule.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query.rule.top; 2 | 3 | import org.springframework.data.domain.PageRequest; 4 | import org.springframework.data.domain.Pageable; 5 | import org.springframework.data.domain.Sort; 6 | 7 | /** 8 | * Created by tdilber at 28-Aug-19 9 | */ 10 | public class TopFilterDescRule implements IPageFilterRule { 11 | 12 | @Override 13 | public Pageable generatePageRequest(int page, int size, String field) { 14 | return PageRequest.of(0, size, Sort.Direction.DESC, field); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/repository/DynamicSpecificationRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.repository; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.query.builder.QueryBuilder; 6 | import com.beyt.jdq.util.ListConsumer; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | import org.springframework.data.jpa.domain.Specification; 10 | import org.springframework.data.jpa.repository.JpaRepository; 11 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 12 | import org.springframework.data.repository.NoRepositoryBean; 13 | 14 | import jakarta.persistence.Tuple; 15 | import java.util.List; 16 | 17 | @NoRepositoryBean 18 | public interface DynamicSpecificationRepository extends JpaRepository, JpaSpecificationExecutor { 19 | 20 | List findAll(List criteriaList); 21 | 22 | List findAll(DynamicQuery dynamicQuery); 23 | 24 | Page findAllAsPage(DynamicQuery dynamicQuery); 25 | 26 | List findAllAsTuple(DynamicQuery dynamicQuery); 27 | 28 | Page findAllAsTuplePage(DynamicQuery dynamicQuery); 29 | 30 | List findAll(DynamicQuery dynamicQuery, Class resultTypeClass); 31 | 32 | Page findAllAsPage(DynamicQuery dynamicQuery, Class resultTypeClass); 33 | 34 | QueryBuilder queryBuilder(); 35 | 36 | Page findAll(List criteriaList, Pageable pageable); 37 | 38 | long count(List criteriaList); 39 | 40 | void consumePartially(ListConsumer processor, int pageSize); 41 | 42 | void consumePartially(Specification specification, ListConsumer processor, int pageSize); 43 | 44 | void consumePartially(List criteriaList, ListConsumer processor, int pageSize); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/repository/DynamicSpecificationRepositoryFactoryBean.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.jpa.repository.support.JpaRepositoryFactory; 5 | import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; 6 | import org.springframework.data.repository.core.RepositoryMetadata; 7 | import org.springframework.data.repository.core.support.RepositoryFactorySupport; 8 | 9 | import jakarta.persistence.EntityManager; 10 | import java.io.Serializable; 11 | 12 | 13 | public class DynamicSpecificationRepositoryFactoryBean, T, ID extends Serializable> 14 | extends JpaRepositoryFactoryBean { 15 | 16 | public DynamicSpecificationRepositoryFactoryBean(Class repositoryInterface) { 17 | super(repositoryInterface); 18 | } 19 | 20 | protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 21 | return new GenericSpecificationRepositoryFactory(entityManager); 22 | } 23 | 24 | private static class GenericSpecificationRepositoryFactory 25 | extends JpaRepositoryFactory { 26 | 27 | public GenericSpecificationRepositoryFactory(EntityManager entityManager) { 28 | super(entityManager); 29 | } 30 | 31 | @Override 32 | protected Class getRepositoryBaseClass(RepositoryMetadata metadata) { 33 | Class repositoryInterface = metadata.getRepositoryInterface(); 34 | if (DynamicSpecificationRepository.class.isAssignableFrom(repositoryInterface)) { 35 | return DynamicSpecificationRepositoryImpl.class; 36 | } else { 37 | return super.getRepositoryBaseClass(metadata); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/repository/DynamicSpecificationRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.repository; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.query.DynamicQueryManager; 6 | import com.beyt.jdq.query.builder.QueryBuilder; 7 | import com.beyt.jdq.util.ListConsumer; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.PageRequest; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.data.jpa.domain.Specification; 12 | import org.springframework.data.jpa.repository.JpaRepository; 13 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 14 | import org.springframework.data.jpa.repository.support.JpaEntityInformation; 15 | import org.springframework.data.jpa.repository.support.SimpleJpaRepository; 16 | import org.springframework.data.repository.NoRepositoryBean; 17 | 18 | import jakarta.persistence.EntityManager; 19 | import jakarta.persistence.Tuple; 20 | import java.io.Serializable; 21 | import java.util.List; 22 | 23 | @NoRepositoryBean 24 | public class DynamicSpecificationRepositoryImpl extends SimpleJpaRepository implements DynamicSpecificationRepository, JpaRepository, JpaSpecificationExecutor { 25 | 26 | private final EntityManager entityManager; 27 | 28 | public DynamicSpecificationRepositoryImpl(JpaEntityInformation entityInformation, 29 | EntityManager entityManager) { 30 | 31 | super(entityInformation, entityManager); 32 | this.entityManager = entityManager; 33 | } 34 | 35 | @Override 36 | public List findAll(List criteriaList) { 37 | return DynamicQueryManager.findAll(this, criteriaList); 38 | } 39 | 40 | @Override 41 | public List findAll(DynamicQuery dynamicQuery) { 42 | return DynamicQueryManager.getEntityListBySelectableFilterAsList(this, dynamicQuery); 43 | } 44 | 45 | @Override 46 | public Page findAllAsPage(DynamicQuery dynamicQuery) { 47 | return DynamicQueryManager.getEntityListBySelectableFilterAsPage(this, dynamicQuery); 48 | } 49 | 50 | @Override 51 | public List findAllAsTuple(DynamicQuery dynamicQuery) { 52 | return DynamicQueryManager.getEntityListBySelectableFilterWithTupleAsList(this, dynamicQuery); 53 | } 54 | 55 | @Override 56 | public Page findAllAsTuplePage(DynamicQuery dynamicQuery) { 57 | return DynamicQueryManager.getEntityListBySelectableFilterWithTupleAsPage(this, dynamicQuery); 58 | } 59 | 60 | @Override 61 | public List findAll(DynamicQuery dynamicQuery, Class resultTypeClass) { 62 | return DynamicQueryManager.getEntityListBySelectableFilterWithReturnTypeAsList(this, dynamicQuery, resultTypeClass); 63 | } 64 | 65 | @Override 66 | public Page findAllAsPage(DynamicQuery dynamicQuery, Class resultTypeClass) { 67 | return DynamicQueryManager.getEntityListBySelectableFilterWithReturnTypeAsPage(this, dynamicQuery, resultTypeClass); 68 | } 69 | 70 | @Override 71 | public QueryBuilder queryBuilder() { 72 | return new QueryBuilder<>(this); 73 | } 74 | 75 | @Override 76 | public Page findAll(List criteriaList, Pageable pageable) { 77 | return DynamicQueryManager.findAll(this, criteriaList, pageable); 78 | } 79 | 80 | static Specification getSpecificationWithCriteria(List criteriaList) { 81 | return DynamicQueryManager.getSpecification(criteriaList); 82 | } 83 | 84 | public Class getDomainClass() { 85 | return super.getDomainClass(); 86 | } 87 | 88 | @Override 89 | public long count(List criteriaList) { 90 | return DynamicQueryManager.count(this, criteriaList); 91 | } 92 | 93 | @Override 94 | public void consumePartially(ListConsumer processor, int pageSize) { 95 | consumePartially((Specification) null, processor, pageSize); 96 | } 97 | 98 | @Override 99 | public void consumePartially(Specification specification, ListConsumer processor, int pageSize) { 100 | Page page = this.findAll((Specification) null, PageRequest.of(0, pageSize)); 101 | processor.accept(page.getContent()); 102 | long totalElements = page.getTotalElements(); 103 | for (int i = 1; (long) i * pageSize < totalElements; i++) { 104 | page = this.findAll(specification, PageRequest.of(i, pageSize)); 105 | processor.accept(page.getContent()); 106 | } 107 | } 108 | 109 | @Override 110 | public void consumePartially(List criteriaList, ListConsumer processor, int pageSize) { 111 | long totalElements = DynamicQueryManager.count(this, criteriaList); 112 | 113 | for (int i = 0; (long) i * pageSize < totalElements; i++) { 114 | processor.accept(DynamicQueryManager.findAll(this, criteriaList, PageRequest.of(i, pageSize)).getContent()); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/repository/JpaDynamicQueryRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.repository; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.query.DynamicQueryManager; 6 | import com.beyt.jdq.query.builder.QueryBuilder; 7 | import com.beyt.jdq.util.ListConsumer; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.PageRequest; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.data.jpa.domain.Specification; 12 | import org.springframework.data.repository.NoRepositoryBean; 13 | 14 | import jakarta.persistence.Tuple; 15 | import java.util.List; 16 | 17 | @NoRepositoryBean 18 | public interface JpaDynamicQueryRepository extends DynamicSpecificationRepository { 19 | 20 | default List findAll(List criteriaList) { 21 | return DynamicQueryManager.findAll(this, criteriaList); 22 | } 23 | 24 | default List findAll(DynamicQuery dynamicQuery) { 25 | return DynamicQueryManager.getEntityListBySelectableFilterAsList(this, dynamicQuery); 26 | } 27 | 28 | default Page findAllAsPage(DynamicQuery dynamicQuery) { 29 | return DynamicQueryManager.getEntityListBySelectableFilterAsPage(this, dynamicQuery); 30 | } 31 | 32 | default List findAllAsTuple(DynamicQuery dynamicQuery) { 33 | return DynamicQueryManager.getEntityListBySelectableFilterWithTupleAsList(this, dynamicQuery); 34 | } 35 | 36 | default Page findAllAsTuplePage(DynamicQuery dynamicQuery) { 37 | return DynamicQueryManager.getEntityListBySelectableFilterWithTupleAsPage(this, dynamicQuery); 38 | } 39 | 40 | default List findAll(DynamicQuery dynamicQuery, Class resultTypeClass) { 41 | return DynamicQueryManager.getEntityListBySelectableFilterWithReturnTypeAsList(this, dynamicQuery, resultTypeClass); 42 | } 43 | 44 | default Page findAllAsPage(DynamicQuery dynamicQuery, Class resultTypeClass) { 45 | return DynamicQueryManager.getEntityListBySelectableFilterWithReturnTypeAsPage(this, dynamicQuery, resultTypeClass); 46 | } 47 | 48 | default QueryBuilder queryBuilder() { 49 | return new QueryBuilder(this); 50 | } 51 | 52 | default Page findAll(List criteriaList, Pageable pageable) { 53 | return DynamicQueryManager.findAll(this, criteriaList, pageable); 54 | } 55 | 56 | static Specification createSpecification(List criteriaList) { 57 | return DynamicQueryManager.getSpecification(criteriaList); 58 | } 59 | 60 | default long count(List criteriaList) { 61 | return DynamicQueryManager.count(this, criteriaList); 62 | } 63 | 64 | default void consumePartially(ListConsumer processor, int pageSize) { 65 | consumePartially((Specification) null, processor, pageSize); 66 | } 67 | 68 | default void consumePartially(Specification specification, ListConsumer processor, int pageSize) { 69 | Page page = this.findAll((Specification) null, PageRequest.of(0, pageSize)); 70 | processor.accept(page.getContent()); 71 | long totalElements = page.getTotalElements(); 72 | for (int i = 1; (long) i * pageSize < totalElements; i++) { 73 | page = this.findAll(specification, PageRequest.of(i, pageSize)); 74 | processor.accept(page.getContent()); 75 | } 76 | } 77 | 78 | default void consumePartially(List criteriaList, ListConsumer processor, int pageSize) { 79 | long totalElements = DynamicQueryManager.count(this, criteriaList); 80 | 81 | for (int i = 0; (long) i * pageSize < totalElements; i++) { 82 | processor.accept(DynamicQueryManager.findAll(this, criteriaList, PageRequest.of(i, pageSize)).getContent()); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/resolver/CriteriaListArgumentResolver.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.resolver; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.dto.CriteriaList; 5 | import com.beyt.jdq.dto.enums.CriteriaOperator; 6 | import org.springframework.beans.factory.config.BeanDefinition; 7 | import org.springframework.context.annotation.Role; 8 | import org.springframework.core.MethodParameter; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.bind.support.WebDataBinderFactory; 11 | import org.springframework.web.context.request.NativeWebRequest; 12 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 13 | import org.springframework.web.method.support.ModelAndViewContainer; 14 | 15 | import java.util.Arrays; 16 | 17 | @Component 18 | @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 19 | public class CriteriaListArgumentResolver implements HandlerMethodArgumentResolver { 20 | private static final String KEY_FIELD_START = "key"; 21 | private static final String OPERATION_FIELD_START = "operation"; 22 | private static final String VALUES_FIELD_START = "values"; 23 | 24 | @Override 25 | public boolean supportsParameter(MethodParameter parameter) { 26 | return CriteriaList.class.equals(parameter.getParameterType()); 27 | } 28 | 29 | @Override 30 | public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 31 | CriteriaList filter = new CriteriaList(); 32 | for (int i = 0; ; i++) { 33 | String keyField = KEY_FIELD_START + i; 34 | String operationField = OPERATION_FIELD_START + i; 35 | String valuesField = VALUES_FIELD_START + i; 36 | String key = webRequest.getParameter(keyField); 37 | String operation = webRequest.getParameter(operationField); 38 | String values = webRequest.getParameter(valuesField); 39 | if (key != null && operation != null && values != null) { 40 | Criteria criteria = new Criteria(key, CriteriaOperator.valueOf(operation), null); 41 | criteria.setValues(Arrays.asList(values.split(","))); 42 | filter.add(criteria); 43 | } else { 44 | break; 45 | } 46 | } 47 | return filter; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/resolver/DynamicQueryArgumentResolver.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.resolver; 2 | 3 | import com.beyt.jdq.dto.CriteriaList; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.dto.enums.Order; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.config.BeanDefinition; 8 | import org.springframework.context.annotation.Role; 9 | import org.springframework.core.MethodParameter; 10 | import org.springframework.data.util.Pair; 11 | import org.springframework.stereotype.Component; 12 | import org.springframework.web.bind.support.WebDataBinderFactory; 13 | import org.springframework.web.context.request.NativeWebRequest; 14 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 15 | import org.springframework.web.method.support.ModelAndViewContainer; 16 | 17 | import java.util.Objects; 18 | 19 | @Component 20 | @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 21 | public class DynamicQueryArgumentResolver implements HandlerMethodArgumentResolver { 22 | private static final String SELECT_FIELD_START = "select"; 23 | private static final String SELECT_AS_FIELD_START = "selectAs"; 24 | private static final String ORDER_BY_FIELD_START = "orderBy"; 25 | private static final String ORDER_BY_DIRECTION_FIELD_START = "orderByDirection"; 26 | private static final String PAGE_FIELD_START = "page"; 27 | private static final String PAGE_SIZE_FIELD_START = "pageSize"; 28 | private static final String DISTINCT_FIELD_START = "distinct"; 29 | private final CriteriaListArgumentResolver criteriaListArgumentResolver; 30 | 31 | public DynamicQueryArgumentResolver(CriteriaListArgumentResolver criteriaListArgumentResolver) { 32 | this.criteriaListArgumentResolver = criteriaListArgumentResolver; 33 | } 34 | 35 | @Override 36 | public boolean supportsParameter(MethodParameter parameter) { 37 | return DynamicQuery.class.equals(parameter.getParameterType()); 38 | } 39 | 40 | @Override 41 | public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 42 | DynamicQuery filter = new DynamicQuery(); 43 | 44 | String pageSizeText = webRequest.getParameter(PAGE_SIZE_FIELD_START); 45 | String pageText = webRequest.getParameter(PAGE_FIELD_START); 46 | String distinctText = webRequest.getParameter(DISTINCT_FIELD_START); 47 | 48 | if (StringUtils.isBlank(pageText)) { 49 | pageText = "0"; 50 | } 51 | 52 | if (Objects.nonNull(pageSizeText)) { 53 | filter.setPageNumber(Integer.parseInt(pageText)); 54 | filter.setPageSize(Integer.parseInt(pageSizeText)); 55 | } 56 | 57 | if (Objects.nonNull(distinctText)) { 58 | filter.setDistinct(true); 59 | } 60 | 61 | CriteriaList criteriaList = (CriteriaList) criteriaListArgumentResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); 62 | filter.setWhere(criteriaList); 63 | 64 | for (int i = 0; ; i++) { 65 | String selectParam = SELECT_FIELD_START + i; 66 | String selectAsParam = SELECT_AS_FIELD_START + i; 67 | String select = webRequest.getParameter(selectParam); 68 | String selectAs = webRequest.getParameter(selectAsParam); 69 | if (select != null) { 70 | filter.getSelect().add(Pair.of(select, Objects.nonNull(selectAs) ? selectAs : select)); 71 | } else { 72 | break; 73 | } 74 | } 75 | 76 | for (int i = 0; ; i++) { 77 | String orderByParam = ORDER_BY_FIELD_START + i; 78 | String orderByDirectionParam = ORDER_BY_DIRECTION_FIELD_START + i; 79 | String orderBy = webRequest.getParameter(orderByParam); 80 | String orderByDirection = webRequest.getParameter(orderByDirectionParam); 81 | if (orderBy != null && orderByDirection != null) { 82 | filter.getOrderBy().add(Pair.of(orderBy, Order.of(orderByDirection))); 83 | } else { 84 | break; 85 | } 86 | } 87 | return filter; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/ApplicationContextUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util; 2 | 3 | import com.beyt.jdq.deserializer.IDeserializer; 4 | import com.beyt.jdq.provider.IEntityManagerProvider; 5 | import org.springframework.beans.BeansException; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.context.ApplicationContextAware; 8 | 9 | import jakarta.persistence.EntityManager; 10 | 11 | public class ApplicationContextUtil implements ApplicationContextAware { 12 | private static ApplicationContext applicationContext; 13 | @Override 14 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 15 | ApplicationContextUtil.applicationContext = applicationContext; 16 | } 17 | 18 | public static ApplicationContext getApplicationContext() { 19 | return applicationContext; 20 | } 21 | 22 | public static EntityManager getEntityManager(){ 23 | return applicationContext.getBean(IEntityManagerProvider.class).provide(); 24 | } 25 | 26 | public static IDeserializer getDeserializer() { 27 | return applicationContext.getBean(IDeserializer.class); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/ListConsumer.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util; 2 | 3 | import java.util.List; 4 | import java.util.function.Consumer; 5 | 6 | /** 7 | * Created by tdilber at 7/17/2020 8 | */ 9 | public interface ListConsumer extends Consumer> { 10 | void accept(List entityList); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util; 2 | 3 | import com.beyt.jdq.util.field.FieldUtil; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.apache.commons.lang3.SerializationException; 6 | 7 | import java.lang.reflect.Method; 8 | import java.util.ArrayList; 9 | import java.util.Date; 10 | import java.util.List; 11 | 12 | /** 13 | * Created by tdilber at 7/10/2020 14 | */ 15 | @Slf4j 16 | public class ReflectionUtil { 17 | 18 | public static void convertObjectArrayToIfNotAvailable(Class clazz, Object[] objects) throws Exception { 19 | convertObjectArrayToIfEnum(clazz, objects); 20 | convertObjectArrayToIfDate(clazz, objects); 21 | } 22 | 23 | public static void convertObjectArrayToIfEnum(Class clazz, Object[] objects) throws Exception { 24 | if (objects.length > 0 && clazz.isEnum()) { 25 | Method valueOf = clazz.getMethod( 26 | "valueOf", String.class); 27 | for (int i = 0; i < objects.length; i++) { 28 | objects[i] = valueOf.invoke(null, objects[i].toString()); 29 | } 30 | } 31 | } 32 | 33 | public static void convertObjectArrayToIfDate(Class clazz, Object[] objects) throws Exception { 34 | if (objects.length > 0 && Date.class.isAssignableFrom(clazz)) { 35 | for (int i = 0; i < objects.length; i++) { 36 | objects[i] = new Date(Long.parseLong(objects[i].toString())); 37 | } 38 | } 39 | } 40 | 41 | 42 | public static List convertObjectArrayToIfNotAvailable(Class clazz, List objects) throws Exception { 43 | if (FieldUtil.isSupportedType(clazz)) { 44 | List result = new ArrayList<>(); 45 | for (Object object : objects) { 46 | result.add(FieldUtil.fillValue(clazz, object.toString())); 47 | } 48 | return result; 49 | } 50 | 51 | return objects; 52 | } 53 | 54 | @SuppressWarnings("unchecked") 55 | public static T deserializeObject(String serialized, Class clazz) throws Exception { 56 | if (FieldUtil.isSupportedType(clazz)) { 57 | return (T) FieldUtil.fillValue(clazz, serialized); 58 | } 59 | 60 | throw new SerializationException("Field Type: " + clazz.getName() + " not supported!"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/SpecificationUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util; 2 | 3 | import com.beyt.jdq.dto.Criteria; 4 | import com.beyt.jdq.exception.DynamicQueryNoFirstValueException; 5 | import org.springframework.core.io.ClassPathResource; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.nio.charset.StandardCharsets; 10 | import java.nio.file.Files; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by tdilber at 14-Aug-19 16 | */ 17 | public class SpecificationUtil { 18 | 19 | public static String toLowerCaseFirstLetter(String string) { 20 | if (string.length() <= 1) { 21 | throw new RuntimeException("String don't have available length!!"); 22 | } 23 | return Character.toLowerCase(string.charAt(0)) + string.substring(1); 24 | } 25 | 26 | public static void checkHasFirstValue(Criteria criteria) { 27 | if (criteria.getValues().size() == 0) { 28 | throw new DynamicQueryNoFirstValueException("There is No Value in Criteria Key: " + criteria.getKey()); 29 | } 30 | } 31 | 32 | public static void checkHasTwoValue(Criteria criteria) { 33 | if (criteria.getValues().size() < 2) { 34 | throw new DynamicQueryNoFirstValueException("There is No Value in Criteria Key: " + criteria.getKey()); 35 | } 36 | } 37 | 38 | public static String getStringFromResourceFile(String path) throws IOException { 39 | File resource = new ClassPathResource(path).getFile(); 40 | return new String(Files.readAllBytes(resource.toPath()), StandardCharsets.UTF_8); 41 | } 42 | 43 | public static void convertObjectToCriteriaValue(Object value, Criteria criteriaDTO) { 44 | if (value.getClass().isArray()) { 45 | criteriaDTO.setValues(Arrays.asList((Object[]) value)); 46 | } else if (value instanceof List) { 47 | criteriaDTO.setValues((List) value); 48 | } else { 49 | Object[] array = new Object[1]; 50 | array[0] = value; 51 | criteriaDTO.setValues(Arrays.asList(array)); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util; 2 | 3 | import org.springframework.util.Assert; 4 | 5 | import java.util.Locale; 6 | 7 | /** 8 | * Created by tdilber at 14-Sep-19 9 | */ 10 | public class StringUtil { 11 | 12 | public static String lowerFirstLetter(String simpleName) { 13 | Assert.hasText(simpleName, "must have text!"); 14 | return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1); 15 | } 16 | 17 | public static String uppercaseFirstLetter(String simpleName) { 18 | Assert.hasText(simpleName, "must have text!"); 19 | return simpleName.substring(0, 1).toUpperCase(Locale.ENGLISH) + simpleName.substring(1); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/FieldUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field; 2 | 3 | import com.beyt.jdq.util.field.helper.*; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import java.time.Instant; 7 | import java.time.LocalDate; 8 | import java.time.ZonedDateTime; 9 | import java.util.Date; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.sql.Timestamp; 13 | 14 | /** 15 | * Created by tdilber at 11/17/2020 16 | */ 17 | @Slf4j 18 | public final class FieldUtil { 19 | private FieldUtil() { 20 | 21 | } 22 | 23 | private static final Map, IFieldHelper> fieldHelperMap = new HashMap<>(); 24 | 25 | static { 26 | fieldHelperMap.put(String.class, new StringFieldHelper()); 27 | fieldHelperMap.put(Boolean.class, new BooleanFieldHelper()); 28 | fieldHelperMap.put(Date.class, new DateFieldHelper()); 29 | fieldHelperMap.put(Timestamp.class, new TimestampFieldHelper()); 30 | fieldHelperMap.put(Double.class, new DoubleFieldHelper()); 31 | fieldHelperMap.put(Long.class, new LongFieldHelper()); 32 | fieldHelperMap.put(LocalDate.class, new LocalDateFieldHelper()); 33 | fieldHelperMap.put(ZonedDateTime.class, new ZonedDateTimeFieldHelper()); 34 | fieldHelperMap.put(Instant.class, new InstantFieldHelper()); 35 | fieldHelperMap.put(Integer.class, new IntegerFieldHelper()); 36 | } 37 | 38 | private static IFieldHelper getFieldHelper(Class fieldType) { 39 | for (Class clazz : fieldHelperMap.keySet()) { 40 | if (fieldType.isAssignableFrom(clazz) && fieldHelperMap.containsKey(clazz)) { 41 | return fieldHelperMap.get(clazz); 42 | } 43 | } 44 | throw new IllegalStateException("Field Type: " + fieldType.getName() + " not supported!"); 45 | } 46 | 47 | public static boolean isSupportedType(Class clazz) { 48 | return clazz.isEnum() || fieldHelperMap.containsKey(clazz); 49 | } 50 | 51 | public static Object fillRandom(Class fieldType) { 52 | if (fieldType.isEnum()) { 53 | return new EnumFieldHelper(fieldType).fillRandom(); 54 | } 55 | return getFieldHelper(fieldType).fillRandom(); 56 | } 57 | 58 | public static Object fillValue(Class fieldType, String value) { 59 | if (fieldType.isEnum()) { 60 | return new EnumFieldHelper(fieldType).fillValue(value); 61 | } 62 | return getFieldHelper(fieldType).fillValue(value); 63 | } 64 | 65 | public static String createGeneratorCode(Class fieldType, String value) { 66 | if (fieldType.isEnum()) { 67 | return new EnumFieldHelper(fieldType).createGeneratorCode(value); 68 | } 69 | return getFieldHelper(fieldType).createGeneratorCode(value); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/BooleanFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 11/17/2020 7 | */ 8 | @Slf4j 9 | public class BooleanFieldHelper implements IFieldHelper { 10 | @Override 11 | public Boolean fillRandom() { 12 | return random.nextBoolean(); 13 | } 14 | 15 | @Override 16 | public Boolean fillValue(String value) { 17 | return Boolean.parseBoolean(value); 18 | } 19 | 20 | @Override 21 | public String createGeneratorCode(String value) { 22 | return value.toLowerCase(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/DateFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.text.DateFormat; 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | /** 11 | * Created by tdilber at 11/17/2020 12 | */ 13 | @Slf4j 14 | public class DateFieldHelper implements IFieldHelper { 15 | @Override 16 | public Date fillRandom() { 17 | return new Date(System.currentTimeMillis() + random.nextInt(1000000000)); 18 | } 19 | 20 | @Override 21 | public Date fillValue(String value) { 22 | DateFormat dateFormat = new SimpleDateFormat(); 23 | try { 24 | return dateFormat.parse(value); 25 | } catch (ParseException e) { 26 | throw new IllegalStateException(e.getMessage(), e); 27 | } 28 | } 29 | 30 | @Override 31 | public String createGeneratorCode(String value) { 32 | return "new Date(" + fillValue(value).getTime() + "L)"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/DoubleFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 11/17/2020 7 | */ 8 | @Slf4j 9 | public class DoubleFieldHelper implements IFieldHelper { 10 | @Override 11 | public Double fillRandom() { 12 | return random.nextDouble(); 13 | } 14 | 15 | @Override 16 | public Double fillValue(String value) { 17 | return Double.parseDouble(value); 18 | } 19 | 20 | @Override 21 | public String createGeneratorCode(String value) { 22 | return value + "d"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/EnumFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 11/17/2020 7 | */ 8 | @Slf4j 9 | public class EnumFieldHelper> implements IFieldHelper { 10 | private final Class enumType; 11 | 12 | public EnumFieldHelper(Class enumType) { 13 | this.enumType = enumType; 14 | } 15 | 16 | @Override 17 | public T fillRandom() { 18 | T[] enumConstants = enumType.getEnumConstants(); 19 | return enumConstants[random.nextInt(enumConstants.length)]; 20 | } 21 | 22 | @Override 23 | public T fillValue(String value) { 24 | T[] enumConstants = enumType.getEnumConstants(); 25 | for (T enumConstant : enumConstants) { 26 | if (enumConstant.toString().equalsIgnoreCase(value)) { 27 | return enumConstant; 28 | } 29 | } 30 | throw new IllegalStateException("Enum Type: " + enumType.getSimpleName() + " value: " + value + " not matched!"); 31 | } 32 | 33 | @Override 34 | public String createGeneratorCode(String value) { 35 | T[] enumConstants = enumType.getEnumConstants(); 36 | for (T enumConstant : enumConstants) { 37 | if (enumConstant.toString().equalsIgnoreCase(value)) { 38 | return enumType.getSimpleName() + "." + enumConstant.name(); 39 | } 40 | } 41 | 42 | throw new IllegalStateException("Enum Type: " + enumType.getSimpleName() + " value: " + value + " not matched!"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/IFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * Created by tdilber at 11/17/2020 7 | */ 8 | public interface IFieldHelper { 9 | static final Random random = new Random(); 10 | 11 | T fillRandom(); 12 | 13 | T fillValue(String value); 14 | 15 | String createGeneratorCode(String value); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/InstantFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.time.Instant; 6 | 7 | /** 8 | * Created by tdilber at 11/17/2020 9 | */ 10 | @Slf4j 11 | public class InstantFieldHelper implements IFieldHelper { 12 | @Override 13 | public Instant fillRandom() { 14 | return Instant.ofEpochMilli(System.currentTimeMillis() + random.nextInt(1000000000)); 15 | } 16 | 17 | @Override 18 | public Instant fillValue(String value) { 19 | return Instant.parse(value); 20 | } 21 | 22 | @Override 23 | public String createGeneratorCode(String value) { 24 | return "Instant.parse(\"" + value + "\")"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/IntegerFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 11/17/2020 7 | */ 8 | @Slf4j 9 | public class IntegerFieldHelper implements IFieldHelper { 10 | @Override 11 | public Integer fillRandom() { 12 | return random.nextInt(); 13 | } 14 | 15 | @Override 16 | public Integer fillValue(String value) { 17 | return Integer.parseInt(value); 18 | } 19 | 20 | @Override 21 | public String createGeneratorCode(String value) { 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/LocalDateFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.time.Instant; 6 | import java.time.LocalDate; 7 | import java.time.ZoneId; 8 | 9 | /** 10 | * Created by tdilber at 11/17/2020 11 | */ 12 | @Slf4j 13 | public class LocalDateFieldHelper implements IFieldHelper { 14 | @Override 15 | public LocalDate fillRandom() { 16 | return Instant.ofEpochMilli(System.currentTimeMillis() + random.nextInt(1000000000)) 17 | .atZone(ZoneId.systemDefault()) 18 | .toLocalDate(); 19 | } 20 | 21 | @Override 22 | public LocalDate fillValue(String value) { 23 | return LocalDate.parse(value); 24 | } 25 | 26 | @Override 27 | public String createGeneratorCode(String value) { 28 | return "LocalDate.parse(\"" + value + "\")"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/LongFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * Created by tdilber at 11/17/2020 7 | */ 8 | @Slf4j 9 | public class LongFieldHelper implements IFieldHelper { 10 | @Override 11 | public Long fillRandom() { 12 | return random.nextLong(); 13 | } 14 | 15 | @Override 16 | public Long fillValue(String value) { 17 | return Long.parseLong(value); 18 | } 19 | 20 | @Override 21 | public String createGeneratorCode(String value) { 22 | return value + "L"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/StringFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.util.Random; 6 | 7 | /** 8 | * Created by tdilber at 11/17/2020 9 | */ 10 | @Slf4j 11 | public class StringFieldHelper implements IFieldHelper { 12 | int lastIndex = 0; 13 | 14 | @Override 15 | public String fillRandom() { 16 | int leftLimit = 97; // letter 'a' 17 | int rightLimit = 122; // letter 'z' 18 | int targetStringLength = 8; 19 | Random random = new Random(); 20 | 21 | String generatedString = random.ints(leftLimit, rightLimit + 1) 22 | .limit(targetStringLength) 23 | .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) 24 | .toString(); 25 | return generatedString 26 | + Long.toString(System.currentTimeMillis()).substring(4) 27 | + (lastIndex++); 28 | } 29 | 30 | @Override 31 | public String fillValue(String value) { 32 | return value; 33 | } 34 | 35 | @Override 36 | public String createGeneratorCode(String value) { 37 | return "\"" + value + "\""; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/TimestampFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.text.DateFormat; 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.sql.Timestamp; 9 | 10 | /** 11 | * Created by tdilber at 11/17/2020 12 | */ 13 | @Slf4j 14 | public class TimestampFieldHelper implements IFieldHelper { 15 | @Override 16 | public Timestamp fillRandom() { 17 | return new Timestamp(System.currentTimeMillis() + random.nextInt(1000000000)); 18 | } 19 | 20 | @Override 21 | public Timestamp fillValue(String value) { 22 | DateFormat dateFormat = new SimpleDateFormat(); 23 | try { 24 | return new Timestamp(dateFormat.parse(value).getTime()); 25 | } catch (ParseException e) { 26 | throw new IllegalStateException(e.getMessage(), e); 27 | } 28 | } 29 | 30 | @Override 31 | public String createGeneratorCode(String value) { 32 | return "new Timestamp(" + fillValue(value).getTime() + "L)"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/beyt/jdq/util/field/helper/ZonedDateTimeFieldHelper.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util.field.helper; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.time.Instant; 6 | import java.time.ZoneId; 7 | import java.time.ZonedDateTime; 8 | 9 | /** 10 | * Created by tdilber at 11/17/2020 11 | */ 12 | @Slf4j 13 | public class ZonedDateTimeFieldHelper implements IFieldHelper { 14 | @Override 15 | public ZonedDateTime fillRandom() { 16 | return ZonedDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() + random.nextInt(1000000000)), ZoneId.systemDefault()); 17 | } 18 | 19 | @Override 20 | public ZonedDateTime fillValue(String value) { 21 | return ZonedDateTime.parse(value); 22 | } 23 | 24 | @Override 25 | public String createGeneratorCode(String value) { 26 | return "ZonedDateTime.parse(\"" + value + "\")"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/TestApplication.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq; 2 | 3 | import com.beyt.jdq.annotation.EnableJpaDynamicQuery; 4 | import com.beyt.jdq.annotation.EnableJpaDynamicQueryArgumentResolvers; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | @SpringBootApplication 9 | @EnableJpaDynamicQuery 10 | @EnableJpaDynamicQueryArgumentResolvers 11 | public class TestApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(TestApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/TestUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.databind.SerializationFeature; 6 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 7 | import com.google.gson.*; 8 | import com.google.gson.stream.JsonReader; 9 | import com.google.gson.stream.JsonToken; 10 | import com.google.gson.stream.JsonWriter; 11 | import org.apache.logging.log4j.util.Strings; 12 | import org.hamcrest.Description; 13 | import org.hamcrest.TypeSafeDiagnosingMatcher; 14 | import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; 15 | import org.springframework.format.support.DefaultFormattingConversionService; 16 | import org.springframework.format.support.FormattingConversionService; 17 | 18 | import jakarta.persistence.EntityManager; 19 | import jakarta.persistence.TypedQuery; 20 | import jakarta.persistence.criteria.CriteriaBuilder; 21 | import jakarta.persistence.criteria.CriteriaQuery; 22 | import jakarta.persistence.criteria.Root; 23 | import java.io.IOException; 24 | import java.time.Instant; 25 | import java.time.ZonedDateTime; 26 | import java.time.format.DateTimeParseException; 27 | import java.util.ArrayList; 28 | import java.util.Arrays; 29 | import java.util.Collections; 30 | import java.util.List; 31 | 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | 34 | /** 35 | * Utility class for testing REST controllers. 36 | */ 37 | public final class TestUtil { 38 | 39 | private static final ObjectMapper mapper = createObjectMapper(); 40 | private static ExclusionStrategy excludeStrings = new SpecificClassExclusionStrategy(); 41 | private static Gson gson = new GsonBuilder() 42 | .registerTypeAdapter(Instant.class, new TypeAdapter() { 43 | @Override 44 | public void write(JsonWriter out, Instant value) throws IOException { 45 | out.value(value.toString()); 46 | } 47 | 48 | @Override 49 | public Instant read(JsonReader in) throws IOException { 50 | if (in.peek() == JsonToken.NULL) { 51 | in.nextNull(); 52 | return null; 53 | } 54 | 55 | String nextString = in.nextString(); 56 | if (Strings.isBlank(nextString)) { 57 | return null; 58 | } 59 | 60 | return Instant.parse(nextString); 61 | } 62 | }) 63 | .setExclusionStrategies(excludeStrings) 64 | .create(); 65 | 66 | private static class SpecificClassExclusionStrategy implements ExclusionStrategy { 67 | @Override 68 | public boolean shouldSkipField(FieldAttributes f) { 69 | return false; /*f.getName().equals("createdByName") || 70 | f.getName().equals("createdDate") || 71 | f.getName().equals("modifiedBy") || 72 | f.getName().equals("modifiedDate") || 73 | f.getName().equals("lastModifiedByName") || 74 | f.getName().equals("date") || 75 | f.getName().equals("lastModifiedDate");*/ 76 | } 77 | 78 | @Override 79 | public boolean shouldSkipClass(Class aClass) { 80 | return false; 81 | } 82 | } 83 | 84 | public static List toList(T... values) { 85 | ArrayList list = new ArrayList<>(); 86 | Collections.addAll(list, values); 87 | return list; 88 | } 89 | 90 | private static ObjectMapper createObjectMapper() { 91 | ObjectMapper mapper = new ObjectMapper(); 92 | mapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false); 93 | mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); 94 | mapper.registerModule(new JavaTimeModule()); 95 | return mapper; 96 | } 97 | 98 | /** 99 | * Convert an object to JSON byte array. 100 | * 101 | * @param object the object to convert. 102 | * @return the JSON byte array. 103 | * @throws IOException 104 | */ 105 | public static byte[] convertObjectToJsonBytes(Object object) throws IOException { 106 | return mapper.writeValueAsBytes(object); 107 | } 108 | 109 | /** 110 | * Create a byte array with a specific size filled with specified data. 111 | * 112 | * @param size the size of the byte array. 113 | * @param data the data to put in the byte array. 114 | * @return the JSON byte array. 115 | */ 116 | public static byte[] createByteArray(int size, String data) { 117 | byte[] byteArray = new byte[size]; 118 | for (int i = 0; i < size; i++) { 119 | byteArray[i] = Byte.parseByte(data, 2); 120 | } 121 | return byteArray; 122 | } 123 | 124 | public static List getResultListValue(String content, Class clazz) { 125 | T[] arr = gson.fromJson(content, clazz); 126 | return Arrays.asList(arr); //or return Arrays.asList(new Gson().fromJson(s, clazz)); for a one-liner 127 | } 128 | 129 | public static T getResultValue(String content, Class clazz) { 130 | T result = gson.fromJson(content, clazz); 131 | return result; 132 | } 133 | 134 | /** 135 | * A matcher that tests that the examined string represents the same instant as the reference datetime. 136 | */ 137 | public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher { 138 | 139 | private final ZonedDateTime date; 140 | 141 | public ZonedDateTimeMatcher(ZonedDateTime date) { 142 | this.date = date; 143 | } 144 | 145 | @Override 146 | protected boolean matchesSafely(String item, Description mismatchDescription) { 147 | try { 148 | if (!date.isEqual(ZonedDateTime.parse(item))) { 149 | mismatchDescription.appendText("was ").appendValue(item); 150 | return false; 151 | } 152 | return true; 153 | } catch (DateTimeParseException e) { 154 | mismatchDescription.appendText("was ").appendValue(item) 155 | .appendText(", which could not be parsed as a ZonedDateTime"); 156 | return false; 157 | } 158 | 159 | } 160 | 161 | @Override 162 | public void describeTo(Description description) { 163 | description.appendText("a String representing the same Instant as ").appendValue(date); 164 | } 165 | } 166 | 167 | /** 168 | * Creates a matcher that matches when the examined string represents the same instant as the reference datetime. 169 | * 170 | * @param date the reference datetime against which the examined string is checked. 171 | */ 172 | public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { 173 | return new ZonedDateTimeMatcher(date); 174 | } 175 | 176 | /** 177 | * Verifies the equals/hashcode contract on the domain object. 178 | */ 179 | public static void equalsVerifier(Class clazz) throws Exception { 180 | T domainObject1 = clazz.getConstructor().newInstance(); 181 | assertThat(domainObject1.toString()).isNotNull(); 182 | assertThat(domainObject1).isEqualTo(domainObject1); 183 | assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); 184 | // Test with an instance of another class 185 | Object testOtherObject = new Object(); 186 | assertThat(domainObject1).isNotEqualTo(testOtherObject); 187 | assertThat(domainObject1).isNotEqualTo(null); 188 | // Test with an instance of the same class 189 | T domainObject2 = clazz.getConstructor().newInstance(); 190 | assertThat(domainObject1).isNotEqualTo(domainObject2); 191 | // HashCodes are equals because the objects are not persisted yet 192 | assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); 193 | } 194 | 195 | /** 196 | * Create a {@link FormattingConversionService} which use ISO date format, instead of the localized one. 197 | * 198 | * @return the {@link FormattingConversionService}. 199 | */ 200 | public static FormattingConversionService createFormattingConversionService() { 201 | DefaultFormattingConversionService dfcs = new DefaultFormattingConversionService(); 202 | DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); 203 | registrar.setUseIsoFormat(true); 204 | registrar.registerFormatters(dfcs); 205 | return dfcs; 206 | } 207 | 208 | /** 209 | * Makes a an executes a query to the EntityManager finding all stored objects. 210 | * 211 | * @param The type of objects to be searched 212 | * @param em The instance of the EntityManager 213 | * @param clss The class type to be searched 214 | * @return A list of all found objects 215 | */ 216 | public static List findAll(EntityManager em, Class clss) { 217 | CriteriaBuilder cb = em.getCriteriaBuilder(); 218 | CriteriaQuery cq = cb.createQuery(clss); 219 | Root rootEntry = cq.from(clss); 220 | CriteriaQuery all = cq.select(rootEntry); 221 | TypedQuery allQuery = em.createQuery(all); 222 | return allQuery.getResultList(); 223 | } 224 | 225 | private TestUtil() { 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/context/DBSelectionContext.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.context; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.context.annotation.RequestScope; 7 | 8 | import java.io.Serializable; 9 | 10 | 11 | @Component 12 | @RequestScope 13 | public class DBSelectionContext implements Serializable { 14 | public enum Database { 15 | READ, WRITE 16 | } 17 | 18 | @Getter 19 | @Setter 20 | private Database database = Database.WRITE; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/controller/PresentationTestController.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.controller; 2 | 3 | import com.beyt.jdq.dto.CriteriaList; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.presetation.S9_Query_Builder; 6 | import com.beyt.jdq.testenv.entity.school.Course; 7 | import com.beyt.jdq.testenv.repository.AdminUserRepository; 8 | import com.beyt.jdq.testenv.repository.CourseRepository; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.data.domain.Page; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.util.List; 17 | 18 | @RestController 19 | @RequestMapping("/test-api") 20 | public class PresentationTestController { 21 | @Autowired 22 | private CourseRepository courseRepository; 23 | @Autowired 24 | private AdminUserRepository adminUserRepository; 25 | 26 | 27 | @GetMapping("/course") 28 | public ResponseEntity> getCourseWithCriteria(CriteriaList criteriaList) { 29 | List customerList = courseRepository.findAll(criteriaList); 30 | return ResponseEntity.ok().body(customerList); 31 | } 32 | 33 | @GetMapping("/course/as-page") 34 | public ResponseEntity> getCourseWithSearchFilterAsPage(DynamicQuery dynamicQuery) { 35 | Page customerList = courseRepository.findAllAsPage(dynamicQuery); 36 | return ResponseEntity.ok().body(customerList); 37 | } 38 | 39 | @GetMapping("/course/as-list") 40 | public ResponseEntity> getCourseWithSearchFilterAsList(DynamicQuery dynamicQuery) { 41 | List customerList = adminUserRepository.findAll(dynamicQuery, S9_Query_Builder.AuthorizationSummary.class); 42 | return ResponseEntity.ok().body(customerList); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/deserializer/DateTimeDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.deserializer; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.sql.Timestamp; 6 | import java.text.SimpleDateFormat; 7 | import java.sql.Timestamp; 8 | import java.util.Date; 9 | 10 | @Component 11 | public class DateTimeDeserializer extends BasicDeserializer { 12 | 13 | @Override 14 | public T deserialize(Object value, Class clazz) throws Exception { 15 | if (clazz.isAssignableFrom(Date.class)) { 16 | if (value instanceof Date date) { 17 | return (T) date; 18 | } 19 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); 20 | simpleDateFormat.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); 21 | Date parsedDate = simpleDateFormat.parse(value.toString()); 22 | return (T) parsedDate; 23 | } 24 | 25 | if (clazz.isAssignableFrom(Timestamp.class)) { 26 | if (value instanceof Timestamp date) { 27 | return (T) date; 28 | } 29 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); 30 | simpleDateFormat.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); 31 | Date parsedDate = simpleDateFormat.parse(value.toString()); 32 | return (T) new Timestamp(parsedDate.getTime()); 33 | } 34 | 35 | 36 | 37 | return super.deserialize(value, clazz); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/interceptor/DatabaseSelectionInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.interceptor; 2 | 3 | import com.beyt.jdq.context.DBSelectionContext; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.method.HandlerMethod; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | 10 | import jakarta.servlet.http.HttpServletRequest; 11 | import jakarta.servlet.http.HttpServletResponse; 12 | import java.lang.reflect.Method; 13 | 14 | @Slf4j 15 | public class DatabaseSelectionInterceptor implements HandlerInterceptor { 16 | 17 | @Autowired 18 | private DBSelectionContext dbSelectionContext; 19 | 20 | @Override 21 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 22 | if (!(handler instanceof HandlerMethod)) { 23 | return true; 24 | } 25 | 26 | HandlerMethod handlerMethod = (HandlerMethod) handler; 27 | Method method = handlerMethod.getMethod(); 28 | GetMapping getMapping = method.getAnnotation(GetMapping.class); 29 | if (getMapping != null) { 30 | dbSelectionContext.setDatabase(DBSelectionContext.Database.READ); 31 | } 32 | 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S10_Argument_Resolvers.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.TestUtil; 6 | import com.beyt.jdq.testenv.entity.school.Course; 7 | import com.beyt.jdq.util.PresentationUtil; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestInstance; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.http.MediaType; 14 | import org.springframework.test.annotation.DirtiesContext; 15 | import org.springframework.test.web.servlet.MockMvc; 16 | import org.springframework.test.web.servlet.MvcResult; 17 | 18 | import java.util.List; 19 | import java.util.Objects; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 25 | 26 | @AutoConfigureMockMvc 27 | @SpringBootTest(classes = TestApplication.class) 28 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 29 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 30 | public class S10_Argument_Resolvers extends BaseTestInstance { 31 | 32 | @Autowired 33 | private MockMvc mockMvc; 34 | 35 | private static final String COURSE_SEARCH_LIST_API_URL = "/test-api/course/as-list"; 36 | private static final String COURSE_CRITERIA_API_URL = "/test-api/course"; 37 | 38 | 39 | @Test 40 | public void argumentCriteriaListTests() throws Exception { 41 | // List.of(course1, course2, course3, course4, course5, course6, course7, course8, course9, course10); 42 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 43 | "key0=name&operation0=CONTAIN&values0=Calculus", Course[].class, List.of(course2, course3)); 44 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 45 | "key0=name&operation0=DOES_NOT_CONTAIN&values0=I", Course[].class, List.of()); 46 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 47 | "key0=name&operation0=END_WITH&values0=Science", Course[].class, List.of(course1)); 48 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 49 | "key0=name&operation0=START_WITH&values0=Physics", Course[].class, List.of(course4, course5)); 50 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 51 | "key0=active&operation0=SPECIFIED&values0=true", Course[].class, List.of(course1, course2, course8, course9, course10)); 52 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 53 | "key0=active&operation0=SPECIFIED&values0=false", Course[].class, List.of(course3, course4, course5, course6, course7)); 54 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 55 | "key0=name&operation0=EQUAL&values0=Calculus I", Course[].class, List.of(course2)); 56 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 57 | "key0=startDate&operation0=EQUAL&values0=2015-06-18", Course[].class, List.of()); 58 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 59 | "key0=maxStudentCount&operation0=EQUAL&values0=54", Course[].class, List.of(course9)); 60 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 61 | "key0=name&operation0=NOT_EQUAL&values0=Introduction to Computer Science", Course[].class, List.of(course2, course3, course4, course5, course6, course7, course8, course9, course10)); 62 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 63 | "key0=id&operation0=GREATER_THAN&values0=5", Course[].class, List.of(course6, course7, course8, course9, course10)); 64 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 65 | "key0=startDate&operation0=GREATER_THAN&values0=2015-06-18", Course[].class, List.of(course1, course2, course3, course4, course5, course6, course7, course10)); 66 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 67 | "key0=id&operation0=GREATER_THAN_OR_EQUAL&values0=8", Course[].class, List.of(course8, course9, course10)); 68 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 69 | "key0=startDate&operation0=GREATER_THAN_OR_EQUAL&values0=2019-06-18", Course[].class, List.of(course5, course6, course7, course10)); 70 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 71 | "key0=maxStudentCount&operation0=LESS_THAN&values0=40", Course[].class, List.of(course7, course8, course10)); 72 | printRequestedResultAndAssert(COURSE_CRITERIA_API_URL, 73 | "key0=maxStudentCount&operation0=LESS_THAN_OR_EQUAL&values0=40", Course[].class, List.of(course6, course7, course8, course10)); 74 | } 75 | 76 | 77 | @Test 78 | public void argumentSearchQueryTests() throws Exception { 79 | printRequestedResultAndAssert(COURSE_SEARCH_LIST_API_URL, 80 | "select0=id&select1=username&select2=roles.id&select3=roles.name&select4=roles.roleAuthorizations.authorization.id&select5=roles.roleAuthorizations.authorization.name&select6=roles.roleAuthorizations.authorization.menuIcon&" + 81 | "selectAs0=adminId&selectAs1=adminUsername&selectAs2=roleId&selectAs3=roleName&selectAs4=authorizationId&selectAs5=authorizationName&selectAs6=menuIcon&" + 82 | "orderBy0=roles.id&orderByDirection0=desc&" + 83 | "page=1&" + 84 | "pageSize=2&" + 85 | "key0=roles.roleAuthorizations.authorization.menuIcon&operation0=START_WITH&values0=icon", S9_Query_Builder.AuthorizationSummary[].class, List.of(new S9_Query_Builder.AuthorizationSummary(3L, "admin3", 3L, "role3", 3L, "auth3", "icon3"), new S9_Query_Builder.AuthorizationSummary(2L, "admin2", 2L, "role2", 2L, "auth2", "icon2"))); 86 | } 87 | 88 | private void printRequestedResultAndAssert(String apiUrl, String filter, Class clazz, Object result) throws Exception { 89 | MvcResult mvcResult = mockMvc.perform(get(apiUrl + "?" + filter)) 90 | .andExpect(status().isOk()) 91 | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); 92 | 93 | PresentationUtil.prettyPrint(TestUtil.getResultListValue(mvcResult.getResponse().getContentAsString(), clazz)); 94 | 95 | assertEquals(result, TestUtil.getResultListValue(mvcResult.getResponse().getContentAsString(), clazz)); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S11_Additional_Features.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.TestUtil; 6 | import com.beyt.jdq.dto.Criteria; 7 | import com.beyt.jdq.dto.CriteriaList; 8 | import com.beyt.jdq.dto.enums.CriteriaOperator; 9 | import com.beyt.jdq.testenv.entity.school.Course; 10 | import com.beyt.jdq.testenv.repository.CourseRepository; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.TestInstance; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 15 | import org.springframework.boot.test.context.SpringBootTest; 16 | import org.springframework.test.annotation.DirtiesContext; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | @SpringBootTest(classes = TestApplication.class) 24 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 25 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 26 | public class S11_Additional_Features extends BaseTestInstance { 27 | private @Autowired CourseRepository courseRepository; 28 | 29 | 30 | @Test 31 | public void consumePartially() { 32 | List courses = new ArrayList<>(); 33 | courseRepository.consumePartially((courseList) -> { 34 | courseList.forEach(course -> { 35 | System.out.println(course.getName()); 36 | }); 37 | System.out.println("Consumed partially"); 38 | courses.addAll(courseList); 39 | }, 2); 40 | 41 | assertEquals(List.of(course1, course2, course3, course4, course5, course6, course7, course8, course9, course10), courses); 42 | } 43 | 44 | @Test 45 | public void consumePartially2() { 46 | List courses = new ArrayList<>(); 47 | CriteriaList criteriaList = CriteriaList.of(Criteria.of("id", CriteriaOperator.GREATER_THAN, 5)); 48 | courseRepository.consumePartially(criteriaList, (courseList) -> { 49 | courseList.forEach(course -> { 50 | System.out.println(course.getName()); 51 | }); 52 | System.out.println("Consumed partially"); 53 | courses.addAll(courseList); 54 | }, 2); 55 | assertEquals(List.of(course6, course7, course8, course9, course10), courses); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S1_Operators.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.Criteria; 6 | import com.beyt.jdq.dto.CriteriaList; 7 | import com.beyt.jdq.dto.enums.CriteriaOperator; 8 | import com.beyt.jdq.testenv.entity.User; 9 | import com.beyt.jdq.testenv.entity.school.Course; 10 | import com.beyt.jdq.testenv.repository.CourseRepository; 11 | import com.beyt.jdq.testenv.repository.DepartmentRepository; 12 | import com.beyt.jdq.util.PresentationUtil; 13 | import lombok.SneakyThrows; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.TestInstance; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 19 | import org.springframework.boot.test.context.SpringBootTest; 20 | import org.springframework.test.annotation.DirtiesContext; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import static java.util.stream.Collectors.toList; 26 | import static org.junit.jupiter.api.Assertions.assertEquals; 27 | 28 | @Slf4j 29 | @SpringBootTest(classes = TestApplication.class) 30 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 31 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 32 | public class S1_Operators extends BaseTestInstance { 33 | private @Autowired CourseRepository courseRepository; 34 | private @Autowired DepartmentRepository departmentRepository; 35 | 36 | 37 | //CONTAIN 38 | //DOES_NOT_CONTAIN 39 | //END_WITH 40 | //START_WITH 41 | //SPECIFIED 42 | //EQUAL 43 | //NOT_EQUAL 44 | //GREATER_THAN 45 | //GREATER_THAN_OR_EQUAL 46 | //LESS_THAN 47 | //LESS_THAN_OR_EQUAL 48 | 49 | @Test 50 | public void contain() { 51 | var criteriaList = CriteriaList.of(Criteria.of("name", CriteriaOperator.CONTAIN, "Calculus")); 52 | PresentationUtil.prettyPrint(criteriaList); 53 | List courseList = courseRepository.findAll(criteriaList); 54 | PresentationUtil.prettyPrint(courseList); 55 | 56 | assertEquals(new ArrayList<>(List.of(course2, course3)), courseList); 57 | } 58 | 59 | @Test 60 | public void doesNotContain() { 61 | var criteriaList = CriteriaList.of(Criteria.of("name", CriteriaOperator.DOES_NOT_CONTAIN, "I")); 62 | PresentationUtil.prettyPrint(criteriaList); 63 | List courseList = courseRepository.findAll(criteriaList); 64 | PresentationUtil.prettyPrint(courseList); 65 | assertEquals(List.of(), courseList); 66 | } 67 | 68 | @Test 69 | public void endWith() { 70 | var criteriaList = CriteriaList.of(Criteria.of("name", CriteriaOperator.END_WITH, "Science")); 71 | PresentationUtil.prettyPrint(criteriaList); 72 | List courseList = courseRepository.findAll(criteriaList); 73 | PresentationUtil.prettyPrint(courseList); 74 | assertEquals(List.of(course1), courseList); 75 | } 76 | 77 | @Test 78 | public void startWith() { 79 | var criteriaList = CriteriaList.of(Criteria.of("name", CriteriaOperator.START_WITH, "Physics")); 80 | PresentationUtil.prettyPrint(criteriaList); 81 | List courseList = courseRepository.findAll(criteriaList); 82 | PresentationUtil.prettyPrint(courseList); 83 | assertEquals(List.of(course4, course5), courseList); 84 | } 85 | 86 | @Test 87 | public void specifiedTrue() { 88 | var criteriaList = CriteriaList.of(Criteria.of("active", CriteriaOperator.SPECIFIED, "true")); 89 | PresentationUtil.prettyPrint(criteriaList); 90 | List courseList = courseRepository.findAll(criteriaList); 91 | PresentationUtil.prettyPrint(courseList); 92 | assertEquals(List.of(course1, course2, course8, course9, course10), courseList); 93 | } 94 | 95 | 96 | 97 | @Test 98 | public void specifiedFalse() { 99 | var criteriaList = CriteriaList.of(Criteria.of("active", CriteriaOperator.SPECIFIED, "false")); 100 | PresentationUtil.prettyPrint(criteriaList); 101 | List courseList = courseRepository.findAll(criteriaList); 102 | PresentationUtil.prettyPrint(courseList); 103 | assertEquals(List.of(course3, course4, course5, course6, course7), courseList); 104 | } 105 | 106 | @Test 107 | public void equal() { 108 | var criteriaList = CriteriaList.of(Criteria.of("name", CriteriaOperator.EQUAL, "Calculus I")); 109 | PresentationUtil.prettyPrint(criteriaList); 110 | List courseList = courseRepository.findAll(criteriaList); 111 | PresentationUtil.prettyPrint(courseList); 112 | assertEquals(List.of(course2), courseList); 113 | } 114 | 115 | @SneakyThrows 116 | @Test 117 | public void equalDate() { 118 | var criteriaList = CriteriaList.of(Criteria.of("startDate", CriteriaOperator.EQUAL, "2015-06-18")); 119 | PresentationUtil.prettyPrint(criteriaList); 120 | List courseList = courseRepository.findAll(criteriaList); 121 | PresentationUtil.prettyPrint(courseList); 122 | assertEquals(List.of(), courseList); 123 | } 124 | 125 | @SneakyThrows 126 | @Test 127 | public void equalInteger() { 128 | var criteriaList = CriteriaList.of(Criteria.of("maxStudentCount", CriteriaOperator.EQUAL, 54)); 129 | PresentationUtil.prettyPrint(criteriaList); 130 | List courseList = courseRepository.findAll(criteriaList); 131 | PresentationUtil.prettyPrint(courseList);//9 132 | assertEquals(List.of(course9), courseList); 133 | } 134 | 135 | @Test 136 | public void notEqual() { 137 | var criteriaList = CriteriaList.of(Criteria.of("name", CriteriaOperator.NOT_EQUAL, "Introduction to Computer Science")); 138 | PresentationUtil.prettyPrint(criteriaList); 139 | List courseList = courseRepository.findAll(criteriaList); 140 | PresentationUtil.prettyPrint(courseList); //2,3,4,5,6,7,8,9,10 141 | assertEquals(List.of(course2, course3, course4, course5, course6, course7, course8, course9, course10), courseList); 142 | } 143 | 144 | @Test 145 | public void greaterThan() { 146 | var criteriaList = CriteriaList.of(Criteria.of("id", CriteriaOperator.GREATER_THAN, 5)); 147 | PresentationUtil.prettyPrint(criteriaList); 148 | List courseList = courseRepository.findAll(criteriaList); 149 | PresentationUtil.prettyPrint(courseList); 150 | assertEquals(List.of(course6, course7, course8, course9, course10), courseList); 151 | } 152 | 153 | @Test 154 | public void greaterThanDate() { 155 | var criteriaList = CriteriaList.of(Criteria.of("startDate", CriteriaOperator.GREATER_THAN, "2015-06-18")); 156 | PresentationUtil.prettyPrint(criteriaList); 157 | List courseList = courseRepository.findAll(criteriaList); 158 | PresentationUtil.prettyPrint(courseList); //1,2,3,4,5,6,7,10 159 | assertEquals(List.of(course1, course2, course3, course4, course5, course6, course7, course10), courseList); 160 | } 161 | 162 | @Test 163 | public void greaterThanOrEqual() { 164 | var criteriaList = CriteriaList.of(Criteria.of("id", CriteriaOperator.GREATER_THAN_OR_EQUAL, 8)); 165 | PresentationUtil.prettyPrint(criteriaList); 166 | List courseList = courseRepository.findAll(criteriaList); 167 | PresentationUtil.prettyPrint(courseList);//8,9,10 168 | assertEquals(List.of(course8, course9, course10), courseList); 169 | } 170 | 171 | @Test 172 | public void greaterThanOrEqualDate() { 173 | var criteriaList = CriteriaList.of(Criteria.of("startDate", CriteriaOperator.GREATER_THAN_OR_EQUAL, "2019-06-18")); 174 | PresentationUtil.prettyPrint(criteriaList); 175 | List courseList = courseRepository.findAll(criteriaList); 176 | PresentationUtil.prettyPrint(courseList);//5.6.7.10 177 | assertEquals(List.of(course5, course6, course7, course10), courseList); 178 | } 179 | 180 | @Test 181 | public void lessThan() { 182 | var criteriaList = CriteriaList.of(Criteria.of(Course.Fields.maxStudentCount, CriteriaOperator.LESS_THAN, 40)); 183 | PresentationUtil.prettyPrint(criteriaList); 184 | List courseList = courseRepository.findAll(criteriaList); 185 | PresentationUtil.prettyPrint(courseList); 186 | assertEquals(List.of(course7, course8, course10), courseList); 187 | } 188 | 189 | @Test 190 | public void lessThanOrEqual() { 191 | var criteriaList = CriteriaList.of(Criteria.of(Course.Fields.maxStudentCount, CriteriaOperator.LESS_THAN_OR_EQUAL, 40)); 192 | PresentationUtil.prettyPrint(criteriaList); 193 | List courseList = courseRepository.findAll(criteriaList); 194 | PresentationUtil.prettyPrint(courseList); // 6,7,8,10 195 | assertEquals(List.of(course6, course7, course8, course10), courseList); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S2_Multi_Value_Operators.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.Criteria; 6 | import com.beyt.jdq.dto.CriteriaList; 7 | import com.beyt.jdq.dto.enums.CriteriaOperator; 8 | import com.beyt.jdq.testenv.entity.school.Course; 9 | import com.beyt.jdq.testenv.repository.CourseRepository; 10 | import com.beyt.jdq.testenv.repository.DepartmentRepository; 11 | import com.beyt.jdq.util.PresentationUtil; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.TestInstance; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.List; 23 | 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | 26 | @Slf4j 27 | @SpringBootTest(classes = TestApplication.class) 28 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 29 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 30 | public class S2_Multi_Value_Operators extends BaseTestInstance { 31 | private @Autowired CourseRepository courseRepository; 32 | private @Autowired DepartmentRepository departmentRepository; 33 | 34 | 35 | @Test 36 | public void equal() { 37 | var criteriaList = CriteriaList.of(Criteria.of(Course.Fields.name, CriteriaOperator.EQUAL, "Calculus I", "Calculus II")); 38 | PresentationUtil.prettyPrint(criteriaList); 39 | List courseList = courseRepository.findAll(criteriaList); 40 | PresentationUtil.prettyPrint(courseList); //2,3 41 | assertEquals(List.of(course2, course3), courseList); 42 | } 43 | 44 | @Test 45 | public void equalInteger() { 46 | var criteriaList = CriteriaList.of(Criteria.of(Course.Fields.maxStudentCount, CriteriaOperator.EQUAL, 40, 50)); 47 | PresentationUtil.prettyPrint(criteriaList); 48 | List courseList = courseRepository.findAll(criteriaList); 49 | PresentationUtil.prettyPrint(courseList);//1,6 50 | assertEquals(List.of(course1, course6), courseList); 51 | } 52 | 53 | @Test 54 | public void notEqual() { 55 | var criteriaList = CriteriaList.of(Criteria.of(Course.Fields.name, CriteriaOperator.NOT_EQUAL, "Calculus I", "Calculus II")); 56 | PresentationUtil.prettyPrint(criteriaList); 57 | List courseList = courseRepository.findAll(criteriaList); 58 | PresentationUtil.prettyPrint(courseList);//1,4,5,6,7,8,9,10 59 | assertEquals(Arrays.asList(course1, course4, course5, course6, course7, course8, course9, course10), courseList); 60 | } 61 | 62 | @Test 63 | public void notEqualDate() { 64 | var criteriaList = CriteriaList.of(Criteria.of(Course.Fields.startDate, CriteriaOperator.NOT_EQUAL, "2013-06-18", "2015-06-18", "2016-06-18")); 65 | PresentationUtil.prettyPrint(criteriaList); 66 | List courseList = courseRepository.findAll(criteriaList); 67 | PresentationUtil.prettyPrint(courseList); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S3_AND_OR_Operator.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.Criteria; 6 | import com.beyt.jdq.dto.CriteriaList; 7 | import com.beyt.jdq.dto.enums.CriteriaOperator; 8 | import com.beyt.jdq.testenv.entity.school.Course; 9 | import com.beyt.jdq.testenv.repository.CourseRepository; 10 | import com.beyt.jdq.testenv.repository.DepartmentRepository; 11 | import com.beyt.jdq.util.PresentationUtil; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.TestInstance; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | 20 | import java.util.List; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | @Slf4j 25 | @SpringBootTest(classes = TestApplication.class) 26 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 27 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 28 | public class S3_AND_OR_Operator extends BaseTestInstance { 29 | private @Autowired CourseRepository courseRepository; 30 | private @Autowired DepartmentRepository departmentRepository; 31 | 32 | 33 | @Test 34 | public void and() { 35 | var criteriaList = CriteriaList.of( 36 | Criteria.of(Course.Fields.name, CriteriaOperator.CONTAIN, "II"), 37 | Criteria.of(Course.Fields.id, CriteriaOperator.GREATER_THAN, 5)); 38 | PresentationUtil.prettyPrint(criteriaList); 39 | List courseList = courseRepository.findAll(criteriaList); 40 | PresentationUtil.prettyPrint(courseList); // 7 , 9 41 | assertEquals(List.of(course7, course9), courseList); 42 | } 43 | 44 | 45 | @Test 46 | public void and2() { 47 | var criteriaList = CriteriaList.of( 48 | Criteria.of(Course.Fields.name, CriteriaOperator.CONTAIN, "II"), 49 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 7, 8, 9, 10), 50 | Criteria.of(Course.Fields.active, CriteriaOperator.SPECIFIED, false)); 51 | PresentationUtil.prettyPrint(criteriaList); 52 | List courseList = courseRepository.findAll(criteriaList); 53 | PresentationUtil.prettyPrint(courseList); // 7 54 | assertEquals(List.of(course7), courseList); 55 | } 56 | 57 | 58 | @Test 59 | public void or() { 60 | var criteriaList = CriteriaList.of( 61 | Criteria.of(Course.Fields.name, CriteriaOperator.CONTAIN, "II"), 62 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 7, 8, 9, 10), 63 | Criteria.of(Course.Fields.active, CriteriaOperator.SPECIFIED, false), 64 | Criteria.OR(), 65 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 1, 2, 3, 4, 5), 66 | Criteria.of(Course.Fields.id, CriteriaOperator.LESS_THAN, 3) 67 | ); 68 | PresentationUtil.prettyPrint(criteriaList); 69 | List courseList = courseRepository.findAll(criteriaList); 70 | PresentationUtil.prettyPrint(courseList);//1,2,7 71 | assertEquals(List.of(course1, course2, course7), courseList); 72 | } 73 | 74 | 75 | @Test 76 | public void or2() { 77 | var criteriaList = CriteriaList.of( 78 | Criteria.of(Course.Fields.name, CriteriaOperator.CONTAIN, "II"), 79 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 7, 8, 9, 10), 80 | Criteria.of(Course.Fields.active, CriteriaOperator.SPECIFIED, false), 81 | Criteria.OR(), 82 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 1, 2, 3, 4, 5), 83 | Criteria.OR(), 84 | Criteria.of(Course.Fields.id, CriteriaOperator.LESS_THAN, 3) 85 | ); 86 | PresentationUtil.prettyPrint(criteriaList); 87 | List courseList = courseRepository.findAll(criteriaList); 88 | PresentationUtil.prettyPrint(courseList);//1,2,3,4,5,7 89 | assertEquals(List.of(course1, course2, course3, course4, course5, course7), courseList); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S4_SCOPE_Operator.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.Criteria; 6 | import com.beyt.jdq.dto.CriteriaList; 7 | import com.beyt.jdq.dto.enums.CriteriaOperator; 8 | import com.beyt.jdq.testenv.entity.school.Course; 9 | import com.beyt.jdq.testenv.repository.CourseRepository; 10 | import com.beyt.jdq.testenv.repository.DepartmentRepository; 11 | import com.beyt.jdq.util.PresentationUtil; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.TestInstance; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | 20 | import java.util.List; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | @Slf4j 25 | @SpringBootTest(classes = TestApplication.class) 26 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 27 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 28 | public class S4_SCOPE_Operator extends BaseTestInstance { 29 | private @Autowired CourseRepository courseRepository; 30 | private @Autowired DepartmentRepository departmentRepository; 31 | 32 | 33 | // (A OR B) AND (C OR D) 34 | @Test 35 | public void scope() { 36 | var criteriaList = CriteriaList.of( 37 | Criteria.of("", CriteriaOperator.PARENTHES, 38 | CriteriaList.of(Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 1), 39 | Criteria.OR(), 40 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 2))), 41 | Criteria.of("", CriteriaOperator.PARENTHES, 42 | CriteriaList.of(Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 2), 43 | Criteria.OR(), 44 | Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 3))) 45 | ); 46 | PresentationUtil.prettyPrint(criteriaList); 47 | List courseList = courseRepository.findAll(criteriaList); 48 | PresentationUtil.prettyPrint(courseList); 49 | assertEquals(List.of(course2), courseList); 50 | } 51 | 52 | 53 | @Test 54 | public void scopeInsideScope() { 55 | var criteriaList = CriteriaList.of( 56 | Criteria.of("", CriteriaOperator.PARENTHES, 57 | CriteriaList.of(Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 1, 2, 3), 58 | Criteria.of(Course.Fields.id, CriteriaOperator.NOT_EQUAL, 2), 59 | Criteria.OR(), 60 | Criteria.of("", CriteriaOperator.PARENTHES, 61 | CriteriaList.of(Criteria.of(Course.Fields.id, CriteriaOperator.EQUAL, 2), 62 | Criteria.of(Course.Fields.id, CriteriaOperator.NOT_EQUAL, 3))))) 63 | ); 64 | PresentationUtil.prettyPrint(criteriaList); 65 | List courseList = courseRepository.findAll(criteriaList); 66 | PresentationUtil.prettyPrint(courseList); 67 | assertEquals(List.of(course1, course2, course3), courseList); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S5_Join.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.Criteria; 6 | import com.beyt.jdq.dto.CriteriaList; 7 | import com.beyt.jdq.dto.enums.CriteriaOperator; 8 | import com.beyt.jdq.testenv.entity.school.Department; 9 | import com.beyt.jdq.testenv.entity.school.Student; 10 | import com.beyt.jdq.testenv.repository.DepartmentRepository; 11 | import com.beyt.jdq.testenv.repository.StudentRepository; 12 | import com.beyt.jdq.util.PresentationUtil; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.TestInstance; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | 20 | import java.util.List; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | @SpringBootTest(classes = TestApplication.class) 25 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 26 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 27 | public class S5_Join extends BaseTestInstance { 28 | private @Autowired DepartmentRepository departmentRepository; 29 | private @Autowired StudentRepository studentRepository; 30 | 31 | 32 | /** 33 | * Inner join with single entity criteria 34 | */ 35 | @Test 36 | public void innerJoin() { 37 | var criteriaList = CriteriaList.of(Criteria.of("department.name", CriteriaOperator.START_WITH, "P")); 38 | PresentationUtil.prettyPrint(criteriaList); 39 | List students = studentRepository.findAll(criteriaList); 40 | PresentationUtil.prettyPrint(students); 41 | assertEquals(List.of(student3, student9), students); 42 | } 43 | 44 | /** 45 | * Inner join with multi joined entity criteria 46 | */ 47 | @Test 48 | public void innerJoin2() { 49 | var criteriaList = CriteriaList.of( 50 | Criteria.of("department.name", CriteriaOperator.START_WITH, "P"), 51 | Criteria.of("department.id", CriteriaOperator.GREATER_THAN, 3) 52 | ); 53 | PresentationUtil.prettyPrint(criteriaList); 54 | List students = studentRepository.findAll(criteriaList); 55 | PresentationUtil.prettyPrint(students); 56 | assertEquals(List.of( student9), students); 57 | } 58 | 59 | /** 60 | * Inner join with different entity criteria 61 | */ 62 | @Test 63 | public void innerJoin3() { 64 | var criteriaList = CriteriaList.of( 65 | Criteria.of("department.name", CriteriaOperator.START_WITH, "P"), 66 | Criteria.of("name", CriteriaOperator.START_WITH, "Robert") 67 | ); 68 | PresentationUtil.prettyPrint(criteriaList); 69 | List students = studentRepository.findAll(criteriaList); 70 | PresentationUtil.prettyPrint(students); 71 | assertEquals(List.of(student3), students); 72 | } 73 | 74 | /** 75 | * One to many inner join 76 | */ 77 | @Test 78 | public void innerJoin4() { 79 | var criteriaList = CriteriaList.of( 80 | Criteria.of("students.id", CriteriaOperator.GREATER_THAN, 3), 81 | Criteria.of("id", CriteriaOperator.LESS_THAN, 6) 82 | ); 83 | PresentationUtil.prettyPrint(criteriaList); 84 | List departments = departmentRepository.findAll(criteriaList); 85 | PresentationUtil.prettyPrint(departments); 86 | assertEquals(List.of(department4, department5), departments); 87 | } 88 | 89 | /** 90 | * Many to many inner join 91 | */ 92 | @Test 93 | public void innerJoin5() { 94 | var criteriaList = CriteriaList.of( 95 | Criteria.of("courses.maxStudentCount", CriteriaOperator.GREATER_THAN, 100), 96 | Criteria.of("id", CriteriaOperator.GREATER_THAN, 3) 97 | ); 98 | PresentationUtil.prettyPrint(criteriaList); 99 | List students = studentRepository.findAll(criteriaList); 100 | PresentationUtil.prettyPrint(students); 101 | assertEquals(List.of(student4, student5), students); 102 | } 103 | 104 | /** 105 | * Typical left join with is null check 106 | */ 107 | @Test 108 | public void leftJoin() { 109 | var criteriaList = CriteriaList.of( 110 | Criteria.of("department students = studentRepository.findAll(criteriaList); 115 | PresentationUtil.prettyPrint(students); 116 | assertEquals(List.of(student11), students); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S6_Advenced_Join.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.Criteria; 6 | import com.beyt.jdq.dto.CriteriaList; 7 | import com.beyt.jdq.dto.enums.CriteriaOperator; 8 | import com.beyt.jdq.testenv.entity.authorization.AdminUser; 9 | import com.beyt.jdq.testenv.repository.AdminUserRepository; 10 | import com.beyt.jdq.testenv.repository.DepartmentRepository; 11 | import com.beyt.jdq.util.PresentationUtil; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.TestInstance; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.test.annotation.DirtiesContext; 18 | 19 | import java.util.List; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | @SpringBootTest(classes = TestApplication.class) 25 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 26 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 27 | public class S6_Advenced_Join extends BaseTestInstance { 28 | private @Autowired AdminUserRepository adminUserRepository; 29 | private @Autowired DepartmentRepository departmentRepository; 30 | 31 | @Test 32 | public void roleJoin() { 33 | var criteriaList = CriteriaList.of(Criteria.of("roles.roleAuthorizations.authorization.menuIcon", CriteriaOperator.START_WITH, "icon")); 34 | PresentationUtil.prettyPrint(criteriaList); 35 | List adminUserList = adminUserRepository.findAll(criteriaList); 36 | PresentationUtil.prettyPrint(adminUserList);//1,2,3,4,5 37 | assertEquals(List.of(adminUser1, adminUser2, adminUser3, adminUser4, adminUser5), adminUserList); 38 | } 39 | 40 | @Test 41 | public void roleLeftJoin() { 42 | var criteriaList = CriteriaList.of(Criteria.of("roles adminUserList = adminUserRepository.findAll(criteriaList); 45 | PresentationUtil.prettyPrint(adminUserList); 46 | assertEquals(List.of(adminUser1, adminUser2, adminUser3, adminUser4, adminUser5), adminUserList); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/presetation/S9_Query_Builder.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.presetation; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.dto.enums.Order; 6 | import com.beyt.jdq.testenv.repository.AdminUserRepository; 7 | import com.beyt.jdq.util.PresentationUtil; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.TestInstance; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.data.domain.Page; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | 20 | import java.util.List; 21 | import java.util.Objects; 22 | 23 | import static com.beyt.jdq.query.builder.QuerySimplifier.*; 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | 26 | @SpringBootTest(classes = TestApplication.class) 27 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 28 | @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 29 | public class S9_Query_Builder extends BaseTestInstance { 30 | private @Autowired AdminUserRepository adminUserRepository; 31 | 32 | 33 | @NoArgsConstructor 34 | @AllArgsConstructor 35 | public static class AuthorizationSummary { 36 | @Getter 37 | @Setter 38 | private Long adminId; 39 | @Getter @Setter private String adminUsername; 40 | @Getter @Setter private Long roleId; 41 | @Getter @Setter private String roleName; 42 | @Getter @Setter private Long authorizationId; 43 | @Getter @Setter private String authorizationName; 44 | @Getter @Setter private String menuIcon; 45 | 46 | @Override 47 | public boolean equals(Object o) { 48 | if (this == o) return true; 49 | if (!(o instanceof AuthorizationSummary that)) return false; 50 | return Objects.equals(adminId, that.adminId) && Objects.equals(adminUsername, that.adminUsername) && Objects.equals(roleId, that.roleId) && Objects.equals(roleName, that.roleName) && Objects.equals(authorizationId, that.authorizationId) && Objects.equals(authorizationName, that.authorizationName) && Objects.equals(menuIcon, that.menuIcon); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return Objects.hash(adminId, adminUsername, roleId, roleName, authorizationId, authorizationName, menuIcon); 56 | } 57 | } 58 | @Test 59 | public void queryBuilder() { 60 | Page result = adminUserRepository.queryBuilder() 61 | .select(Select("id", "adminId"), 62 | Select("username", "adminUsername"), 63 | Select("roles.id", "roleId"), 64 | Select("roles.name", "roleName"), 65 | Select("roles.roleAuthorizations.authorization.id", "authorizationId"), 66 | Select("roles.roleAuthorizations.authorization.name", "authorizationName"), 67 | Select("roles.roleAuthorizations.authorization.menuIcon", "menuIcon")) 68 | .distinct(false) 69 | .where(Field("roles.roleAuthorizations.authorization.menuIcon").startWith("icon"), Parantesis(Field("id").eq(3), OR, Field("roles.id").eq(4), OR, Field("id").eq(5)), Parantesis(Field("id").eq(5), OR, Field("id").eq(4), OR, Field("roles.id").eq(3))) 70 | .orderBy(OrderBy("roles.id", Order.DESC)) 71 | .page(1, 2) 72 | .getResultAsPage(AuthorizationSummary.class); 73 | 74 | PresentationUtil.prettyPrint(result); 75 | 76 | 77 | assertEquals(List.of(new AuthorizationSummary(3L, "admin3", 3L, "role3", 3L, "auth3", "icon3")), result.getContent()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/query/DynamicSpecificationTest.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.query; 2 | 3 | import com.beyt.jdq.dto.enums.JoinType; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.data.util.Pair; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | 13 | class DynamicSpecificationTest { 14 | 15 | @Test 16 | void getFieldName() { 17 | Assertions.assertEquals("name", DynamicSpecification.getFieldName("asd.asdname")); 18 | } 19 | 20 | @Test 21 | void getFieldJoins() { 22 | List> fieldJoins = new ArrayList<>(); 23 | fieldJoins.add(Pair.of("asd2fg", JoinType.INNER)); 24 | fieldJoins.add(Pair.of("asdhj", JoinType.LEFT)); 25 | fieldJoins.add(Pair.of("asdasda", JoinType.RIGHT)); 26 | 27 | assertEquals(fieldJoins, DynamicSpecification.getFieldJoins("asd2fg.asdhjname")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/resolver/ArgumentResolversTests.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.resolver; 2 | 3 | import com.beyt.jdq.BaseTestInstance; 4 | import com.beyt.jdq.TestApplication; 5 | import com.beyt.jdq.TestUtil; 6 | import com.beyt.jdq.testenv.entity.Customer; 7 | import com.beyt.jdq.testenv.entity.User; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.TestInstance; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.http.MediaType; 15 | import org.springframework.test.web.servlet.MockMvc; 16 | import org.springframework.test.web.servlet.MvcResult; 17 | 18 | import java.util.List; 19 | 20 | import static com.beyt.jdq.TestUtil.toList; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 24 | 25 | @AutoConfigureMockMvc 26 | @SpringBootTest(classes = TestApplication.class) 27 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 28 | public class ArgumentResolversTests extends BaseTestInstance { 29 | 30 | @Autowired 31 | private MockMvc mockMvc; 32 | 33 | private static final String CUSTOMER_CRITERIA_API_URL = "/test-api/customer"; 34 | private static final String USER_CRITERIA_API_URL = "/test-api/user"; 35 | private static final String CUSTOMER_SEARCH_LIST_API_URL = "/test-api/customer/as-list"; 36 | private static final String CUSTOMER_SEARCH_PAGE_API_URL = "/test-api/customer/as-page"; 37 | private static final String USER_SEARCH_LIST_API_URL = "/test-api/user/as-list"; 38 | private static final String USER_SEARCH_PAGE_API_URL = "/test-api/user/as-page"; 39 | 40 | @Test 41 | public void argumentCriteriaListTests() throws Exception { 42 | /* CONTAIN 43 | DOES_NOT_CONTAIN 44 | END_WITH 45 | START_WITH 46 | SPECIFIED 47 | EQUAL 48 | NOT_EQUAL 49 | GREATER_THAN 50 | GREATER_THAN_OR_EQUAL 51 | LESS_THAN 52 | LESS_THAN_OR_EQUAL 53 | OR 54 | PARENTHES */ 55 | // toList(customer1, customer2, customer3, customer4, customer5, customer6, customer7, customer8) 56 | // toList(user1, user2, user3, user4, user5, user6, user7, user8) 57 | checkRequestSingleUserEntity(toList(user1), USER_CRITERIA_API_URL, 58 | "key0=id&operation0=EQUAL&values0=1", User[].class); 59 | checkRequestSingleUserEntity(toList(user1, user2, user3), USER_CRITERIA_API_URL, 60 | "key0=id&operation0=EQUAL&values0=1,2,3", User[].class); 61 | checkRequestSingleUserEntity(toList(user2, user4, user6, user7), USER_CRITERIA_API_URL, 62 | "key0=status&operation0=EQUAL&values0=ACTIVE", User[].class); 63 | checkRequestSingleUserEntity(toList(user1, user2, user3, user4, user5, user6, user7, user8), USER_CRITERIA_API_URL, 64 | "key0=status&operation0=EQUAL&values0=ACTIVE,PASSIVE", User[].class); 65 | checkRequestSingleUserEntity(toList(user2, user5, user6, user8), USER_CRITERIA_API_URL, 66 | "key0=type&operation0=EQUAL&values0=ADMIN", User[].class); 67 | checkRequestSingleUserEntity(toList(user2, user6), USER_CRITERIA_API_URL, 68 | "key0=type&operation0=EQUAL&values0=ADMIN&key1=status&operation1=EQUAL&values1=ACTIVE", User[].class); 69 | checkRequestSingleUserEntity(toList(user1, user2, user3, user4, user6, user7, user8), USER_CRITERIA_API_URL, 70 | "key0=id&operation0=NOT_EQUAL&values0=5", User[].class); 71 | checkRequestSingleUserEntity(toList(user5), USER_CRITERIA_API_URL, 72 | "key0=name&operation0=CONTAIN&values0=5", User[].class); 73 | checkRequestSingleUserEntity(toList(user1, user2, user3, user4, user6, user7, user8), USER_CRITERIA_API_URL, 74 | "key0=name&operation0=DOES_NOT_CONTAIN&values0=5", User[].class); 75 | checkRequestSingleUserEntity(toList(user5), USER_CRITERIA_API_URL, 76 | "key0=name&operation0=END_WITH&values0=5", User[].class); 77 | checkRequestSingleUserEntity(toList(user1, user2, user3, user4, user5, user6, user7, user8), USER_CRITERIA_API_URL, 78 | "key0=name&operation0=START_WITH&values0=Name", User[].class); 79 | checkRequestSingleUserEntity(toList(user2, user3, user4, user5, user6, user7, user8), USER_CRITERIA_API_URL, 80 | "key0=id&operation0=GREATER_THAN&values0=1", User[].class); 81 | checkRequestSingleUserEntity(toList(user5, user6, user7, user8), USER_CRITERIA_API_URL, 82 | "key0=id&operation0=GREATER_THAN_OR_EQUAL&values0=5", User[].class); 83 | checkRequestSingleUserEntity(toList(user1, user2), USER_CRITERIA_API_URL, 84 | "key0=id&operation0=LESS_THAN&values0=3", User[].class); 85 | checkRequestSingleUserEntity(toList(user1, user2, user3), USER_CRITERIA_API_URL, 86 | "key0=id&operation0=LESS_THAN_OR_EQUAL&values0=3", User[].class); 87 | checkRequestSingleUserEntity(toList(user1, user2), USER_CRITERIA_API_URL, 88 | "key0=id&operation0=EQUAL&values0=1" + 89 | "&key1=&operation1=OR&values1=" + 90 | "&key2=id&operation2=EQUAL&values2=2", User[].class); 91 | checkShouldNotBeFound(USER_CRITERIA_API_URL, 92 | "key0=id&operation0=EQUAL&values0=0"); 93 | 94 | // Join Tests 95 | checkRequestSingleUserEntity(toList(customer1, customer2, customer3, customer4, customer5, customer6, customer7, customer8), CUSTOMER_CRITERIA_API_URL, 96 | "key0=user.surname&operation0=CONTAIN&values0=Surname", Customer[].class); 97 | } 98 | 99 | 100 | @Test 101 | public void argumentSearchQueryTests() throws Exception { 102 | checkRequestSingleUserEntity(toList(User.builder().name(user7.getName()).surname(user7.getSurname()).birthdate(user7.getBirthdate()).build(), 103 | User.builder().name(user6.getName()).surname(user6.getSurname()).birthdate(user6.getBirthdate()).build()), USER_SEARCH_LIST_API_URL, 104 | "select0=name&select1=surname&select2=birthdate&" + 105 | "orderBy0=name&orderByDirection0=desc&" + 106 | "page=0&" + 107 | "pageSize=2&" + 108 | "key0=id&operation0=NOT_EQUAL&values0=8", User[].class); 109 | } 110 | 111 | private void checkRequestSingleUserEntity(List userList, String apiUrl, String filter, Class clazz) throws Exception { 112 | MvcResult mvcResult = mockMvc.perform(get(apiUrl + "?" + filter)) 113 | .andExpect(status().isOk()) 114 | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); 115 | 116 | assertEquals(userList, TestUtil.getResultListValue(mvcResult.getResponse().getContentAsString(), clazz)); 117 | } 118 | 119 | /** 120 | * Executes the search, and checks that the default entity is not returned. 121 | */ 122 | private void checkShouldNotBeFound(String apiUrl, String filter) throws Exception { 123 | mockMvc.perform(get(apiUrl + "?" + filter)) 124 | .andExpect(status().isOk()) 125 | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) 126 | .andExpect(jsonPath("$").isArray()) 127 | .andExpect(jsonPath("$").isEmpty()); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/config/DynamicSpecificationRepositoryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.config; 2 | 3 | import com.beyt.jdq.repository.DynamicSpecificationRepositoryFactoryBean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 6 | 7 | @Configuration 8 | @EnableJpaRepositories(repositoryFactoryBeanClass = DynamicSpecificationRepositoryFactoryBean.class, basePackages = "com.beyt.jdq.testenv.repository") 9 | public class DynamicSpecificationRepositoryConfiguration { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.controller; 2 | 3 | import com.beyt.jdq.dto.CriteriaList; 4 | import com.beyt.jdq.dto.DynamicQuery; 5 | import com.beyt.jdq.testenv.entity.Customer; 6 | import com.beyt.jdq.testenv.entity.User; 7 | import com.beyt.jdq.testenv.repository.CustomerRepository; 8 | import com.beyt.jdq.testenv.repository.UserRepository; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.data.domain.Page; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.util.List; 17 | 18 | @RestController 19 | @RequestMapping("/test-api") 20 | public class TestController { 21 | @Autowired 22 | private UserRepository userRepository; 23 | 24 | @Autowired 25 | private CustomerRepository customerRepository; 26 | 27 | 28 | @GetMapping("/user") 29 | public ResponseEntity> getUserWithCriteria(CriteriaList criteriaList) { 30 | List userList = userRepository.findAll(criteriaList); 31 | return ResponseEntity.ok().body(userList); 32 | } 33 | 34 | @GetMapping("/customer") 35 | public ResponseEntity> getCustomerWithCriteria(CriteriaList criteriaList) { 36 | List customerList = customerRepository.findAll(criteriaList); 37 | return ResponseEntity.ok().body(customerList); 38 | } 39 | 40 | @GetMapping("/user/as-page") 41 | public ResponseEntity> getUserWithSearchFilterAsPage(DynamicQuery dynamicQuery) { 42 | Page userList = userRepository.findAllAsPage(dynamicQuery); 43 | return ResponseEntity.ok().body(userList); 44 | } 45 | 46 | @GetMapping("/user/as-list") 47 | public ResponseEntity> getUserWithSearchFilterAsList(DynamicQuery dynamicQuery) { 48 | List userList = userRepository.findAll(dynamicQuery); 49 | return ResponseEntity.ok().body(userList); 50 | } 51 | 52 | @GetMapping("/customer/as-page") 53 | public ResponseEntity> getCustomerWithSearchFilterAsPage(DynamicQuery dynamicQuery) { 54 | Page customerList = customerRepository.findAllAsPage(dynamicQuery); 55 | return ResponseEntity.ok().body(customerList); 56 | } 57 | 58 | @GetMapping("/customer/as-list") 59 | public ResponseEntity> getCustomerWithSearchFilterAsList(DynamicQuery dynamicQuery) { 60 | List customerList = customerRepository.findAll(dynamicQuery); 61 | return ResponseEntity.ok().body(customerList); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/Customer.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import jakarta.persistence.*; 8 | import java.io.Serializable; 9 | import java.time.Instant; 10 | 11 | @Entity 12 | @Table(name = "customer") 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Customer implements Serializable { 17 | 18 | private static final long serialVersionUID = 1L; 19 | 20 | @Id 21 | @GeneratedValue(strategy = GenerationType.IDENTITY) 22 | private Long id; 23 | 24 | @Column(name = "name") 25 | private String name; 26 | 27 | @Column(name = "age") 28 | private Integer age; 29 | 30 | @Column(name = "birthdate") 31 | private Instant birthdate; 32 | 33 | @ManyToOne 34 | private User user; 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import jakarta.persistence.*; 9 | import java.io.Serializable; 10 | import java.time.Instant; 11 | 12 | @Entity 13 | @Table(name = "test_user") 14 | @Data 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @Builder 18 | public class User implements Serializable { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | private Long id; 25 | 26 | @Column(name = "name") 27 | private String name; 28 | 29 | @Column(name = "surname") 30 | private String surname; 31 | 32 | @Column(name = "age") 33 | private Integer age; 34 | 35 | @Column(name = "birthdate") 36 | private Instant birthdate; 37 | 38 | 39 | @Column(name = "status") 40 | @Enumerated(EnumType.STRING) 41 | private Status status; 42 | 43 | @Column(name = "type") 44 | @Enumerated(EnumType.ORDINAL) 45 | private Type type; 46 | 47 | public enum Status { 48 | ACTIVE, PASSIVE 49 | } 50 | 51 | public enum Type { 52 | ADMIN, USER 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/authorization/AdminUser.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.authorization; 2 | 3 | import jakarta.persistence.*; 4 | 5 | import lombok.*; 6 | import lombok.experimental.FieldNameConstants; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Set; 11 | 12 | @Getter 13 | @Setter 14 | @ToString 15 | @Entity 16 | @Table(name = "admin_user") 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @FieldNameConstants 20 | public class AdminUser { 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | private Long id; 24 | 25 | private String username; 26 | 27 | private String password; 28 | 29 | @ManyToMany(fetch = FetchType.EAGER) 30 | @JoinTable( 31 | name = "admin_user_role", 32 | joinColumns = @JoinColumn(name = "admin_user_id"), 33 | inverseJoinColumns = @JoinColumn(name = "role_id")) 34 | List roles; 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) return true; 39 | if (!(o instanceof AdminUser adminUser)) return false; 40 | return Objects.equals(id, adminUser.id) && Objects.equals(username, adminUser.username) && Objects.equals(password, adminUser.password); 41 | } 42 | 43 | @Override 44 | public int hashCode() { 45 | return Objects.hash(id, username, password); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/authorization/Authorization.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.authorization; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | import jakarta.persistence.GeneratedValue; 6 | import jakarta.persistence.GenerationType; 7 | 8 | import lombok.*; 9 | import lombok.experimental.FieldNameConstants; 10 | 11 | import java.util.Objects; 12 | import java.util.Set; 13 | 14 | @Getter 15 | @Setter 16 | @ToString 17 | @Entity 18 | @Table(name = "my_authorization") 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @FieldNameConstants 22 | public class Authorization { 23 | @Id 24 | @GeneratedValue(strategy = GenerationType.IDENTITY) 25 | private Long id; 26 | 27 | private String name; 28 | 29 | @Column(name = "menu_url") 30 | private String menuUrl; 31 | 32 | @Column(name = "menu_icon") 33 | private String menuIcon; 34 | 35 | public Authorization(Long id, String name, String menuUrl, String menuIcon) { 36 | this.id = id; 37 | this.name = name; 38 | this.menuUrl = menuUrl; 39 | this.menuIcon = menuIcon; 40 | } 41 | 42 | @JsonIgnore 43 | @ToString.Exclude 44 | @OneToMany(mappedBy = "authorization", fetch = FetchType.LAZY) 45 | Set roleAuthorizations; 46 | 47 | @Override 48 | public boolean equals(Object o) { 49 | if (this == o) return true; 50 | if (!(o instanceof Authorization that)) return false; 51 | return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(menuUrl, that.menuUrl) && Objects.equals(menuIcon, that.menuIcon); 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Objects.hash(id, name, menuUrl, menuIcon); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/authorization/Role.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.authorization; 2 | 3 | import jakarta.persistence.*; 4 | 5 | import lombok.*; 6 | import lombok.experimental.FieldNameConstants; 7 | 8 | import java.util.Objects; 9 | import java.util.Set; 10 | 11 | @Getter 12 | @Setter 13 | @ToString 14 | @Entity 15 | @Table(name = "role") 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @FieldNameConstants 19 | public class Role { 20 | @Id 21 | @GeneratedValue(strategy = GenerationType.IDENTITY) 22 | private Long id; 23 | 24 | private String name; 25 | 26 | private String description; 27 | 28 | public Role(Long id, String name, String description) { 29 | this.id = id; 30 | this.name = name; 31 | this.description = description; 32 | } 33 | 34 | @OneToMany(mappedBy = "role", fetch = FetchType.EAGER) 35 | Set roleAuthorizations; 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) return true; 40 | if (!(o instanceof Role role)) return false; 41 | return Objects.equals(id, role.id) && Objects.equals(name, role.name) && Objects.equals(description, role.description); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return Objects.hash(id, name, description); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/authorization/RoleAuthorization.java: -------------------------------------------------------------------------------- 1 | // RoleAuthorization.java 2 | package com.beyt.jdq.testenv.entity.authorization; 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import jakarta.persistence.*; 6 | 7 | import lombok.*; 8 | import lombok.experimental.FieldNameConstants; 9 | import org.hibernate.annotations.Fetch; 10 | import org.hibernate.annotations.FetchMode; 11 | 12 | import java.util.Objects; 13 | 14 | @Getter 15 | @Setter 16 | @ToString 17 | @Entity 18 | @Table(name = "role_authorization") 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @FieldNameConstants 22 | public class RoleAuthorization { 23 | @Id 24 | @GeneratedValue(strategy = GenerationType.IDENTITY) 25 | private Long id; 26 | 27 | @ToString.Exclude 28 | @JsonIgnore 29 | @ManyToOne 30 | @JoinColumn(name = "role_id") 31 | private Role role; 32 | 33 | @ManyToOne 34 | @Fetch(FetchMode.SELECT) 35 | @JoinColumn(name = "authorization_id") 36 | private Authorization authorization; 37 | 38 | @Override 39 | public boolean equals(Object o) { 40 | if (this == o) return true; 41 | if (!(o instanceof RoleAuthorization that)) return false; 42 | return Objects.equals(id, that.id); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | return Objects.hashCode(id); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/school/Address.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.school; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | import lombok.experimental.FieldNameConstants; 10 | 11 | import java.util.Objects; 12 | 13 | @ToString 14 | @Getter 15 | @Setter 16 | @Entity 17 | @Table(name = "address") 18 | @NoArgsConstructor 19 | @FieldNameConstants 20 | public class Address { 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | private Long id; 24 | 25 | private String street; 26 | private String city; 27 | private String state; 28 | private String zip; 29 | 30 | public Address(Long id, String street, String city, String state, String zip) { 31 | this.id = id; 32 | this.street = street; 33 | this.city = city; 34 | this.state = state; 35 | this.zip = zip; 36 | } 37 | 38 | @ToString.Exclude 39 | @JsonIgnore 40 | @OneToOne(mappedBy = "address", fetch = FetchType.LAZY) 41 | private Student student; 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (!(o instanceof Address address)) return false; 47 | return Objects.equals(id, address.id) && Objects.equals(street, address.street) && Objects.equals(city, address.city) && Objects.equals(state, address.state) && Objects.equals(zip, address.zip); 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return Objects.hash(id, street, city, state, zip); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/school/Course.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.school; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | 6 | import lombok.*; 7 | import lombok.experimental.FieldNameConstants; 8 | 9 | import java.sql.Timestamp; 10 | import java.util.Objects; 11 | import java.util.Set; 12 | 13 | @ToString 14 | @Getter 15 | @Setter 16 | @Entity 17 | @Table(name = "course") 18 | @NoArgsConstructor 19 | @FieldNameConstants 20 | public class Course { 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | private Long id; 24 | 25 | private String name; 26 | 27 | private Timestamp startDate; 28 | 29 | private Integer maxStudentCount; 30 | 31 | private Boolean active; 32 | 33 | private String description; 34 | 35 | public Course(Long id, String name, Timestamp startDate, Integer maxStudentCount, Boolean active, String description) { 36 | this.id = id; 37 | this.name = name; 38 | this.startDate = startDate; 39 | this.maxStudentCount = maxStudentCount; 40 | this.active = active; 41 | this.description = description; 42 | } 43 | 44 | public static Course of(String name, String description) { 45 | return new Course(null, name, null, null, null, description); 46 | } 47 | 48 | @JsonIgnore 49 | @ToString.Exclude 50 | @ManyToMany(mappedBy = "courses", fetch = FetchType.LAZY) 51 | private Set students; 52 | 53 | @Override 54 | public boolean equals(Object o) { 55 | if (this == o) return true; 56 | if (!(o instanceof Course course)) return false; 57 | return Objects.equals(id, course.id) && Objects.equals(name, course.name) && Objects.equals(startDate, course.startDate) && Objects.equals(maxStudentCount, course.maxStudentCount) && Objects.equals(active, course.active) && Objects.equals(description, course.description); 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return Objects.hash(id, name, startDate, maxStudentCount, active, description); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/school/Department.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.school; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | 6 | import lombok.*; 7 | import lombok.experimental.FieldNameConstants; 8 | 9 | import java.util.Objects; 10 | import java.util.Set; 11 | 12 | @ToString 13 | @Getter 14 | @Setter 15 | @Entity 16 | @Table(name = "department") 17 | @NoArgsConstructor 18 | @FieldNameConstants 19 | public class Department { 20 | @Id 21 | @GeneratedValue(strategy = GenerationType.IDENTITY) 22 | private Long id; 23 | 24 | private String name; 25 | 26 | public Department(Long id, String name) { 27 | this.id = id; 28 | this.name = name; 29 | } 30 | 31 | @JsonIgnore 32 | @ToString.Exclude 33 | @OneToMany(mappedBy="department", fetch = FetchType.EAGER) 34 | private Set students; 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) return true; 39 | if (!(o instanceof Department that)) return false; 40 | return Objects.equals(id, that.id) && Objects.equals(name, that.name); 41 | } 42 | 43 | @Override 44 | public int hashCode() { 45 | return Objects.hash(id, name); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/entity/school/Student.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.entity.school; 2 | 3 | import jakarta.persistence.*; 4 | 5 | import lombok.*; 6 | import lombok.experimental.FieldNameConstants; 7 | import org.hibernate.annotations.Fetch; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.Set; 12 | 13 | @ToString 14 | @Getter 15 | @Setter 16 | @Entity 17 | @Table(name = "student") 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @FieldNameConstants 21 | public class Student { 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | private Long id; 25 | 26 | private String name; 27 | 28 | public Student(Long id, String name) { 29 | this.id = id; 30 | this.name = name; 31 | } 32 | 33 | @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 34 | @JoinColumn(name = "address_id", referencedColumnName = "id") 35 | private Address address; 36 | 37 | @ManyToOne(fetch = FetchType.EAGER) 38 | @JoinColumn(name="department_id", nullable=true) 39 | private Department department; 40 | 41 | @ManyToMany(fetch = FetchType.EAGER) 42 | @Fetch(org.hibernate.annotations.FetchMode.SUBSELECT) 43 | @JoinTable( 44 | name = "StudentCourse", 45 | joinColumns = @JoinColumn(name = "student_id"), 46 | inverseJoinColumns = @JoinColumn(name = "course_id")) 47 | List courses; 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (!(o instanceof Student student)) return false; 53 | return Objects.equals(id, student.id) && Objects.equals(name, student.name); 54 | } 55 | public static Student of(String name) { 56 | Student student = new Student(); 57 | student.setName(name); 58 | return student; 59 | } 60 | @Override 61 | public int hashCode() { 62 | return Objects.hash(id, name); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/AddressRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.school.Address; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface AddressRepository extends JpaRepository, JpaDynamicQueryRepository { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/AdminUserRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.authorization.AdminUser; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface AdminUserRepository extends JpaRepository, JpaDynamicQueryRepository {} 8 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/AuthorizationRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.authorization.Authorization; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface AuthorizationRepository extends JpaRepository, JpaDynamicQueryRepository {} 8 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/CourseRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.school.Course; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface CourseRepository extends JpaDynamicQueryRepository { 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.Customer; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface CustomerRepository extends JpaDynamicQueryRepository { 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/DepartmentRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.school.Department; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface DepartmentRepository extends JpaRepository, JpaDynamicQueryRepository { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/RoleAuthorizationRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.authorization.RoleAuthorization; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface RoleAuthorizationRepository extends JpaRepository, JpaDynamicQueryRepository {} 8 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.authorization.Role; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface RoleRepository extends JpaRepository, JpaDynamicQueryRepository {} 8 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/StudentRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.JpaDynamicQueryRepository; 4 | import com.beyt.jdq.testenv.entity.school.Student; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface StudentRepository extends JpaRepository, JpaDynamicQueryRepository { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository; 2 | 3 | import com.beyt.jdq.repository.DynamicSpecificationRepository; 4 | import com.beyt.jdq.testenv.entity.User; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface UserRepository extends DynamicSpecificationRepository { 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/testenv/repository/field/FieldUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.testenv.repository.field; 2 | 3 | import com.beyt.jdq.util.field.FieldUtil; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.time.Instant; 9 | import java.time.ZoneId; 10 | import java.time.ZonedDateTime; 11 | import java.sql.Timestamp; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | 16 | class FieldUtilTest { 17 | 18 | @Test 19 | void fillValue() throws ParseException { 20 | long currentTimeMillis = System.currentTimeMillis(); 21 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(); 22 | Instant instant = Instant.ofEpochMilli(currentTimeMillis); 23 | 24 | 25 | assertEquals(TimeUnit.NANOSECONDS, FieldUtil.fillValue(TimeUnit.class, "NANOSECONDS")); 26 | assertEquals("NANOSECONDS", FieldUtil.fillValue(String.class, "NANOSECONDS")); 27 | assertEquals(Long.parseLong("155"), FieldUtil.fillValue(Long.class, "155")); 28 | assertEquals(Double.parseDouble("155"), FieldUtil.fillValue(Double.class, "155")); 29 | assertEquals(Integer.parseInt("155"), FieldUtil.fillValue(Integer.class, "155")); 30 | assertEquals(Boolean.TRUE, FieldUtil.fillValue(Boolean.class, "True")); 31 | assertEquals(simpleDateFormat.format(new Timestamp(currentTimeMillis)), simpleDateFormat.format(FieldUtil.fillValue(Timestamp.class, simpleDateFormat.format(new Timestamp(currentTimeMillis))))); 32 | assertEquals(ZonedDateTime.ofInstant(instant, ZoneId.systemDefault()), FieldUtil.fillValue(ZonedDateTime.class, ZonedDateTime.ofInstant(instant, ZoneId.systemDefault()).toString())); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/beyt/jdq/util/PresentationUtil.java: -------------------------------------------------------------------------------- 1 | package com.beyt.jdq.util; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import lombok.SneakyThrows; 5 | 6 | public class PresentationUtil { 7 | 8 | @SneakyThrows 9 | public static void prettyPrint(Object object) { 10 | var objectMapper = new ObjectMapper(); 11 | System.out.println("______________________________________________________________________________"); 12 | System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object)); 13 | System.out.println("========================================================================"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | sql: 3 | # init: 4 | # data-locations: classpath:data.sql 5 | # mode: always 6 | # schema-locations: classpath:init.sql 7 | application: 8 | name: test-app 9 | datasource: 10 | url: jdbc:h2:mem:test-app;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false 11 | name: 12 | username: 13 | password: 14 | hikari: 15 | auto-commit: false 16 | jackson: 17 | serialization: 18 | write-durations-as-timestamps: false 19 | jpa: 20 | defer-datasource-initialization: true 21 | database-platform: org.hibernate.dialect.H2Dialect 22 | open-in-view: false 23 | show-sql: true 24 | hibernate: 25 | ddl-auto: create-drop 26 | naming: 27 | physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy 28 | implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy 29 | properties: 30 | hibernate.id.new_generator_mappings: true 31 | hibernate.connection.provider_disables_autocommit: true 32 | hibernate.cache.use_second_level_cache: false 33 | hibernate.cache.use_query_cache: false 34 | hibernate.generate_statistics: false 35 | hibernate.jdbc.time_zone: UTC 36 | main: 37 | allow-bean-definition-overriding: true 38 | 39 | 40 | server: 41 | port: 10344 42 | address: localhost 43 | -------------------------------------------------------------------------------- /src/test/resources/config/data.sql: -------------------------------------------------------------------------------- 1 | -- Insert queries for Address 2 | INSERT INTO address (id, street, city, state, zip) VALUES (1, '123 Main St', 'New York', 'NY', '10001'); 3 | INSERT INTO address (id, street, city, state, zip) VALUES (2, '456 Park Ave', 'Chicago', 'IL', '60605'); 4 | INSERT INTO address (id, street, city, state, zip) VALUES (3, '789 Broadway', 'Los Angeles', 'CA', '90001'); 5 | INSERT INTO address (id, street, city, state, zip) VALUES (4, '321 Market St', 'San Francisco', 'CA', '94105'); 6 | INSERT INTO address (id, street, city, state, zip) VALUES (5, '654 Elm St', 'Dallas', 'TX', '75001'); 7 | INSERT INTO address (id, street, city, state, zip) VALUES (6, '987 Oak St', 'Houston', 'TX', '77002'); 8 | INSERT INTO address (id, street, city, state, zip) VALUES (7, '345 Pine St', 'Philadelphia', 'PA', '19019'); 9 | INSERT INTO address (id, street, city, state, zip) VALUES (8, '678 Maple St', 'Phoenix', 'AZ', '85001'); 10 | INSERT INTO address (id, street, city, state, zip) VALUES (9, '102 Beach St', 'Miami', 'FL', '33101'); 11 | INSERT INTO address (id, street, city, state, zip) VALUES (10, '567 Hill St', 'Atlanta', 'GA', '30301'); 12 | -- ... repeat for 8 more addresses 13 | 14 | -- Insert queries for Department 15 | INSERT INTO department (id, name) VALUES (1, 'Computer Science'); 16 | INSERT INTO department (id, name) VALUES (2, 'Mathematics'); 17 | INSERT INTO department (id, name) VALUES (3, 'Physics'); 18 | INSERT INTO department (id, name) VALUES (4, 'Chemistry'); 19 | INSERT INTO department (id, name) VALUES (5, 'Biology'); 20 | INSERT INTO department (id, name) VALUES (6, 'English Literature'); 21 | INSERT INTO department (id, name) VALUES (7, 'History'); 22 | INSERT INTO department (id, name) VALUES (8, 'Geography'); 23 | INSERT INTO department (id, name) VALUES (9, 'Political Science'); 24 | INSERT INTO department (id, name) VALUES (10, 'Economics'); 25 | -- ... repeat for 8 more departments 26 | 27 | -- Insert queries for Course 28 | INSERT INTO course (id, name, start_date, max_student_count, active, description) 29 | VALUES 30 | (1, 'Introduction to Computer Science', '2016-06-18', 50, 1, 'Introduction to fundamental concepts of computer science.'), 31 | (2, 'Calculus I', '2017-06-18', 60, 1, 'Introduction to fundamental concepts of calculus.'), 32 | (3, 'Calculus II', '2018-06-18', 250, null, 'Advanced topics in calculus including integrals and series.'), 33 | (4, 'Physics I', '2019-06-18', 250, null, 'Introduction to classical mechanics and Newtonian physics.'), 34 | (5, 'Physics II', '2020-06-18', 250, null, 'Advanced topics in physics including electromagnetism and thermodynamics.'), 35 | (6, 'Chemistry I', '2021-06-18', 40, null, 'Basic principles of chemistry including atomic structure and chemical bonding.'), 36 | (7, 'Chemistry II', '2022-06-18', 30, null, 'Continuation of chemistry studies covering topics like kinetics and equilibrium.'), 37 | (8, 'Biology I', '2015-06-18', 20, 1, 'Introduction to cellular biology and genetics.'), 38 | (9, 'Biology II', '2013-06-18', 54, 1, 'Advanced topics in biology including evolution and ecology.'), 39 | (10, 'English Literature I', '2025-06-18', 10, 0, 'Exploration of classic works of English literature and literary analysis.'); 40 | 41 | -- ... repeat for 8 more courses 42 | 43 | -- Insert queries for Student 44 | INSERT INTO student (id, name, address_id, department_id) VALUES (1, 'John Doe', 1, 1); 45 | INSERT INTO student (id, name, address_id, department_id) VALUES (2, 'Jane Smith', 2, 2); 46 | INSERT INTO student (id, name, address_id, department_id) VALUES (3, 'Robert Johnson', 3, 3); 47 | INSERT INTO student (id, name, address_id, department_id) VALUES (4, 'Emily Davis', 4, 4); 48 | INSERT INTO student (id, name, address_id, department_id) VALUES (5, 'Michael Miller', 5, 5); 49 | INSERT INTO student (id, name, address_id, department_id) VALUES (6, 'Sarah Wilson', 6, 6); 50 | INSERT INTO student (id, name, address_id, department_id) VALUES (7, 'David Moore', 7, 7); 51 | INSERT INTO student (id, name, address_id, department_id) VALUES (8, 'Jessica Taylor', 8, 8); 52 | INSERT INTO student (id, name, address_id, department_id) VALUES (9, 'Daniel Anderson', 9, 9); 53 | INSERT INTO student (id, name, address_id, department_id) VALUES (10, 'Jennifer Thomas', 10, 10); 54 | INSERT INTO student (id, name, address_id, department_id) VALUES (11, 'Talha Dilber', null, null); 55 | -- ... repeat for 8 more students 56 | 57 | -- Insert queries for Student_Course 58 | INSERT INTO student_course (student_id, course_id) VALUES (1, 1); 59 | INSERT INTO student_course (student_id, course_id) VALUES (1, 2); 60 | INSERT INTO student_course (student_id, course_id) VALUES (2, 2); 61 | INSERT INTO student_course (student_id, course_id) VALUES (2, 4); 62 | INSERT INTO student_course (student_id, course_id) VALUES (3, 3); 63 | INSERT INTO student_course (student_id, course_id) VALUES (4, 4); 64 | INSERT INTO student_course (student_id, course_id) VALUES (5, 5); 65 | INSERT INTO student_course (student_id, course_id) VALUES (6, 6); 66 | INSERT INTO student_course (student_id, course_id) VALUES (7, 7); 67 | INSERT INTO student_course (student_id, course_id) VALUES (8, 8); 68 | INSERT INTO student_course (student_id, course_id) VALUES (9, 9); 69 | INSERT INTO student_course (student_id, course_id) VALUES (10, 10); 70 | -- ... repeat for 8 more student-course relationships 71 | 72 | -- data.sql 73 | -- Insert queries for AdminUser 74 | INSERT INTO admin_user (id, username, password) VALUES (1, 'admin1', 'password1'); 75 | INSERT INTO admin_user (id, username, password) VALUES (2, 'admin2', 'password2'); 76 | INSERT INTO admin_user (id, username, password) VALUES (3, 'admin3', 'password3'); 77 | INSERT INTO admin_user (id, username, password) VALUES (4, 'admin4', 'password4'); 78 | INSERT INTO admin_user (id, username, password) VALUES (5, 'admin5', 'password5'); 79 | -- ... repeat for 9 more admin users 80 | 81 | -- Insert queries for Role 82 | INSERT INTO role (id, name, description) VALUES (1, 'role1', 'description1'); 83 | INSERT INTO role (id, name, description) VALUES (2, 'role2', 'description2'); 84 | INSERT INTO role (id, name, description) VALUES (3, 'role3', 'description3'); 85 | INSERT INTO role (id, name, description) VALUES (4, 'role4', 'description4'); 86 | INSERT INTO role (id, name, description) VALUES (5, 'role5', 'description5'); 87 | 88 | -- ... repeat for 9 more roles 89 | 90 | -- Insert queries for Authorization 91 | INSERT INTO my_authorization (id, name, menu_url, menu_icon) VALUES (1, 'auth1', '/url1', 'icon1'); 92 | INSERT INTO my_authorization (id, name, menu_url, menu_icon) VALUES (2, 'auth2', '/url2', 'icon2'); 93 | INSERT INTO my_authorization (id, name, menu_url, menu_icon) VALUES (3, 'auth3', '/url3', 'icon3'); 94 | INSERT INTO my_authorization (id, name, menu_url, menu_icon) VALUES (4, 'auth4', '/url4', 'icon4'); 95 | INSERT INTO my_authorization (id, name, menu_url, menu_icon) VALUES (5, 'auth5', '/url5', 'icon5'); 96 | -- ... repeat for 9 more authorizations 97 | 98 | -- Insert queries for AdminUserRole 99 | INSERT INTO admin_user_role (admin_user_id, role_id) VALUES (1, 1); 100 | INSERT INTO admin_user_role (admin_user_id, role_id) VALUES (2, 2); 101 | INSERT INTO admin_user_role (admin_user_id, role_id) VALUES (3, 3); 102 | INSERT INTO admin_user_role (admin_user_id, role_id) VALUES (4, 4); 103 | INSERT INTO admin_user_role (admin_user_id, role_id) VALUES (5, 5); 104 | -- ... repeat for 9 more admin user-role relationships 105 | 106 | -- Insert queries for RoleAuthorization 107 | INSERT INTO role_authorization (id, role_id, authorization_id) VALUES (1, 1, 1); 108 | INSERT INTO role_authorization (id, role_id, authorization_id) VALUES (2, 2, 2); 109 | INSERT INTO role_authorization (id, role_id, authorization_id) VALUES (3, 3, 3); 110 | INSERT INTO role_authorization (id, role_id, authorization_id) VALUES (4, 4, 4); 111 | INSERT INTO role_authorization (id, role_id, authorization_id) VALUES (5, 5, 5); 112 | -------------------------------------------------------------------------------- /src/test/resources/config/init.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE address ( 2 | id INT PRIMARY KEY, 3 | street VARCHAR(255), 4 | city VARCHAR(255), 5 | state VARCHAR(2), 6 | zip VARCHAR(5) 7 | ); 8 | 9 | CREATE TABLE department ( 10 | id INT PRIMARY KEY, 11 | name VARCHAR(255) 12 | ); 13 | 14 | CREATE TABLE course ( 15 | id INT PRIMARY KEY, 16 | name VARCHAR(255), 17 | start_date DATETIME, 18 | max_student_count INT, 19 | active BIT, 20 | description VARCHAR(255) 21 | ); 22 | 23 | CREATE TABLE student ( 24 | id INT PRIMARY KEY, 25 | name VARCHAR(255), 26 | address_id INT, 27 | department_id INT, 28 | FOREIGN KEY (address_id) REFERENCES address(id), 29 | FOREIGN KEY (department_id) REFERENCES department(id) 30 | ); 31 | 32 | CREATE TABLE student_course ( 33 | student_id INT, 34 | course_id INT, 35 | PRIMARY KEY (student_id, course_id), 36 | FOREIGN KEY (student_id) REFERENCES student(id), 37 | FOREIGN KEY (course_id) REFERENCES course(id) 38 | ); 39 | 40 | CREATE TABLE admin_user ( 41 | id INT PRIMARY KEY, 42 | username VARCHAR(255), 43 | password VARCHAR(255) 44 | ); 45 | 46 | CREATE TABLE role ( 47 | id INT PRIMARY KEY, 48 | name VARCHAR(255), 49 | description VARCHAR(255) 50 | ); 51 | 52 | CREATE TABLE my_authorization ( 53 | id INT PRIMARY KEY, 54 | name VARCHAR(255), 55 | menu_url VARCHAR(255), 56 | menu_icon VARCHAR(255) 57 | ); 58 | 59 | CREATE TABLE admin_user_role ( 60 | admin_user_id INT, 61 | role_id INT, 62 | PRIMARY KEY (admin_user_id, role_id), 63 | FOREIGN KEY (admin_user_id) REFERENCES admin_user(id), 64 | FOREIGN KEY (role_id) REFERENCES role(id) 65 | ); 66 | 67 | CREATE TABLE role_authorization ( 68 | id INT PRIMARY KEY, 69 | role_id INT, 70 | authorization_id INT, 71 | FOREIGN KEY (role_id) REFERENCES role(id), 72 | FOREIGN KEY (authorization_id) REFERENCES my_authorization(id) 73 | ); 74 | --------------------------------------------------------------------------------