├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── codecov.yml ├── query-builder-core ├── src │ ├── main │ │ └── java │ │ │ └── com.reinaldoarrosi.android.querybuilder │ │ │ ├── sqlite │ │ │ ├── from │ │ │ │ ├── AliasableFrom.java │ │ │ │ ├── TableFrom.java │ │ │ │ ├── SubQueryFrom.java │ │ │ │ ├── From.java │ │ │ │ └── JoinFrom.java │ │ │ ├── criteria │ │ │ │ ├── NotExistsCriteria.java │ │ │ │ ├── ExistsCriteria.java │ │ │ │ ├── OrCriteria.java │ │ │ │ ├── AndCriteria.java │ │ │ │ ├── BetweenCriteria.java │ │ │ │ ├── ValueBetweenCriteria.java │ │ │ │ ├── InCriteria.java │ │ │ │ ├── NotInCriteria.java │ │ │ │ ├── BasicCriteria.java │ │ │ │ └── Criteria.java │ │ │ ├── projection │ │ │ │ ├── CastDateProjection.java │ │ │ │ ├── CastIntProjection.java │ │ │ │ ├── CastRealProjection.java │ │ │ │ ├── CastDateTimeProjection.java │ │ │ │ ├── CastStringProjection.java │ │ │ │ ├── ColumnProjection.java │ │ │ │ ├── SubQueryProjection.java │ │ │ │ ├── ConstantProjection.java │ │ │ │ ├── AggregateProjection.java │ │ │ │ ├── AliasedProjection.java │ │ │ │ └── Projection.java │ │ │ ├── order │ │ │ │ ├── OrderAscending.java │ │ │ │ ├── OrderDescending.java │ │ │ │ ├── OrderAscendingIgnoreCase.java │ │ │ │ ├── OrderDescendingIgnoreCase.java │ │ │ │ └── Order.java │ │ │ ├── QueryBuildConfiguration.java │ │ │ └── QueryBuilder.java │ │ │ └── Utils.java │ └── test │ │ └── java │ │ └── com │ │ └── reinaldoarrosi │ │ └── android │ │ └── querybuilder │ │ └── UtilsTest.java ├── .gitignore └── build.gradle ├── .travis.yml ├── .gitignore ├── LICENSE.md ├── gradlew.bat ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':query-builder-core' -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reinaldoarrosi/QueryBuilder/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | fixes: 2 | - "com/reinaldoarrosi/android/querybuilder::query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder" 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/from/AliasableFrom.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.from; 2 | 3 | public abstract class AliasableFrom extends From { 4 | protected String alias; 5 | 6 | @SuppressWarnings("unchecked") 7 | public T as(String alias) { 8 | this.alias = alias; 9 | return (T)this; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: oraclejdk7 3 | 4 | script: 5 | - ./gradlew build jacocoTestReport 6 | 7 | after_success: 8 | - bash <(curl -s https://codecov.io/bash) 9 | 10 | notifications: 11 | email: 12 | recipients: 13 | - skrzynecki.krzysztof@gmail.com 14 | on_success: never 15 | on_failure: always 16 | 17 | cache: 18 | directories: 19 | - $HOME/.m2 20 | - $HOME/.gradle -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/NotExistsCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 4 | 5 | public class NotExistsCriteria extends ExistsCriteria { 6 | public NotExistsCriteria(QueryBuilder subQuery) { 7 | super(subQuery); 8 | } 9 | 10 | @Override 11 | public String build() { 12 | return "NOT " + super.build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pydevproject 2 | .project 3 | .metadata 4 | .settings 5 | **/bin/** 6 | **/tmp/** 7 | **/tmp/**/* 8 | *.tmp 9 | *.bak 10 | *.swp 11 | *~.nib 12 | local.properties 13 | .loadpath 14 | 15 | # External tool builders 16 | .externalToolBuilders/ 17 | 18 | # Locally stored "Eclipse launch configurations" 19 | *.launch 20 | 21 | # CDT-specific 22 | .cproject 23 | 24 | # PDT-specific 25 | .buildpath 26 | 27 | # built application files 28 | *.apk 29 | *.ap_ 30 | 31 | # files for the dex VM 32 | *.dex 33 | 34 | # Java class files 35 | *.class 36 | 37 | # generated files 38 | **/gen/** 39 | 40 | # Proguard folder generated by Eclipse 41 | proguard/ 42 | 43 | # Intellij project files 44 | *.iml 45 | *.ipr 46 | *.iws 47 | .idea/ 48 | 49 | # Gradle 50 | /build 51 | /.gradle -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/from/TableFrom.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.from; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | 8 | public class TableFrom extends AliasableFrom { 9 | private String table; 10 | 11 | public TableFrom(String table) { 12 | this.table = table; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | String ret = (!Utils.isNullOrWhiteSpace(table) ? table : ""); 18 | 19 | if(!Utils.isNullOrWhiteSpace(alias)) 20 | ret = ret + " AS " + alias; 21 | 22 | return ret; 23 | } 24 | 25 | @Override 26 | public List buildParameters() { 27 | return Utils.EMPTY_LIST; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /query-builder-core/.gitignore: -------------------------------------------------------------------------------- 1 | *.pydevproject 2 | .project 3 | .metadata 4 | .settings 5 | **/bin/** 6 | **/tmp/** 7 | **/tmp/**/* 8 | *.tmp 9 | *.bak 10 | *.swp 11 | *~.nib 12 | local.properties 13 | .loadpath 14 | 15 | # External tool builders 16 | .externalToolBuilders/ 17 | 18 | # Locally stored "Eclipse launch configurations" 19 | *.launch 20 | 21 | # CDT-specific 22 | .cproject 23 | 24 | # PDT-specific 25 | .buildpath 26 | 27 | # built application files 28 | *.apk 29 | *.ap_ 30 | 31 | # files for the dex VM 32 | *.dex 33 | 34 | # Java class files 35 | *.class 36 | 37 | # generated files 38 | **/gen/** 39 | 40 | # Proguard folder generated by Eclipse 41 | proguard/ 42 | 43 | # Intellij project files 44 | *.iml 45 | *.ipr 46 | *.iws 47 | .idea/ 48 | 49 | # Gradle build folder 50 | /build -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/CastDateProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class CastDateProjection extends Projection { 8 | private Projection projection; 9 | 10 | public CastDateProjection(Projection projection) { 11 | this.projection = projection; 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = (projection != null ? projection.build() : ""); 17 | return "DATE(" + ret + ")"; 18 | } 19 | 20 | @Override 21 | public List buildParameters() { 22 | if(projection != null) 23 | return projection.buildParameters(); 24 | else 25 | return Utils.EMPTY_LIST; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/CastIntProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class CastIntProjection extends Projection { 8 | private Projection projection; 9 | 10 | public CastIntProjection(Projection projection) { 11 | this.projection = projection; 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = (projection != null ? projection.build() : ""); 17 | return "CAST(" + ret + " AS INTEGER)"; 18 | } 19 | 20 | @Override 21 | public List buildParameters() { 22 | if (projection != null) 23 | return projection.buildParameters(); 24 | else 25 | return Utils.EMPTY_LIST; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/CastRealProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class CastRealProjection extends Projection { 8 | private Projection projection; 9 | 10 | public CastRealProjection(Projection projection) { 11 | this.projection = projection; 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = (projection != null ? projection.build() : ""); 17 | return "CAST(" + ret + " AS REAL)"; 18 | } 19 | 20 | @Override 21 | public List buildParameters() { 22 | if (projection != null) 23 | return projection.buildParameters(); 24 | else 25 | return Utils.EMPTY_LIST; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/CastDateTimeProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class CastDateTimeProjection extends Projection { 8 | private Projection projection; 9 | 10 | public CastDateTimeProjection(Projection projection) { 11 | this.projection = projection; 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = (projection != null ? projection.build() : ""); 17 | return "DATETIME(" + ret + ")"; 18 | } 19 | 20 | @Override 21 | public List buildParameters() { 22 | if (projection != null) 23 | return projection.buildParameters(); 24 | else 25 | return Utils.EMPTY_LIST; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/CastStringProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class CastStringProjection extends Projection { 8 | private Projection projection; 9 | 10 | public CastStringProjection(Projection projection) { 11 | this.projection = projection; 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = (projection != null ? projection.build() : ""); 17 | return "CAST(" + ret + " AS TEXT)"; 18 | } 19 | 20 | @Override 21 | public List buildParameters() { 22 | if (projection != null) 23 | return projection.buildParameters(); 24 | else 25 | return Utils.EMPTY_LIST; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/order/OrderAscending.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.order; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 7 | 8 | public class OrderAscending extends Order { 9 | 10 | public OrderAscending(Projection projection) { 11 | super(projection); 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = " ASC"; 17 | 18 | if(projection != null) 19 | ret = projection.build() + ret; 20 | 21 | return ret; 22 | } 23 | 24 | @Override 25 | public List buildParameters() { 26 | if(projection != null) 27 | return projection.buildParameters(); 28 | else 29 | return Utils.EMPTY_LIST; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/order/OrderDescending.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.order; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 7 | 8 | public class OrderDescending extends Order { 9 | 10 | public OrderDescending(Projection projection) { 11 | super(projection); 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = " DESC"; 17 | 18 | if(projection != null) 19 | ret = projection.build() + ret; 20 | 21 | return ret; 22 | } 23 | 24 | @Override 25 | public List buildParameters() { 26 | if(projection != null) 27 | return projection.buildParameters(); 28 | else 29 | return Utils.EMPTY_LIST; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /query-builder-core/src/test/java/com/reinaldoarrosi/android/querybuilder/UtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class UtilsTest { 8 | @Test 9 | public void isNullOrWhiteSpace() throws Exception { 10 | assertTrue(Utils.isNullOrWhiteSpace(null)); 11 | 12 | assertTrue(Utils.isNullOrWhiteSpace("")); 13 | 14 | assertTrue(Utils.isNullOrWhiteSpace(" ")); 15 | 16 | assertFalse(Utils.isNullOrWhiteSpace("a")); 17 | } 18 | 19 | @Test 20 | public void isNullOrEmpty() throws Exception { 21 | assertTrue(Utils.isNullOrEmpty(null)); 22 | 23 | assertTrue(Utils.isNullOrEmpty("")); 24 | 25 | assertFalse(Utils.isNullOrEmpty(" ")); 26 | 27 | assertFalse(Utils.isNullOrEmpty("a")); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/ColumnProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class ColumnProjection extends Projection { 8 | private String table; 9 | private String column; 10 | 11 | public ColumnProjection(String table, String column) { 12 | this.table = table; 13 | this.column = column; 14 | } 15 | 16 | @Override 17 | public String build() { 18 | String ret = ""; 19 | 20 | if(!Utils.isNullOrWhiteSpace(table)) 21 | ret = ret + table + "."; 22 | 23 | if(!Utils.isNullOrWhiteSpace(column)) 24 | ret = ret + column; 25 | 26 | return ret; 27 | } 28 | 29 | @Override 30 | public List buildParameters() { 31 | return Utils.EMPTY_LIST; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/SubQueryProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 7 | 8 | public class SubQueryProjection extends Projection { 9 | private QueryBuilder subQuery; 10 | 11 | public SubQueryProjection(QueryBuilder subQuery) { 12 | this.subQuery = subQuery; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | if(subQuery != null) 18 | return "(" + subQuery.build() + ")"; 19 | else 20 | return ""; 21 | } 22 | 23 | @Override 24 | public List buildParameters() { 25 | if(subQuery != null) 26 | return subQuery.buildParameters(); 27 | else 28 | return Utils.EMPTY_LIST; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/ConstantProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.reinaldoarrosi.android.querybuilder.Utils; 7 | 8 | public class ConstantProjection extends Projection { 9 | private Object constant; 10 | 11 | public ConstantProjection(Object constant) { 12 | this.constant = constant; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | if(constant != null) 18 | return "?"; 19 | else 20 | return "NULL"; 21 | } 22 | 23 | @Override 24 | public List buildParameters() { 25 | if(constant != null) { 26 | List ret = new ArrayList(); 27 | ret.add(constant); 28 | 29 | return ret; 30 | } else { 31 | return Utils.EMPTY_LIST; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/order/OrderAscendingIgnoreCase.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.order; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 7 | 8 | public class OrderAscendingIgnoreCase extends Order { 9 | 10 | public OrderAscendingIgnoreCase(Projection projection) { 11 | super(projection); 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = " COLLATE NOCASE ASC"; 17 | 18 | if(projection != null) 19 | ret = projection.build() + ret; 20 | 21 | return ret; 22 | } 23 | 24 | @Override 25 | public List buildParameters() { 26 | if(projection != null) 27 | return projection.buildParameters(); 28 | else 29 | return Utils.EMPTY_LIST; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/order/OrderDescendingIgnoreCase.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.order; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 7 | 8 | public class OrderDescendingIgnoreCase extends Order { 9 | 10 | public OrderDescendingIgnoreCase(Projection projection) { 11 | super(projection); 12 | } 13 | 14 | @Override 15 | public String build() { 16 | String ret = " COLLATE NOCASE DESC"; 17 | 18 | if(projection != null) 19 | ret = projection.build() + ret; 20 | 21 | return ret; 22 | } 23 | 24 | @Override 25 | public List buildParameters() { 26 | if(projection != null) 27 | return projection.buildParameters(); 28 | else 29 | return Utils.EMPTY_LIST; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/ExistsCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 7 | 8 | public class ExistsCriteria extends Criteria { 9 | private QueryBuilder subQuery; 10 | 11 | public ExistsCriteria(QueryBuilder subQuery) { 12 | this.subQuery = subQuery; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | String ret = "EXISTS("; 18 | 19 | if(subQuery != null) 20 | ret = ret + subQuery.build(); 21 | 22 | ret = ret + ")"; 23 | return ret; 24 | } 25 | 26 | @Override 27 | public List buildParameters() { 28 | if(subQuery != null) 29 | return subQuery.buildParameters(); 30 | else 31 | return Utils.EMPTY_LIST; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/from/SubQueryFrom.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.from; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 7 | 8 | public class SubQueryFrom extends AliasableFrom { 9 | private QueryBuilder subQuery; 10 | 11 | public SubQueryFrom(QueryBuilder subQuery) { 12 | this.subQuery = subQuery; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | String ret = (subQuery != null ? "(" + subQuery.build() + ")" : ""); 18 | 19 | if(!Utils.isNullOrWhiteSpace(alias)) 20 | ret = ret + " AS " + alias; 21 | 22 | return ret; 23 | } 24 | 25 | @Override 26 | public List buildParameters() { 27 | if(subQuery != null) 28 | return subQuery.buildParameters(); 29 | else 30 | return Utils.EMPTY_LIST; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/OrCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class OrCriteria extends Criteria { 7 | private Criteria left; 8 | private Criteria right; 9 | 10 | public OrCriteria(Criteria left, Criteria right) { 11 | this.left = left; 12 | this.right = right; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | String ret = " OR "; 18 | 19 | if(left != null) 20 | ret = left.build() + ret; 21 | 22 | if(right != null) 23 | ret = ret + right.build(); 24 | 25 | return "(" + ret.trim() + ")"; 26 | } 27 | 28 | @Override 29 | public List buildParameters() { 30 | List ret = new ArrayList(); 31 | 32 | if(left != null) 33 | ret.addAll(left.buildParameters()); 34 | 35 | if(right != null) 36 | ret.addAll(right.buildParameters()); 37 | 38 | return ret; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/AndCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class AndCriteria extends Criteria { 7 | private Criteria left; 8 | private Criteria right; 9 | 10 | public AndCriteria(Criteria left, Criteria right) { 11 | this.left = left; 12 | this.right = right; 13 | } 14 | 15 | @Override 16 | public String build() { 17 | String ret = " AND "; 18 | 19 | if(left != null) 20 | ret = left.build() + ret; 21 | 22 | if(right != null) 23 | ret = ret + right.build(); 24 | 25 | return "(" + ret.trim() + ")"; 26 | } 27 | 28 | @Override 29 | public List buildParameters() { 30 | List ret = new ArrayList(); 31 | 32 | if(left != null) 33 | ret.addAll(left.buildParameters()); 34 | 35 | if(right != null) 36 | ret.addAll(right.buildParameters()); 37 | 38 | return ret; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Reinaldo Arrosi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/QueryBuildConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite; 2 | 3 | import org.joda.time.format.DateTimeFormat; 4 | import org.joda.time.format.DateTimeFormatter; 5 | 6 | public class QueryBuildConfiguration { 7 | private static final QueryBuildConfiguration current = new QueryBuildConfiguration(); 8 | 9 | public static QueryBuildConfiguration current() { 10 | return current; 11 | } 12 | 13 | private DateTimeFormatter dateFormat = DateTimeFormat.forPattern("yyyy-MM-dd"); 14 | private DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); 15 | 16 | public DateTimeFormatter getDateFormat() { 17 | return dateFormat; 18 | } 19 | 20 | public DateTimeFormatter getDateTimeFormat() { 21 | return dateTimeFormat; 22 | } 23 | 24 | public void setDateFormat(String format) { 25 | setDateFormat(DateTimeFormat.forPattern(format)); 26 | } 27 | 28 | public void setDateTimeFormat(String format) { 29 | setDateTimeFormat(DateTimeFormat.forPattern(format)); 30 | } 31 | 32 | public void setDateFormat(DateTimeFormatter format) { 33 | dateFormat = format; 34 | } 35 | 36 | public void setDateTimeFormat(DateTimeFormatter format) { 37 | dateTimeFormat = format; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/AggregateProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class AggregateProjection extends Projection { 8 | public static class Type { 9 | public static final int MIN = 1; 10 | public static final int MAX = 2; 11 | public static final int SUM = 3; 12 | public static final int AVG = 4; 13 | public static final int COUNT = 5; 14 | } 15 | 16 | private Projection projection; 17 | private int type; 18 | 19 | public AggregateProjection(Projection projection, int type) { 20 | this.projection = projection; 21 | this.type = type; 22 | } 23 | 24 | @Override 25 | public String build() { 26 | String ret = (projection != null ? projection.build() : ""); 27 | 28 | if(type == Type.MIN) 29 | return "MIN(" + ret + ")"; 30 | else if(type == Type.MAX) 31 | return "MAX(" + ret + ")"; 32 | else if(type == Type.SUM) 33 | return "SUM(" + ret + ")"; 34 | else if(type == Type.AVG) 35 | return "AVG(" + ret + ")"; 36 | else if(type == Type.COUNT) 37 | return "COUNT(" + ret + ")"; 38 | else 39 | return ret; 40 | } 41 | 42 | @Override 43 | public List buildParameters() { 44 | if(projection != null) 45 | return projection.buildParameters(); 46 | else 47 | return Utils.EMPTY_LIST; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/BetweenCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public class BetweenCriteria extends Criteria { 10 | private Projection projection; 11 | private Object valueStart; 12 | private Object valueEnd; 13 | 14 | public BetweenCriteria(Projection projection, Object valueStart, Object valueEnd) { 15 | this.projection = projection; 16 | this.valueStart = valueStart; 17 | this.valueEnd = valueEnd; 18 | 19 | if(this.projection instanceof AliasedProjection) 20 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 21 | } 22 | 23 | @Override 24 | public String build() { 25 | StringBuilder sb = new StringBuilder(); 26 | 27 | if(projection != null) 28 | sb.append(projection.build()); 29 | 30 | sb.append(" BETWEEN "); 31 | sb.append((valueStart != null ? "?" : "NULL")); 32 | sb.append(" AND "); 33 | sb.append((valueEnd != null ? "?" : "NULL")); 34 | 35 | return sb.toString(); 36 | } 37 | 38 | @Override 39 | public List buildParameters() { 40 | List ret = new ArrayList(); 41 | 42 | if(projection != null) 43 | ret.addAll(projection.buildParameters()); 44 | 45 | if(valueStart != null) 46 | ret.add(valueStart); 47 | 48 | if(valueEnd != null) 49 | ret.add(valueEnd); 50 | 51 | return ret; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/order/Order.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.order; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 7 | 8 | public abstract class Order { 9 | public static Order orderByAscending(String column) { 10 | return new OrderAscending(Projection.column(column)); 11 | } 12 | 13 | public static Order orderByDescending(String column) { 14 | return new OrderDescending(Projection.column(column)); 15 | } 16 | 17 | public static Order orderByAscending(Projection projection) { 18 | return new OrderAscending(projection); 19 | } 20 | 21 | public static Order orderByDescending(Projection projection) { 22 | return new OrderDescending(projection); 23 | } 24 | 25 | public static Order orderByAscendingIgnoreCase(String column) { 26 | return new OrderAscendingIgnoreCase(Projection.column(column)); 27 | } 28 | 29 | public static Order orderByDescendingIgnoreCase(String column) { 30 | return new OrderDescendingIgnoreCase(Projection.column(column)); 31 | } 32 | 33 | public static Order orderByAscendingIgnoreCase(Projection projection) { 34 | return new OrderAscendingIgnoreCase(projection); 35 | } 36 | 37 | public static Order orderByDescendingIgnoreCase(Projection projection) { 38 | return new OrderDescendingIgnoreCase(projection); 39 | } 40 | 41 | 42 | protected Projection projection; 43 | 44 | public Order(Projection projection) { 45 | this.projection = projection; 46 | 47 | if(this.projection instanceof AliasedProjection) 48 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 49 | } 50 | 51 | public abstract String build(); 52 | public abstract List buildParameters(); 53 | } 54 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/ValueBetweenCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public class ValueBetweenCriteria extends Criteria { 10 | private Object value; 11 | private Projection projectionStart; 12 | private Projection projectionEnd; 13 | 14 | public ValueBetweenCriteria(Object value, Projection projectionStart, Projection projectionEnd) { 15 | this.value = value; 16 | this.projectionStart = projectionStart; 17 | this.projectionEnd = projectionEnd; 18 | 19 | if(this.projectionStart instanceof AliasedProjection) 20 | this.projectionStart = ((AliasedProjection)this.projectionStart).removeAlias(); 21 | 22 | if(this.projectionEnd instanceof AliasedProjection) 23 | this.projectionEnd = ((AliasedProjection)this.projectionEnd).removeAlias(); 24 | } 25 | 26 | @Override 27 | public String build() { 28 | StringBuilder sb = new StringBuilder(); 29 | 30 | sb.append((value != null ? "?" : "NULL")); 31 | sb.append(" BETWEEN "); 32 | sb.append((projectionStart != null ? projectionStart.build() : "NULL")); 33 | sb.append(" AND "); 34 | sb.append((projectionEnd != null ? projectionEnd.build() : "NULL")); 35 | 36 | return sb.toString(); 37 | } 38 | 39 | @Override 40 | public List buildParameters() { 41 | List ret = new ArrayList(); 42 | 43 | if(value != null) 44 | ret.add(value); 45 | 46 | if(projectionStart != null) 47 | ret.addAll(projectionStart.buildParameters()); 48 | 49 | if(projectionEnd != null) 50 | ret.addAll(projectionEnd.buildParameters()); 51 | 52 | return ret; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/from/From.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.from; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.criteria.Criteria; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public abstract class From { 10 | public static class PartialJoin { 11 | private String joinType; 12 | private From left; 13 | private From right; 14 | 15 | protected PartialJoin(From left, From right, String joinType) { 16 | this.joinType = joinType; 17 | this.left = left; 18 | this.right = right; 19 | } 20 | 21 | public JoinFrom on(String leftColumn, String rightColumn) { 22 | return on(Criteria.equals(Projection.column(leftColumn), Projection.column(rightColumn))); 23 | } 24 | 25 | public JoinFrom on(Criteria criteria) { 26 | return new JoinFrom(left, right, joinType, criteria); 27 | } 28 | } 29 | 30 | public static TableFrom table(String table) { 31 | return new TableFrom(table); 32 | } 33 | 34 | public static SubQueryFrom subQuery(QueryBuilder subQuery) { 35 | return new SubQueryFrom(subQuery); 36 | } 37 | 38 | public PartialJoin innerJoin(String table) { 39 | return innerJoin(From.table(table)); 40 | } 41 | 42 | public PartialJoin innerJoin(QueryBuilder subQuery) { 43 | return innerJoin(From.subQuery(subQuery)); 44 | } 45 | 46 | public PartialJoin innerJoin(From table) { 47 | return new PartialJoin(this, table, "INNER JOIN"); 48 | } 49 | 50 | public PartialJoin leftJoin(String table) { 51 | return leftJoin(From.table(table)); 52 | } 53 | 54 | public PartialJoin leftJoin(QueryBuilder subQuery) { 55 | return leftJoin(From.subQuery(subQuery)); 56 | } 57 | 58 | public PartialJoin leftJoin(From table) { 59 | return new PartialJoin(this, table, "LEFT JOIN"); 60 | } 61 | 62 | public abstract String build(); 63 | 64 | public abstract List buildParameters(); 65 | } 66 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/AliasedProjection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.Utils; 6 | 7 | public class AliasedProjection extends Projection { 8 | private Projection projection; 9 | private String alias; 10 | 11 | public AliasedProjection(Projection projection, String alias) { 12 | this.projection = projection; 13 | this.alias = alias; 14 | } 15 | 16 | @Override 17 | public Projection as(String alias) { 18 | this.alias = alias; 19 | return this; 20 | } 21 | 22 | @Override 23 | public Projection castAsDate() { 24 | if(projection != null) 25 | projection = projection.castAsDate(); 26 | 27 | return this; 28 | } 29 | 30 | @Override 31 | public Projection castAsDateTime() { 32 | if(projection != null) 33 | projection = projection.castAsDateTime(); 34 | 35 | return this; 36 | } 37 | 38 | @Override 39 | public Projection castAsInt() { 40 | if(projection != null) 41 | projection = projection.castAsInt(); 42 | 43 | return this; 44 | } 45 | 46 | @Override 47 | public Projection castAsReal() { 48 | if(projection != null) 49 | projection = projection.castAsReal(); 50 | 51 | return this; 52 | } 53 | 54 | @Override 55 | public Projection castAsString() { 56 | if(projection != null) 57 | projection = projection.castAsString(); 58 | 59 | return this; 60 | } 61 | 62 | public Projection removeAlias() { 63 | Projection p = projection; 64 | 65 | while(p instanceof AliasedProjection) { 66 | p = ((AliasedProjection)p).projection; 67 | } 68 | 69 | return p; 70 | } 71 | 72 | @Override 73 | public String build() { 74 | String ret = (projection != null ? projection.build() : ""); 75 | return ret + " AS " + alias; 76 | } 77 | 78 | @Override 79 | public List buildParameters() { 80 | if(projection != null) 81 | return projection.buildParameters(); 82 | else 83 | return Utils.EMPTY_LIST; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/from/JoinFrom.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.from; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.criteria.Criteria; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public class JoinFrom extends From { 10 | private From left; 11 | private From right; 12 | private String joinType; 13 | private Criteria criteria; 14 | 15 | public JoinFrom(From left, From right, String joinType, Criteria criteria) { 16 | this.left = left; 17 | this.right = right; 18 | this.joinType = joinType; 19 | this.criteria = criteria; 20 | } 21 | 22 | public JoinFrom onOr(String leftColumn, String rightColumn) { 23 | return onOr(Criteria.equals(Projection.column(leftColumn), Projection.column(rightColumn))); 24 | } 25 | 26 | public JoinFrom onAnd(String leftColumn, String rightColumn) { 27 | return onAnd(Criteria.equals(Projection.column(leftColumn), Projection.column(rightColumn))); 28 | } 29 | 30 | public JoinFrom onAnd(Criteria criteria) { 31 | this.criteria = (this.criteria != null ? this.criteria.and(criteria) : criteria); 32 | return this; 33 | } 34 | 35 | public JoinFrom onOr(Criteria criteria) { 36 | this.criteria = (this.criteria != null ? this.criteria.or(criteria) : criteria); 37 | return this; 38 | } 39 | 40 | @Override 41 | public String build() { 42 | String leftSide = (left != null ? left.build() : ""); 43 | String rightSide = (right != null ? right.build() : ""); 44 | String joinCriteria = (criteria != null ? criteria.build() : ""); 45 | 46 | return "(" + leftSide + " " + joinType + " " + rightSide + " ON " + joinCriteria + ")"; 47 | } 48 | 49 | @Override 50 | public List buildParameters() { 51 | List ret = new ArrayList(); 52 | 53 | if(left != null) 54 | ret.addAll(left.buildParameters()); 55 | 56 | if(right != null) 57 | ret.addAll(right.buildParameters()); 58 | 59 | if(criteria != null) 60 | ret.addAll(criteria.buildParameters()); 61 | 62 | return ret; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/Utils.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import org.joda.time.LocalDate; 8 | import org.joda.time.LocalDateTime; 9 | import org.joda.time.format.DateTimeFormatter; 10 | 11 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuildConfiguration; 12 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 13 | 14 | public class Utils { 15 | public static final List EMPTY_LIST = new ArrayList(); 16 | 17 | public static String toString(Object value) { 18 | if (value == null) 19 | return null; 20 | 21 | if (value instanceof String) 22 | return (String)value; 23 | else if (value instanceof Float) 24 | return new BigDecimal((Float) value).stripTrailingZeros().toPlainString(); 25 | else if (value instanceof Double) 26 | return new BigDecimal((Double) value).stripTrailingZeros().toPlainString(); 27 | else 28 | return String.valueOf(value); 29 | } 30 | 31 | public static String dateToString(LocalDate date, DateTimeFormatter format) { 32 | if (date == null) 33 | return null; 34 | 35 | if(format == null) 36 | format = QueryBuildConfiguration.current().getDateFormat(); 37 | 38 | try { 39 | return date.toString(format); 40 | } catch (Exception e) { 41 | return null; 42 | } 43 | } 44 | 45 | public static String dateToString(LocalDateTime date, DateTimeFormatter format) { 46 | if (date == null) 47 | return null; 48 | 49 | if(format == null) 50 | format = QueryBuildConfiguration.current().getDateTimeFormat(); 51 | 52 | try { 53 | return date.toString(format); 54 | } catch (Exception e) { 55 | return null; 56 | } 57 | } 58 | 59 | public static boolean isNullOrEmpty(String string) { 60 | return (string == null || string.length() <= 0); 61 | } 62 | 63 | public static boolean isNullOrWhiteSpace(String string) { 64 | return (string == null || string.trim().length() <= 0); 65 | } 66 | 67 | public static Projection[] buildColumnProjections(String... columns) { 68 | Projection[] projections = new Projection[columns.length]; 69 | 70 | for (int i = 0; i < columns.length; i++) { 71 | projections[i] = Projection.column(columns[i]); 72 | } 73 | return projections; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /query-builder-core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'jacoco' 3 | apply plugin: 'maven' 4 | apply plugin: 'maven-publish' 5 | apply plugin: 'com.jfrog.bintray' 6 | 7 | jacocoTestReport { 8 | reports { 9 | xml.enabled true 10 | } 11 | } 12 | 13 | dependencies { 14 | compile 'joda-time:joda-time:2.1' 15 | 16 | testCompile 'junit:junit:4.12' 17 | } 18 | 19 | task sourcesJar(type: Jar, dependsOn: classes) { 20 | classifier = 'sources' 21 | from sourceSets.main.allSource 22 | } 23 | 24 | task javadocJar(type: Jar, dependsOn: javadoc) { 25 | classifier = 'javadoc' 26 | from javadoc.destinationDir 27 | } 28 | 29 | def pomConfig = { 30 | licenses { 31 | license { 32 | name "MIT License" 33 | url "https://opensource.org/licenses/MIT" 34 | distribution "repo" 35 | } 36 | } 37 | developers { 38 | developer { 39 | name "Reinaldo Arrosi" 40 | email "rarrosi@gmail.com" 41 | } 42 | } 43 | scm { 44 | connection "scm:git:git://github.com/reinaldoarrosi/QueryBuilder.git" 45 | developerConnection "scm:git:ssh://github.com: reinaldoarrosi/QueryBuilder.git" 46 | url "https://github.com/reinaldoarrosi/QueryBuilder/tree/master" 47 | } 48 | } 49 | 50 | publishing { 51 | publications { 52 | QueryBuilderPublication(MavenPublication) { 53 | from components.java 54 | groupId 'com.github.reinaldoarrosi' 55 | artifactId 'query-builder' 56 | version '0.1.1' 57 | artifact sourcesJar 58 | artifact javadocJar 59 | 60 | pom.withXml { 61 | def root = asNode() 62 | root.appendNode('description', 'Fluent Android library to build SQLite select statements') 63 | root.appendNode('name', 'com.github.reinaldoarrosi:query-builder') 64 | root.appendNode('url', 'https://github.com/reinaldoarrosi/QueryBuilder') 65 | root.children().last() + pomConfig 66 | } 67 | } 68 | } 69 | } 70 | 71 | // Bintray 72 | Properties properties = new Properties() 73 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 74 | 75 | bintray { 76 | user = properties.getProperty('bintray.user') 77 | key = properties.getProperty('bintray.apikey') 78 | publications = ['QueryBuilderPublication'] 79 | pkg { 80 | repo = 'maven' 81 | name = 'query-builder' 82 | version { 83 | name = '0.1.1' 84 | gpg { 85 | sign = true 86 | passphrase = properties.getProperty("bintray.gpg.password") 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/InCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public class InCriteria extends Criteria { 10 | private Projection projection; 11 | private List valuesList; 12 | private Object[] valuesArray; 13 | 14 | public InCriteria(Projection projection, List values) { 15 | this.projection = projection; 16 | this.valuesList = values; 17 | this.valuesArray = null; 18 | 19 | if(this.projection instanceof AliasedProjection) 20 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 21 | } 22 | 23 | public InCriteria(Projection projection, Object[] values) { 24 | this.projection = projection; 25 | this.valuesArray = values; 26 | this.valuesList = null; 27 | 28 | if(this.projection instanceof AliasedProjection) 29 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 30 | } 31 | 32 | @Override 33 | public String build() { 34 | StringBuilder sb = new StringBuilder(); 35 | 36 | if(projection != null) 37 | sb.append(projection.build()); 38 | 39 | sb.append(" IN ("); 40 | 41 | if(valuesList != null) { 42 | if(valuesList.size() <= 0) 43 | return "1=0"; 44 | 45 | for (int i = 0; i < valuesList.size(); i++) { 46 | if(valuesList.get(i) != null) 47 | sb.append("?, "); 48 | else 49 | sb.append("NULL, "); 50 | } 51 | } else { 52 | if(valuesArray.length <= 0) 53 | return "1=0"; 54 | 55 | for (int i = 0; i < valuesArray.length; i++) { 56 | if(valuesArray[i] != null) 57 | sb.append("?, "); 58 | else 59 | sb.append("NULL, "); 60 | } 61 | } 62 | 63 | sb.setLength(sb.length() - 2); //removes the ", " from the last entry 64 | sb.append(")"); 65 | 66 | return sb.toString(); 67 | } 68 | 69 | @Override 70 | public List buildParameters() { 71 | List ret = new ArrayList(); 72 | 73 | if(projection != null) 74 | ret.addAll(projection.buildParameters()); 75 | 76 | if(valuesList != null) { 77 | for (int i = 0; i < valuesList.size(); i++) { 78 | if(valuesList.get(i) != null) 79 | ret.add(valuesList.get(i)); 80 | } 81 | } else { 82 | for (int i = 0; i < valuesArray.length; i++) { 83 | if(valuesArray[i] != null) 84 | ret.add(valuesArray[i]); 85 | } 86 | } 87 | 88 | return ret; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/NotInCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public class NotInCriteria extends Criteria { 10 | private Projection projection; 11 | private List valuesList; 12 | private Object[] valuesArray; 13 | 14 | public NotInCriteria(Projection projection, List values) { 15 | this.projection = projection; 16 | this.valuesList = values; 17 | this.valuesArray = null; 18 | 19 | if(this.projection instanceof AliasedProjection) 20 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 21 | } 22 | 23 | public NotInCriteria(Projection projection, Object[] values) { 24 | this.projection = projection; 25 | this.valuesArray = values; 26 | this.valuesList = null; 27 | 28 | if(this.projection instanceof AliasedProjection) 29 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 30 | } 31 | 32 | @Override 33 | public String build() { 34 | StringBuilder sb = new StringBuilder(); 35 | 36 | if(projection != null) 37 | sb.append(projection.build()); 38 | 39 | sb.append(" NOT IN ("); 40 | 41 | if(valuesList != null) { 42 | if(valuesList.size() <= 0) 43 | return "1=1"; 44 | 45 | for (int i = 0; i < valuesList.size(); i++) { 46 | if(valuesList.get(i) != null) 47 | sb.append("?, "); 48 | else 49 | sb.append("NULL, "); 50 | } 51 | } else { 52 | if(valuesArray.length <= 0) 53 | return "1=1"; 54 | 55 | for (int i = 0; i < valuesArray.length; i++) { 56 | if(valuesArray[i] != null) 57 | sb.append("?, "); 58 | else 59 | sb.append("NULL, "); 60 | } 61 | } 62 | 63 | sb.setLength(sb.length() - 2); //removes the ", " from the last entry 64 | sb.append(")"); 65 | 66 | return sb.toString(); 67 | } 68 | 69 | @Override 70 | public List buildParameters() { 71 | List ret = new ArrayList(); 72 | 73 | if(projection != null) 74 | ret.addAll(projection.buildParameters()); 75 | 76 | if(valuesList != null) { 77 | for (int i = 0; i < valuesList.size(); i++) { 78 | if(valuesList.get(i) != null) 79 | ret.add(valuesList.get(i)); 80 | } 81 | } else { 82 | for (int i = 0; i < valuesArray.length; i++) { 83 | if(valuesArray[i] != null) 84 | ret.add(valuesArray[i]); 85 | } 86 | } 87 | 88 | return ret; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/BasicCriteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.joda.time.LocalDate; 7 | import org.joda.time.LocalDateTime; 8 | 9 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 10 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 11 | 12 | public class BasicCriteria extends Criteria { 13 | public static class Operators { 14 | public static final String IS_NULL = "IS NULL"; 15 | public static final String IS_NOT_NULL = "IS NOT NULL"; 16 | public static final String EQUALS = "="; 17 | public static final String NOT_EQUALS = "<>"; 18 | public static final String GREATER = ">"; 19 | public static final String LESSER = "<"; 20 | public static final String GREATER_OR_EQUALS = ">="; 21 | public static final String LESSER_OR_EQUALS = "<="; 22 | public static final String LIKE = "LIKE"; 23 | public static final String NOT_LIKE = "NOT LIKE"; 24 | } 25 | 26 | private Projection projection; 27 | private String operator; 28 | private Object value; 29 | 30 | public BasicCriteria(Projection projection, String operator, Object value) { 31 | this.projection = projection; 32 | this.operator = operator; 33 | this.value = value; 34 | 35 | if(this.projection instanceof AliasedProjection) 36 | this.projection = ((AliasedProjection)this.projection).removeAlias(); 37 | 38 | if(value == null) { 39 | if(Operators.IS_NULL.equals(operator) || Operators.EQUALS.equals(operator) || Operators.LIKE.equals(operator)) 40 | this.operator = Operators.IS_NULL; 41 | else 42 | this.operator = Operators.IS_NOT_NULL; 43 | } 44 | } 45 | 46 | @Override 47 | public String build() { 48 | StringBuilder sb = new StringBuilder(); 49 | 50 | if(projection != null) { 51 | if(value instanceof LocalDateTime) 52 | sb.append(projection.castAsDateTime().build()); 53 | else if(value instanceof LocalDate) 54 | sb.append(projection.castAsDate().build()); 55 | else 56 | sb.append(projection.build()); 57 | } 58 | 59 | sb.append(" "); 60 | sb.append(operator); 61 | sb.append(" "); 62 | 63 | if(value != null) { 64 | if(value instanceof AliasedProjection) 65 | sb.append(((AliasedProjection)value).removeAlias().build()); 66 | else if(value instanceof Projection) 67 | sb.append(((Projection)value).build()); 68 | else 69 | sb.append("?"); 70 | } 71 | 72 | return sb.toString(); 73 | } 74 | 75 | @Override 76 | public List buildParameters() { 77 | List ret = new ArrayList(); 78 | 79 | if(projection != null) 80 | ret.addAll(projection.buildParameters()); 81 | 82 | if(value != null) 83 | ret.add(value); 84 | 85 | return ret; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/projection/Projection.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.projection; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AggregateProjection.Type; 7 | 8 | public abstract class Projection { 9 | // Simple column 10 | public static ColumnProjection column(String column) { 11 | return new ColumnProjection(null, column); 12 | } 13 | 14 | public static ColumnProjection column(String table, String column) { 15 | return new ColumnProjection(table, column); 16 | } 17 | 18 | 19 | // Constant 20 | public static ConstantProjection constant(Object constant) { 21 | return new ConstantProjection(constant); 22 | } 23 | 24 | 25 | // Aggregate functions 26 | public static AggregateProjection min(String column) { 27 | return min(column(column)); 28 | } 29 | 30 | public static AggregateProjection max(String column) { 31 | return max(column(column)); 32 | } 33 | 34 | public static AggregateProjection sum(String column) { 35 | return sum(column(column)); 36 | } 37 | 38 | public static AggregateProjection avg(String column) { 39 | return avg(column(column)); 40 | } 41 | 42 | public static AggregateProjection count(String column) { 43 | return count(column(column)); 44 | } 45 | 46 | public static AggregateProjection countRows() { 47 | return count(column("*")); 48 | } 49 | 50 | public static AggregateProjection min(Projection projection) { 51 | return new AggregateProjection(projection, Type.MIN); 52 | } 53 | 54 | public static AggregateProjection max(Projection projection) { 55 | return new AggregateProjection(projection, Type.MAX); 56 | } 57 | 58 | public static AggregateProjection sum(Projection projection) { 59 | return new AggregateProjection(projection, Type.SUM); 60 | } 61 | 62 | public static AggregateProjection avg(Projection projection) { 63 | return new AggregateProjection(projection, Type.AVG); 64 | } 65 | 66 | public static AggregateProjection count(Projection projection) { 67 | return new AggregateProjection(projection, Type.COUNT); 68 | } 69 | 70 | 71 | // SubQuery 72 | public static SubQueryProjection subQuery(QueryBuilder subQuery) { 73 | return new SubQueryProjection(subQuery); 74 | } 75 | 76 | public Projection as(String alias) { 77 | return new AliasedProjection(this, alias); 78 | } 79 | 80 | public Projection castAsDate() { 81 | return new CastDateProjection(this); 82 | } 83 | 84 | public Projection castAsDateTime() { 85 | return new CastDateTimeProjection(this); 86 | } 87 | 88 | public Projection castAsReal() { 89 | return new CastRealProjection(this); 90 | } 91 | 92 | public Projection castAsInt() { 93 | return new CastIntProjection(this); 94 | } 95 | 96 | public Projection castAsString() { 97 | return new CastStringProjection(this); 98 | } 99 | 100 | public abstract String build(); 101 | 102 | public abstract List buildParameters(); 103 | } 104 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/criteria/Criteria.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite.criteria; 2 | 3 | import java.util.List; 4 | 5 | import com.reinaldoarrosi.android.querybuilder.sqlite.QueryBuilder; 6 | import com.reinaldoarrosi.android.querybuilder.sqlite.criteria.BasicCriteria.Operators; 7 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 8 | 9 | public abstract class Criteria { 10 | // Null 11 | public static Criteria isNull(String column) { 12 | return new BasicCriteria(Projection.column(column), Operators.IS_NULL, null); 13 | } 14 | 15 | public static Criteria notIsNull(String column) { 16 | return new BasicCriteria(Projection.column(column), Operators.IS_NOT_NULL, null); 17 | } 18 | 19 | public static Criteria isNull(Projection projection) { 20 | return new BasicCriteria(projection, Operators.IS_NULL, null); 21 | } 22 | 23 | public static Criteria notIsNull(Projection projection) { 24 | return new BasicCriteria(projection, Operators.IS_NOT_NULL, null); 25 | } 26 | 27 | 28 | // Basic criterias 29 | public static Criteria equals(String column, Object value) { 30 | return new BasicCriteria(Projection.column(column), Operators.EQUALS, value); 31 | } 32 | 33 | public static Criteria notEquals(String column, Object value) { 34 | return new BasicCriteria(Projection.column(column), Operators.NOT_EQUALS, value); 35 | } 36 | 37 | public static Criteria greaterThan(String column, Object value) { 38 | return new BasicCriteria(Projection.column(column), Operators.GREATER, value); 39 | } 40 | 41 | public static Criteria lesserThan(String column, Object value) { 42 | return new BasicCriteria(Projection.column(column), Operators.LESSER, value); 43 | } 44 | 45 | public static Criteria greaterThanOrEqual(String column, Object value) { 46 | return new BasicCriteria(Projection.column(column), Operators.GREATER_OR_EQUALS, value); 47 | } 48 | 49 | public static Criteria lesserThanOrEqual(String column, Object value) { 50 | return new BasicCriteria(Projection.column(column), Operators.LESSER_OR_EQUALS, value); 51 | } 52 | 53 | public static Criteria equals(Projection column, Object value) { 54 | return new BasicCriteria(column, Operators.EQUALS, value); 55 | } 56 | 57 | public static Criteria notEquals(Projection column, Object value) { 58 | return new BasicCriteria(column, Operators.NOT_EQUALS, value); 59 | } 60 | 61 | public static Criteria greaterThan(Projection column, Object value) { 62 | return new BasicCriteria(column, Operators.GREATER, value); 63 | } 64 | 65 | public static Criteria lesserThan(Projection column, Object value) { 66 | return new BasicCriteria(column, Operators.LESSER, value); 67 | } 68 | 69 | public static Criteria greaterThanOrEqual(Projection column, Object value) { 70 | return new BasicCriteria(column, Operators.GREATER_OR_EQUALS, value); 71 | } 72 | 73 | public static Criteria lesserThanOrEqual(Projection column, Object value) { 74 | return new BasicCriteria(column, Operators.LESSER_OR_EQUALS, value); 75 | } 76 | 77 | 78 | // String-only criterias 79 | public static Criteria startsWith(String column, String value) { 80 | return new BasicCriteria(Projection.column(column), Operators.LIKE, value + "%"); 81 | } 82 | 83 | public static Criteria notStartsWith(String column, String value) { 84 | return new BasicCriteria(Projection.column(column), Operators.NOT_LIKE, value + "%"); 85 | } 86 | 87 | public static Criteria endsWith(String column, String value) { 88 | return new BasicCriteria(Projection.column(column), Operators.LIKE, "%" + value); 89 | } 90 | 91 | public static Criteria notEndsWith(String column, String value) { 92 | return new BasicCriteria(Projection.column(column), Operators.NOT_LIKE, "%" + value); 93 | } 94 | 95 | public static Criteria contains(String column, String value) { 96 | return new BasicCriteria(Projection.column(column), Operators.LIKE, "%" + value + "%"); 97 | } 98 | 99 | public static Criteria notContains(String column, String value) { 100 | return new BasicCriteria(Projection.column(column), Operators.NOT_LIKE, "%" + value + "%"); 101 | } 102 | 103 | public static Criteria startsWith(Projection column, String value) { 104 | return new BasicCriteria(column, Operators.LIKE, value + "%"); 105 | } 106 | 107 | public static Criteria notStartsWith(Projection column, String value) { 108 | return new BasicCriteria(column, Operators.NOT_LIKE, value + "%"); 109 | } 110 | 111 | public static Criteria endsWith(Projection column, String value) { 112 | return new BasicCriteria(column, Operators.LIKE, "%" + value); 113 | } 114 | 115 | public static Criteria notEndsWith(Projection column, String value) { 116 | return new BasicCriteria(column, Operators.NOT_LIKE, "%" + value); 117 | } 118 | 119 | public static Criteria contains(Projection column, String value) { 120 | return new BasicCriteria(column, Operators.LIKE, "%" + value + "%"); 121 | } 122 | 123 | public static Criteria notContains(Projection column, String value) { 124 | return new BasicCriteria(column, Operators.NOT_LIKE, "%" + value + "%"); 125 | } 126 | 127 | 128 | // Between 129 | public static Criteria between(String column, Object valueMin, Object valueMax) { 130 | return new BetweenCriteria(Projection.column(column), valueMin, valueMax); 131 | } 132 | 133 | public static Criteria valueBetween(Object value, String columnMin, String columnMax) { 134 | return new ValueBetweenCriteria(value, Projection.column(columnMin), Projection.column(columnMax)); 135 | } 136 | 137 | public static Criteria between(Projection column, Object valueMin, Object valueMax) { 138 | return new BetweenCriteria(column, valueMin, valueMax); 139 | } 140 | 141 | public static Criteria valueBetween(Object value, Projection columnMin, Projection columnMax) { 142 | return new ValueBetweenCriteria(value, columnMin, columnMax); 143 | } 144 | 145 | 146 | // Exists 147 | public static Criteria exists(QueryBuilder subQuery) { 148 | return new ExistsCriteria(subQuery); 149 | } 150 | 151 | public static Criteria notExists(QueryBuilder subQuery) { 152 | return new NotExistsCriteria(subQuery); 153 | } 154 | 155 | 156 | // In 157 | public static Criteria in(String column, Object[] values) { 158 | return new InCriteria(Projection.column(column), values); 159 | } 160 | 161 | public static Criteria notIn(String column, Object[] values) { 162 | return new NotInCriteria(Projection.column(column), values); 163 | } 164 | 165 | public static Criteria in(String column, List values) { 166 | return new InCriteria(Projection.column(column), values); 167 | } 168 | 169 | public static Criteria notIn(String column, List values) { 170 | return new NotInCriteria(Projection.column(column), values); 171 | } 172 | 173 | public static Criteria in(Projection column, Object[] values) { 174 | return new InCriteria(column, values); 175 | } 176 | 177 | public static Criteria notIn(Projection column, Object[] values) { 178 | return new NotInCriteria(column, values); 179 | } 180 | 181 | public static Criteria in(Projection column, List values) { 182 | return new InCriteria(column, values); 183 | } 184 | 185 | public static Criteria notIn(Projection column, List values) { 186 | return new NotInCriteria(column, values); 187 | } 188 | 189 | public abstract String build(); 190 | public abstract List buildParameters(); 191 | 192 | public AndCriteria and(Criteria criteria) { 193 | return new AndCriteria(this, criteria); 194 | } 195 | 196 | public OrCriteria or(Criteria criteria) { 197 | return new OrCriteria(this, criteria); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QueryBuilder 2 | **THIS PROJECT SUFFERED A MAJOR REDESIGN FROM V1 to V2. IF YOU NEED THE OLD VERSION CHECK THE TAG 1.0 AND GRAB WHAT YOU NEED** 3 | 4 | QueryBuilder is a fluent library for building SELECT statements for SQLite. It creates parameterized queries by default, but you can also get the query string without parameters by using the **toDebugSqlString** method. 5 | 6 | QueryBuilder also uses the excelent JODA-Time library (http://joda-time.sourceforge.net/) to handle dates. **I strongly advise you to use this library instead of using the built-in Date and Time classes from Java.** Version 2.1 is included in the libs folder, but feel free to use the latest version available. 7 | 8 | By default, QueryBuilder assumes that dates are stored in the **yyyy-MM-dd** format, and that datetimes are stored in the **yyyy-MM-dd HH:mm:ss** format. You can change the default formats by using the QueryBuilderConfiguration class. You can also change the format for a specific QueryBuilder instance, overriding the defaults. 9 | 10 | // Set new date/datetime formats as the default 11 | QueryBuilderConfiguration.current().setDateFormat("MM-dd-yyyy").setDateTimeFormat("MM-dd-yyyy HH:mm:ss"); 12 | 13 | // Change the date/datetime formats only for this QueryBuilder instance 14 | QueryBuilder builder = new QueryBuilder(); 15 | builder.setDateFormat("MM-dd-yyyy").setDateTimeFormat("MM-dd-yyyy HH:mm:ss"); 16 | 17 | ## Installing 18 | 19 | ###Maven 20 | 21 | ```xml 22 | 23 | com.github.reinaldoarrosi 24 | query-builder 25 | 0.1.1 26 | pom 27 | 28 | ``` 29 | 30 | ###Gradle 31 | 32 | ```groovy 33 | compile 'com.github.reinaldoarrosi:query-builder:0.1.1' 34 | ``` 35 | 36 | ## Usage 37 | ### Basic statement 38 | 39 | QueryBuilder builder = new QueryBuilder(); 40 | builder.select("MyColumnName1", "MyColumnName2", "MyColumnName3").from("MyTableName"); 41 | 42 | SQLiteDatabase db = getDB(); 43 | db.rawQuery(builder.build(), builder.buildParameters()); 44 | 45 | You can also call *select()* separatelly for each column (or mix both approaches) 46 | 47 | QueryBuilder builder = new QueryBuilder(); 48 | builder.select("MyColumnName1", "MyColumnName2") 49 | .select("MyColumnName3") 50 | .select("MyColumnName4") 51 | .from("MyTableName"); 52 | 53 | SQLiteDatabase db = getDB(); 54 | db.rawQuery(builder.build(), builder.buildParameters()); 55 | 56 | ### Complex SELECT clause 57 | Projections are used to create complex SELECT columns or expressions 58 | 59 | // Column with explicitly declared table (table name or table alias) 60 | .select(Projection.column("MyTableName", "MyColumnName1")) 61 | 62 | // Constants (e.g. SELECT "Teste", 5 FROM MyTable) 63 | .select(Projection.constant("Teste"), Projection.constant(5)) 64 | 65 | // Aggregate functions 66 | .select(Projection.min("MyColumnName")) 67 | .select(Projection.max("MyColumnName")) 68 | .select(Projection.sum("MyColumnName")) 69 | .select(Projection.avg("MyColumnName")) 70 | .select(Projection.count("MyColumnName")) 71 | .select(Projection.countRows()) // e.g. SELECT COUNT(*) FROM MyTable 72 | 73 | // Aliases. ANY Projection can be aliased by calling "as" 74 | .select(Projection.column("MyColumnName").as("MyAlias")) 75 | .select(Projection.constant(5).as("MyAlias")) 76 | .select(Projection.min("MyColumnName").as("MyAlias")) 77 | 78 | // Casts. You can cast ANY projection to date, datetime, real, integer or string 79 | .select(Projection.column("MyColumnName").castAsDate()) 80 | .select(Projection.column("MyColumnName").castAsDateTime()) 81 | .select(Projection.column("MyColumnName").castAsReal()) 82 | .select(Projection.column("MyColumnName").castAsInt()) 83 | .select(Projection.column("MyColumnName").castAsString()) 84 | 85 | ### Sub-queries projections 86 | 87 | QueryBuilder subQuery = new QueryBuilder(); 88 | subQuery.select("MAX(SubColumn)").from("SubTable"); 89 | 90 | QueryBuilder builder = new QueryBuilder(); 91 | builder.select(Projection.subQuery(subQuery).as("MyAlias")) 92 | .from("MyTable"); 93 | 94 | ### FROM clause 95 | For simple FROM clauses the from() method is enough. For more complex FROM clauses you can use the From class 96 | 97 | // Simple from 98 | .from("MyTable") 99 | 100 | // Aliased table 101 | .from(From.table("MyTable1").as("MyTableAlias")) 102 | 103 | ### Inner & Left Joins 104 | Note that in this example *MyTable3* is aliased so the *leftJoin()* is performed by using Projection so that the *MyColumn4* can be fully qualified with the table alias 105 | 106 | QueryBuilder builder = new QueryBuilder(); 107 | builder.select("MyColumn1") 108 | .select(Projection.column("AliasedTable", "MyColumn4")) 109 | .from(From.table("MyTable1").innerJoin("MyTable2") 110 | .on("MyColumn1", "MyColumn2") 111 | .leftJoin(From.table("MyTable3").as("AliasedTable")) 112 | .on(Projection.column("MyColumn3"), Projection.column("AliasedTable", "MyColumn4")) 113 | .onAnd(Criteria.equal("MyColumn5", 0)); 114 | 115 | ### Sub-queries in FROM clause 116 | 117 | QueryBuilder subQuery = new QueryBuilder(); 118 | subQuery.from("SubTable"); 119 | 120 | QueryBuilder builder = new QueryBuilder(); 121 | builder.from(subQuery); 122 | 123 | // you can also JOIN sub-queries: 124 | .from(From.subQuery(subQuery).innerJoin("Table").on("COL_FROM_SUBQUERY", "COL_FROM_TABLE") 125 | .from(From.table("Table").innerJoin(subQuery).on("COL_FROM_TABLE", "COL_FROM_SUBQUERY") 126 | .from(From.subQuery(subQuery1).innerJoin(subQuery2).on("COL_FROM_SUBQUERY1", "COL_FROM_SUBQUERY2") 127 | 128 | ### WHERE clause 129 | The WHERE clause is built by using the Criteria class. It allows to write simple and complex criterias and chain them together with AND/OR. The Criteria class works together with the Projection class, so you can create criterias that compare sub-queries, constants and anything that a Projection is able to create 130 | 131 | Here is an example that tries to show a broad range of usages of the Criteria class 132 | 133 | QueryBuilder subQuery1 = new QueryBuilder(); 134 | subQuery1.select("1").from("SubTable"); 135 | 136 | QueryBuilder subQuery2 = new QueryBuilder(); 137 | subQuery2.select(Projection.max("MySubQueryColumn1")).from("SubTable"); 138 | 139 | QueryBuilder builder = new QueryBuilder(); 140 | builder.select("MyColumn1") 141 | .from("MyTable") 142 | .whereAnd( 143 | Criteria.equals("MyColumn1", 1) 144 | .and(Criteria.in("MyColumn2", new Object[] { 1, 2, 3 })) 145 | .or(Criteria.greaterThan(Projection.subQuery(subQuery2), 5)) 146 | .and(Criteria.exists(subQuery)) 147 | ); 148 | 149 | These are all the methods provided by the Criteria class: 150 | 151 | #### NULL Operators 152 | 153 | - isNull 154 | - notIsNull 155 | 156 | #### Basic operators 157 | Basic operator for strings, numbers and dates. 158 | 159 | When passing a LocalDate or LocalDateTime as parameter, these operators will cast the database column to DATE or DATETIME accordingly. 160 | 161 | When passing a Projection as a parameter these operators will not parameterize this value and use the Projection directly (this is useful for creating a criteria that compares two columns, e.g. SELECT MyColumn3 FROM MyTable WHERE *MyColumn1 = MyColumn2* ) 162 | 163 | - equals 164 | - notEquals 165 | - greaterThan 166 | - lesserThan 167 | - greaterThanOrEqual 168 | - lesserThanOrEqual 169 | 170 | #### Between operators 171 | 172 | - between (e.g. MyColumn1 BETWEEN 5 AND 7) 173 | - valueBetween (e.g. 5 BETWEEN MyColumn1 AND MyColumn2) 174 | 175 | #### String operators 176 | These are used to create LIKE criterias. 177 | 178 | - startsWith (e.g. LIKE 'test%') 179 | - notStartsWith (e.g. NOT LIKE 'test%') 180 | - endsWith (e.g. LIKE '%test') 181 | - notEndsWith (e.g. NOT LIKE '%test') 182 | - contains (e.g. LIKE '%test%') 183 | - notContains (e.g. NOT LIKE '%test%') 184 | 185 | #### IN operators 186 | 187 | - in 188 | - notIn 189 | 190 | #### EXISTS operators (sub-queries only) 191 | 192 | - exists 193 | - notExists 194 | 195 | #### Logical operators 196 | 197 | - or 198 | - and 199 | 200 | ### Group By and Order By 201 | 202 | // Group by a column 203 | .groupBy("MyColumn1", "MyColumn2") 204 | 205 | // Group by - projections 206 | .groupBy(Projection.column("MyColumn1"), Projection.column("MyColumn2")) 207 | 208 | //Order by ascending 209 | .orderByAscending("MyColumn1", "MyColumn2") 210 | 211 | //Order by ascending - projections 212 | .orderByAscending(Projection.column("MyColumn1"), Projection.column("MyColumn2")) 213 | 214 | //Order by descending 215 | .orderByDescending("MyColumn1", "MyColumn2"); 216 | 217 | //Order by descending - projections 218 | .orderByDescending(Projection.column("MyColumn1"), Projection.column("MyColumn2")) 219 | 220 | //Order by ignoring case 221 | .orderByAscendingIgnoreCase("MyColumn1") 222 | .orderByDescendingIgnoreCase("MyColumn1") 223 | 224 | //Order by ignoring case - projections 225 | .orderByAscendingIgnoreCase(Projection.column("MyColumn1")) 226 | .orderByDescendingIgnoreCase(Projection.column("MyColumn1")) 227 | 228 | // Remove all group by 229 | .clearGroupBy() 230 | 231 | // Remove all order by 232 | .clearOrderBy() 233 | 234 | ### Limit and offset AKA Take and Skip AKA paged queries 235 | 236 | QueryBuilder builder = new QueryBuilder(); 237 | builder.select("MyColumn1") 238 | .from("MyTable1") 239 | .skip(10) 240 | .take(100); 241 | 242 | ### Union 243 | When using UNION the ORDER BY clause, limit and offset of the union queries will be ignored. Only the ORDER BY clause, limit and offset of the root query will be considered (see example below) 244 | 245 | QueryBuilder builder1 = new QueryBuilder(); 246 | builder1.select("MyColumn1") 247 | .from("MyTable1") 248 | .orderByAscending("MyColumn1") // this WILL be used 249 | .skip(10) // this WILL be used 250 | .take(20); // this WILL be used 251 | 252 | QueryBuilder builder2 = new QueryBuilder(); 253 | builder2.select("MyColumn2") 254 | .from("MyTable2") 255 | .orderByAscending("MyColumn2") // this WILL NOT be used 256 | .skip(10) // this WILL NOT be used 257 | .take(20); // this WILL NOT be used; 258 | 259 | QueryBuilder builder3 = new QueryBuilder(); 260 | builder3.select("MyColumn3") 261 | .from("MyTable3") 262 | .orderByAscending("MyColumn3") // this WILL NOT be used 263 | .skip(10) // this WILL NOT be used 264 | .take(20); // this WILL NOT be used; 265 | 266 | builder1.union(builder2).unionAll(builder3); 267 | 268 | SQLiteDatabase db = getDB(); 269 | db.rawQuery(builder.build(), builder.buildParameters()); 270 | 271 | -------------------------------------------------------------------------------- /query-builder-core/src/main/java/com.reinaldoarrosi.android.querybuilder/sqlite/QueryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.reinaldoarrosi.android.querybuilder.sqlite; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.joda.time.LocalDate; 7 | import org.joda.time.LocalDateTime; 8 | import org.joda.time.format.DateTimeFormat; 9 | import org.joda.time.format.DateTimeFormatter; 10 | 11 | import com.reinaldoarrosi.android.querybuilder.Utils; 12 | import com.reinaldoarrosi.android.querybuilder.sqlite.criteria.Criteria; 13 | import com.reinaldoarrosi.android.querybuilder.sqlite.from.From; 14 | import com.reinaldoarrosi.android.querybuilder.sqlite.order.Order; 15 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.AliasedProjection; 16 | import com.reinaldoarrosi.android.querybuilder.sqlite.projection.Projection; 17 | 18 | 19 | public class QueryBuilder { 20 | private List projections; 21 | private From from; 22 | private Criteria criteria; 23 | private List groupBy; 24 | private List orderBy; 25 | private int skip; 26 | private int take; 27 | private boolean distinct; 28 | 29 | private List unionQueries; 30 | private boolean unionAll; 31 | 32 | private DateTimeFormatter dateFormat; 33 | private DateTimeFormatter dateTimeFormat; 34 | 35 | public QueryBuilder() { 36 | this(QueryBuildConfiguration.current().getDateFormat(), QueryBuildConfiguration.current().getDateTimeFormat()); 37 | } 38 | 39 | public QueryBuilder(String dateFormat, String dateTimeFormat) { 40 | this(DateTimeFormat.forPattern(dateFormat), DateTimeFormat.forPattern(dateTimeFormat)); 41 | } 42 | 43 | public QueryBuilder(DateTimeFormatter dateFormat, DateTimeFormatter dateTimeFormat) { 44 | projections = new ArrayList(); 45 | from = null; 46 | criteria = null; 47 | groupBy = new ArrayList(); 48 | orderBy = new ArrayList(); 49 | skip = -1; 50 | take = -1; 51 | distinct = false; 52 | 53 | unionQueries = new ArrayList(); 54 | unionAll = false; 55 | 56 | this.dateFormat = dateFormat; 57 | this.dateTimeFormat = dateTimeFormat; 58 | } 59 | 60 | public QueryBuilder withDateFormat(String format) { 61 | return withDateFormat(DateTimeFormat.forPattern(format)); 62 | } 63 | 64 | public QueryBuilder withDateFormat(DateTimeFormatter format) { 65 | this.dateFormat = format; 66 | return this; 67 | } 68 | 69 | public QueryBuilder withDateTimeFormat(String format) { 70 | return withDateTimeFormat(DateTimeFormat.forPattern(format)); 71 | } 72 | 73 | public QueryBuilder withDateTimeFormat(DateTimeFormatter format) { 74 | this.dateTimeFormat = format; 75 | return this; 76 | } 77 | 78 | public QueryBuilder select(String... columns) { 79 | if(columns == null) 80 | return this; 81 | 82 | return select(Utils.buildColumnProjections(columns)); 83 | } 84 | 85 | public QueryBuilder select(Projection... projections) { 86 | if(projections == null) 87 | return this; 88 | 89 | for (int i = 0; i < projections.length; i++) { 90 | this.projections.add(projections[i]); 91 | } 92 | 93 | return this; 94 | } 95 | 96 | public QueryBuilder from(String table) { 97 | return from(From.table(table)); 98 | } 99 | 100 | public QueryBuilder from(QueryBuilder subQuery) { 101 | return from(From.subQuery(subQuery)); 102 | } 103 | 104 | public QueryBuilder from(From from) { 105 | if(from != null) 106 | this.from = from; 107 | 108 | return this; 109 | } 110 | 111 | public QueryBuilder whereAnd(Criteria criteria) { 112 | if(criteria != null) { 113 | if(this.criteria == null) 114 | this.criteria = criteria; 115 | else 116 | this.criteria = this.criteria.and(criteria); 117 | } 118 | 119 | return this; 120 | } 121 | 122 | public QueryBuilder whereOr(Criteria criteria) { 123 | if(criteria != null) { 124 | if(this.criteria == null) 125 | this.criteria = criteria; 126 | else 127 | this.criteria = this.criteria.or(criteria); 128 | } 129 | 130 | return this; 131 | } 132 | 133 | public QueryBuilder groupBy(String... columns) { 134 | if(columns == null) 135 | return this; 136 | 137 | return groupBy(Utils.buildColumnProjections(columns)); 138 | } 139 | 140 | public QueryBuilder groupBy(Projection... projections) { 141 | if(projections == null) 142 | return this; 143 | 144 | for (int i = 0; i < projections.length; i++) { 145 | this.groupBy.add(projections[i]); 146 | } 147 | 148 | return this; 149 | } 150 | 151 | public QueryBuilder clearGroupBy() { 152 | this.groupBy.clear(); 153 | return this; 154 | } 155 | 156 | public QueryBuilder orderByAscending(String... columns) { 157 | if(columns == null) 158 | return this; 159 | 160 | return orderByAscending(Utils.buildColumnProjections(columns)); 161 | } 162 | 163 | public QueryBuilder orderByAscending(Projection... projections) { 164 | if(projections == null) 165 | return this; 166 | 167 | for (int i = 0; i < projections.length; i++) { 168 | this.orderBy.add(Order.orderByAscending(projections[i])); 169 | } 170 | 171 | return this; 172 | } 173 | 174 | public QueryBuilder orderByDescending(String... columns) { 175 | if(columns == null) 176 | return this; 177 | 178 | return orderByDescending(Utils.buildColumnProjections(columns)); 179 | } 180 | 181 | public QueryBuilder orderByDescending(Projection... projections) { 182 | if(projections == null) 183 | return this; 184 | 185 | for (int i = 0; i < projections.length; i++) { 186 | this.orderBy.add(Order.orderByDescending(projections[i])); 187 | } 188 | 189 | return this; 190 | } 191 | 192 | public QueryBuilder orderByAscendingIgnoreCase(String... columns) { 193 | if(columns == null) 194 | return this; 195 | 196 | return orderByAscendingIgnoreCase(Utils.buildColumnProjections(columns)); 197 | } 198 | 199 | public QueryBuilder orderByAscendingIgnoreCase(Projection... projections) { 200 | if(projections == null) 201 | return this; 202 | 203 | for (int i = 0; i < projections.length; i++) { 204 | this.orderBy.add(Order.orderByAscendingIgnoreCase(projections[i])); 205 | } 206 | 207 | return this; 208 | } 209 | 210 | public QueryBuilder orderByDescendingIgnoreCase(String... columns) { 211 | if(columns == null) 212 | return this; 213 | 214 | return orderByDescendingIgnoreCase(Utils.buildColumnProjections(columns)); 215 | } 216 | 217 | public QueryBuilder orderByDescendingIgnoreCase(Projection... projections) { 218 | if(projections == null) 219 | return this; 220 | 221 | for (int i = 0; i < projections.length; i++) { 222 | this.orderBy.add(Order.orderByDescendingIgnoreCase(projections[i])); 223 | } 224 | 225 | return this; 226 | } 227 | 228 | public QueryBuilder clearOrderBy() { 229 | this.orderBy.clear(); 230 | return this; 231 | } 232 | 233 | public QueryBuilder skip(int skip) { 234 | this.skip = skip; 235 | return this; 236 | } 237 | 238 | public QueryBuilder skipNone() { 239 | this.skip = -1; 240 | return this; 241 | } 242 | 243 | public QueryBuilder take(int take) { 244 | this.take = take; 245 | return this; 246 | } 247 | 248 | public QueryBuilder takeAll() { 249 | this.take = -1; 250 | return this; 251 | } 252 | 253 | public QueryBuilder distinct() { 254 | this.distinct = true; 255 | return this; 256 | } 257 | 258 | public QueryBuilder notDistinct() { 259 | this.distinct = false; 260 | return this; 261 | } 262 | 263 | public QueryBuilder union(QueryBuilder query) { 264 | query.unionAll = false; 265 | unionQueries.add(query); 266 | 267 | return this; 268 | } 269 | 270 | public QueryBuilder unionAll(QueryBuilder query) { 271 | query.unionAll = true; 272 | unionQueries.add(query); 273 | 274 | return this; 275 | } 276 | 277 | public String build() { 278 | StringBuilder sb = new StringBuilder(); 279 | 280 | buildSelectClause(sb); 281 | 282 | buildFromClause(sb); 283 | 284 | buildWhereClause(sb); 285 | 286 | buildGroupByClause(sb); 287 | 288 | buildUnionClause(sb); 289 | 290 | buildOrderByClause(sb); 291 | 292 | buildTakeClause(sb); 293 | 294 | buildSkipClause(sb); 295 | 296 | return sb.toString(); 297 | } 298 | 299 | private void buildSkipClause(StringBuilder sb) { 300 | if(skip > 0) { 301 | sb.append(" OFFSET "); 302 | sb.append(skip); 303 | } 304 | } 305 | 306 | private void buildTakeClause(StringBuilder sb) { 307 | if(take > 0) { 308 | sb.append(" LIMIT "); 309 | sb.append(take); 310 | } 311 | } 312 | 313 | private void buildOrderByClause(StringBuilder sb) { 314 | if(orderBy.size() > 0) { 315 | sb.append(" ORDER BY "); 316 | 317 | for (Order o : orderBy) { 318 | sb.append(o.build()); 319 | sb.append(", "); 320 | } 321 | 322 | sb.setLength(sb.length() - 2); // removes the ", " from the last entry 323 | } 324 | } 325 | 326 | private void buildUnionClause(StringBuilder sb) { 327 | List oldOrderBy; 328 | int oldSkip; 329 | int oldTake; 330 | 331 | for (QueryBuilder union : unionQueries) { 332 | sb.append(union.unionAll ? " UNION ALL " : " UNION "); 333 | 334 | oldOrderBy = union.orderBy; 335 | oldSkip = union.skip; 336 | oldTake = union.take; 337 | 338 | union.orderBy = new ArrayList(); 339 | union.skip = -1; 340 | union.take = -1; 341 | 342 | sb.append(union.build()); 343 | 344 | union.orderBy = oldOrderBy; 345 | union.skip = oldSkip; 346 | union.take = oldTake; 347 | } 348 | } 349 | 350 | private void buildGroupByClause(StringBuilder sb) { 351 | if(groupBy.size() > 0) { 352 | sb.append(" GROUP BY "); 353 | 354 | for (Projection p : groupBy) { 355 | if(p instanceof AliasedProjection) 356 | p = ((AliasedProjection)p).removeAlias(); 357 | 358 | sb.append(p.build()); 359 | sb.append(", "); 360 | } 361 | 362 | sb.setLength(sb.length() - 2); // removes the ", " from the last entry 363 | } 364 | } 365 | 366 | private void buildWhereClause(StringBuilder sb) { 367 | if(criteria != null) { 368 | sb.append("WHERE "); 369 | sb.append(criteria.build()); 370 | } 371 | } 372 | 373 | private void buildFromClause(StringBuilder sb) { 374 | if(from != null) { 375 | sb.append("FROM "); 376 | sb.append(from.build()); 377 | sb.append(" "); 378 | } 379 | } 380 | 381 | private void buildSelectClause(StringBuilder sb) { 382 | sb.append("SELECT "); 383 | 384 | if(distinct) 385 | sb.append("DISTINCT "); 386 | 387 | if(projections.size() <= 0) { 388 | sb.append("*"); 389 | } else { 390 | for (Projection p : projections) { 391 | sb.append(p.build()); 392 | sb.append(", "); 393 | } 394 | 395 | sb.setLength(sb.length() - 2); // removes the ", " from the last entry 396 | } 397 | 398 | sb.append(" "); 399 | } 400 | 401 | public List buildParameters() { 402 | List ret = new ArrayList(); 403 | List oldOrderBy; 404 | int oldSkip; 405 | int oldTake; 406 | 407 | buildSelectClauseParameters(ret); 408 | 409 | if(from != null) 410 | ret.addAll(from.buildParameters()); 411 | 412 | if(criteria != null) 413 | ret.addAll(criteria.buildParameters()); 414 | 415 | for (Projection p : groupBy) { 416 | ret.addAll(p.buildParameters()); 417 | } 418 | 419 | for (QueryBuilder union : unionQueries) { 420 | oldOrderBy = union.orderBy; 421 | oldSkip = union.skip; 422 | oldTake = union.take; 423 | 424 | union.orderBy = new ArrayList(); 425 | union.skip = -1; 426 | union.take = -1; 427 | 428 | ret.addAll(union.buildParameters()); 429 | 430 | union.orderBy = oldOrderBy; 431 | union.skip = oldSkip; 432 | union.take = oldTake; 433 | } 434 | 435 | for (Order o : orderBy) { 436 | ret.addAll(o.buildParameters()); 437 | } 438 | 439 | preProcessDateValues(ret); 440 | return ret; 441 | } 442 | 443 | private void buildSelectClauseParameters(List ret) { 444 | for (Projection p : projections) { 445 | ret.addAll(p.buildParameters()); 446 | } 447 | } 448 | 449 | public String toDebugSqlString() { 450 | List parameters = buildParameters(); 451 | String saida = build(); 452 | 453 | if (parameters != null) { 454 | for (Object p : parameters) { 455 | if (p == null) 456 | saida = saida.replaceFirst("\\?", "NULL"); 457 | else 458 | saida = saida.replaceFirst("\\?", escapeSQLString(Utils.toString(p))); 459 | } 460 | } 461 | 462 | return saida; 463 | } 464 | 465 | private void preProcessDateValues(List values) { 466 | Object value; 467 | int index = 0; 468 | 469 | while(index < values.size()) { 470 | value = values.get(index); 471 | 472 | if(value instanceof LocalDateTime) { 473 | values.remove(index); 474 | values.add(index, Utils.dateToString(((LocalDateTime)value), dateTimeFormat)); 475 | } else if(value instanceof LocalDate) { 476 | values.remove(index); 477 | values.add(index, Utils.dateToString(((LocalDate)value), dateFormat)); 478 | } 479 | 480 | index++; 481 | } 482 | } 483 | 484 | private String escapeSQLString(String sqlString) { 485 | // Copied from Android source: DatabaseUtils.appendEscapedSQLString 486 | StringBuilder sb = new StringBuilder(); 487 | sb.append('\''); 488 | 489 | if (sqlString.indexOf('\'') != -1) { 490 | int length = sqlString.length(); 491 | for (int i = 0; i < length; i++) { 492 | char c = sqlString.charAt(i); 493 | if (c == '\'') { 494 | sb.append('\''); 495 | } 496 | sb.append(c); 497 | } 498 | } else 499 | sb.append(sqlString); 500 | 501 | sb.append('\''); 502 | return sb.toString(); 503 | } 504 | } 505 | --------------------------------------------------------------------------------