├── screenshot └── cover.png ├── src ├── main │ └── java │ │ ├── org │ │ └── sql2o │ │ │ ├── tools │ │ │ ├── package-info.java │ │ │ ├── ClassUtils.java │ │ │ ├── UnderscoreToCamelCase.java │ │ │ ├── IOUtils.java │ │ │ ├── FeatureDetector.java │ │ │ └── AbstractCache.java │ │ │ ├── data │ │ │ ├── package-info.java │ │ │ ├── Column.java │ │ │ ├── LazyTable.java │ │ │ ├── Table.java │ │ │ └── TableResultSetIterator.java │ │ │ ├── reflection │ │ │ ├── package-info.java │ │ │ ├── FieldGetterFactory.java │ │ │ ├── MethodGetterFactory.java │ │ │ ├── Setter.java │ │ │ ├── ObjectConstructor.java │ │ │ ├── Getter.java │ │ │ ├── ReflectionFieldGetterFactory.java │ │ │ ├── ReflectionMethodGetterFactory.java │ │ │ ├── ObjectConstructorFactory.java │ │ │ ├── FieldSetterFactory.java │ │ │ ├── MethodSetterFactory.java │ │ │ ├── ReflectionFieldSetterFactory.java │ │ │ ├── ReflectionMethodSetterFactory.java │ │ │ ├── FieldGetter.java │ │ │ ├── FieldSetter.java │ │ │ ├── ReflectionObjectConstructorFactory.java │ │ │ ├── MethodGetter.java │ │ │ ├── MethodSetter.java │ │ │ ├── FactoryFacade.java │ │ │ └── PojoIntrospector.java │ │ │ ├── converters │ │ │ ├── ConvertersProvider.java │ │ │ ├── ConverterBase.java │ │ │ ├── EnumConverterFactory.java │ │ │ ├── Converter.java │ │ │ ├── ConverterException.java │ │ │ ├── DateConverter.java │ │ │ ├── ByteConverter.java │ │ │ ├── LongConverter.java │ │ │ ├── FloatConverter.java │ │ │ ├── ShortConverter.java │ │ │ ├── UUIDConverter.java │ │ │ ├── DoubleConverter.java │ │ │ ├── IntegerConverter.java │ │ │ ├── InputStreamConverter.java │ │ │ ├── BigDecimalConverter.java │ │ │ ├── OracleDateConverter.java │ │ │ ├── java8 │ │ │ │ ├── LocalDateConverter.java │ │ │ │ └── LocalDateTimeConverter.java │ │ │ ├── OracleUUIDConverter.java │ │ │ ├── BooleanConverter.java │ │ │ ├── AbstractDateConverter.java │ │ │ ├── NumberConverter.java │ │ │ ├── StringConverter.java │ │ │ ├── ByteArrayConverter.java │ │ │ └── DefaultEnumConverterFactory.java │ │ │ ├── ResultSetHandler.java │ │ │ ├── ResultSetHandlerFactory.java │ │ │ ├── connectionsources │ │ │ ├── ConnectionSource.java │ │ │ └── DataSourceConnectionSource.java │ │ │ ├── StatementRunnable.java │ │ │ ├── StatementRunnableWithResult.java │ │ │ ├── quirks │ │ │ ├── PostgresQuirks.java │ │ │ ├── PostgresQuirksProvider.java │ │ │ ├── QuirksProvider.java │ │ │ ├── OracleQuirksProvider.java │ │ │ ├── Db2QuirksProvider.java │ │ │ ├── Db2Quirks.java │ │ │ ├── Quirks.java │ │ │ ├── QuirksDetector.java │ │ │ └── OracleQuirks.java │ │ │ ├── ResultSetIterable.java │ │ │ ├── Sql2oException.java │ │ │ ├── DelegatingResultSetHandler.java │ │ │ ├── ResultSetHandlerFactoryBuilder.java │ │ │ ├── JndiDataSource.java │ │ │ ├── PojoResultSetIterator.java │ │ │ ├── DefaultResultSetHandlerFactoryBuilder.java │ │ │ ├── extensions │ │ │ └── postgres │ │ │ │ └── converters │ │ │ │ └── JSONConverter.java │ │ │ ├── GenericDatasource.java │ │ │ └── ResultSetIteratorBase.java │ │ └── com │ │ └── hellokaton │ │ └── anima │ │ ├── enums │ │ ├── OrderBy.java │ │ ├── ErrorCode.java │ │ ├── DMLType.java │ │ └── SupportedType.java │ │ ├── dialect │ │ ├── DB2Dialect.java │ │ ├── SQLiteDialect.java │ │ ├── MySQLDialect.java │ │ ├── PostgreSQLDialect.java │ │ ├── OracleDialect.java │ │ ├── SqlServer2012Dialect.java │ │ └── SqlServerDialect.java │ │ ├── core │ │ ├── functions │ │ │ └── TypeFunction.java │ │ ├── Joins.java │ │ ├── dml │ │ │ ├── Update.java │ │ │ ├── Delete.java │ │ │ └── Select.java │ │ ├── ResultKey.java │ │ ├── JoinParam.java │ │ ├── SQLParams.java │ │ ├── Atomic.java │ │ └── ResultList.java │ │ ├── annotation │ │ ├── EnumMapping.java │ │ ├── Table.java │ │ ├── Ignore.java │ │ └── Column.java │ │ ├── page │ │ └── PageRow.java │ │ ├── exception │ │ └── AnimaException.java │ │ ├── utils │ │ ├── Functions.java │ │ └── TwoFormInflector.java │ │ └── Model.java └── test │ ├── java │ ├── org │ │ └── sql2o │ │ │ ├── quirks │ │ │ ├── H2Quirks.java │ │ │ └── H2QuirksProvider.java │ │ │ ├── pojos │ │ │ ├── SuperPojo.java │ │ │ ├── BigDecimalPojo.java │ │ │ ├── StringConversionPojo.java │ │ │ ├── EntityWithPrivateFields.java │ │ │ ├── Multi1.java │ │ │ ├── ComplexEntity.java │ │ │ └── Multi2.java │ │ │ ├── issues │ │ │ ├── pojos │ │ │ │ ├── KeyValueEntity.java │ │ │ │ └── Issue1Pojo.java │ │ │ └── H2Tests.java │ │ │ ├── reflect │ │ │ ├── UnsafeFieldGetterFactoryTest.java │ │ │ ├── ReflectionFieldGetterFactoryTest.java │ │ │ ├── ReflectionMethodGetterFactoryTest.java │ │ │ ├── UnsafeConstructorFactoryTest.java │ │ │ ├── MethodAccessorsGeneratorMethodGetterFactoryTest.java │ │ │ ├── ReflectionFieldSetterFactoryTest.java │ │ │ ├── ReflectionMethodSetterFactoryTest.java │ │ │ ├── ReflectionConstructorFactoryTest.java │ │ │ ├── MethodAccessorsGeneratorMethodSetterFactoryTest.java │ │ │ ├── UnsafeFieldSetterFactoryTest.java │ │ │ ├── AbstractObjectConstructorFactoryTest.java │ │ │ ├── MethodAccessorsGeneratorObjectConstructorFactoryTest.java │ │ │ ├── AbstractFieldGetterFactoryTest.java │ │ │ ├── ReadColumnAnnotationTest.java │ │ │ ├── AbstractFieldSetterFactoryTest.java │ │ │ ├── AbstractMethodGetterFactoryTest.java │ │ │ └── AbstractMethodSetterFactoryTest.java │ │ │ ├── User.java │ │ │ ├── Entity.java │ │ │ ├── tools │ │ │ └── UnderscoreToCamelCaseTests.java │ │ │ ├── QueryTest.java │ │ │ ├── ConnectionTransactionTest.java │ │ │ └── Sql2oDataSourceTest.java │ └── com │ │ └── hellokaton │ │ └── anima │ │ ├── enums │ │ ├── Gender.java │ │ └── VipLevel.java │ │ ├── mysql │ │ └── OrderInfoTest.java │ │ ├── model │ │ ├── Address.java │ │ ├── User.java │ │ ├── ZhuanJia.java │ │ ├── Person.java │ │ ├── UserDto.java │ │ └── OrderInfo.java │ │ ├── EnumTest.java │ │ ├── converter │ │ └── LevelConverter.java │ │ ├── DeleteTest.java │ │ ├── SaveTest.java │ │ ├── oracle │ │ └── OracleTest.java │ │ ├── sqlserver │ │ └── SqlServerTest.java │ │ ├── ExceptionTest.java │ │ ├── OtherTest.java │ │ ├── LambdaTest.java │ │ ├── UpdateTest.java │ │ ├── JoinTest.java │ │ ├── AnimaTest.java │ │ └── BaseTest.java │ └── resources │ └── logback-test.xml ├── .travis.yml └── .gitignore /screenshot/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/anima/HEAD/screenshot/cover.png -------------------------------------------------------------------------------- /src/main/java/org/sql2o/tools/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * internal tools. 3 | */ 4 | package org.sql2o.tools; -------------------------------------------------------------------------------- /src/main/java/org/sql2o/data/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides the model used by sql2o to represent a raw result set. 3 | */ 4 | package org.sql2o.data; -------------------------------------------------------------------------------- /src/test/java/org/sql2o/quirks/H2Quirks.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.quirks; 2 | 3 | /** 4 | * Created by lars on 10.08.15. 5 | */ 6 | public class H2Quirks extends NoQuirks { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides the internal functionality used by sql2o to accomplish the automatic row to property mapping. 3 | */ 4 | package org.sql2o.reflection; -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/enums/OrderBy.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.enums; 2 | 3 | /** 4 | * @author biezhi 5 | * @date 2018/3/19 6 | */ 7 | public enum OrderBy { 8 | 9 | ASC, DESC 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/enums/Gender.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.enums; 2 | 3 | /** 4 | * @author biezhi 5 | * @date 2018/6/2 6 | */ 7 | public enum Gender { 8 | 9 | MALE, FEMALE 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/DB2Dialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | /** 4 | * DB2 dialect 5 | * 6 | * @author biezhi 7 | * @date 2018/3/17 8 | */ 9 | public class DB2Dialect extends OracleDialect { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/FieldGetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public interface FieldGetterFactory { 9 | Getter newGetter(Field field); 10 | } -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/SQLiteDialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | /** 4 | * SQLite dialect 5 | * 6 | * @author biezhi 7 | * @date 2018/3/17 8 | */ 9 | public class SQLiteDialect extends MySQLDialect { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/MethodGetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public interface MethodGetterFactory { 9 | Getter newGetter(Method method); 10 | } -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/functions/TypeFunction.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.core.functions; 2 | 3 | import java.io.Serializable; 4 | import java.util.function.Function; 5 | 6 | @FunctionalInterface 7 | public interface TypeFunction extends Serializable, Function { 8 | 9 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | notifications: 7 | email: false 8 | 9 | sudo: false 10 | 11 | before_install: 12 | - export TZ='Asia/Shanghai' 13 | 14 | script: "mvn clean cobertura:cobertura" 15 | 16 | after_success: 17 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/ConvertersProvider.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 4/24/14 8 | * Time: 12:53 AM 9 | */ 10 | public interface ConvertersProvider { 11 | void fill(Map, Converter> mapToFill); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/ConverterBase.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * @author aldenquimby@gmail.com 5 | * @since 4/6/14 6 | */ 7 | abstract class ConverterBase implements Converter { 8 | 9 | public Object toDatabaseParam(T val) { 10 | return val; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/EnumConverterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into an {@link Enum}. 5 | */ 6 | public interface EnumConverterFactory { 7 | 8 | Converter newConverter(Class enumClass); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/SuperPojo.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 12/6/11 7 | * Time: 12:45 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class SuperPojo extends EntityWithPrivateFields { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/ResultSetHandler.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | /** 7 | * User: dimzon 8 | * Date: 4/7/14 9 | * Time: 12:01 AM 10 | */ 11 | public interface ResultSetHandler { 12 | T handle(ResultSet resultSet) throws SQLException; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/Setter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | /** 4 | * The Setter interface is used by sql2o to set property values when doing automatic column to property mapping 5 | */ 6 | public interface Setter { 7 | 8 | void setProperty(Object obj, Object value); 9 | Class getType(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ObjectConstructor.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: dimzon 6 | * Date: 4/6/14 7 | * Time: 1:26 AM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public interface ObjectConstructor { 11 | Object newInstance(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/Getter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | /** 4 | * The Getter interface is used by sql2o to get property values when doing automatic column to property mapping 5 | * 6 | * @author mdelapenya 7 | */ 8 | public interface Getter { 9 | 10 | Object getProperty(Object obj); 11 | 12 | Class getType(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ReflectionFieldGetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public class ReflectionFieldGetterFactory implements FieldGetterFactory { 9 | public Getter newGetter(Field field) { 10 | return new FieldGetter(field); 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/Joins.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.core; 2 | 3 | import com.hellokaton.anima.Model; 4 | 5 | /** 6 | * @author biezhi 7 | * @date 2018/4/16 8 | */ 9 | public class Joins { 10 | 11 | public static JoinParam with(Class joinModel) { 12 | return new JoinParam(joinModel); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ReflectionMethodGetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public class ReflectionMethodGetterFactory implements MethodGetterFactory { 9 | public Getter newGetter(Method method) { 10 | return new MethodGetter(method); 11 | } 12 | } -------------------------------------------------------------------------------- /src/test/java/org/sql2o/issues/pojos/KeyValueEntity.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.issues.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 10/23/11 7 | * Time: 7:09 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class KeyValueEntity { 11 | 12 | public int key; 13 | public String value; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ObjectConstructorFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: dimzon 6 | * Date: 4/6/14 7 | * Time: 1:27 AM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public interface ObjectConstructorFactory { 11 | ObjectConstructor newConstructor(Class cls); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/ResultSetHandlerFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import java.sql.ResultSetMetaData; 4 | import java.sql.SQLException; 5 | 6 | /** 7 | * User: dimzon 8 | * Date: 4/7/14 9 | * Time: 12:02 AM 10 | */ 11 | public interface ResultSetHandlerFactory { 12 | ResultSetHandler newResultSetHandler(ResultSetMetaData resultSetMetaData) throws SQLException; 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/UnsafeFieldGetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.UnsafeFieldGetterFactory; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public class UnsafeFieldGetterFactoryTest extends AbstractFieldGetterFactoryTest { 9 | public UnsafeFieldGetterFactoryTest() { 10 | super(new UnsafeFieldGetterFactory()); 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/FieldSetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: dimzon 8 | * Date: 4/6/14 9 | * Time: 12:39 AM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public interface FieldSetterFactory { 13 | Setter newSetter(Field field); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/MethodSetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: dimzon 8 | * Date: 4/6/14 9 | * Time: 12:42 AM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public interface MethodSetterFactory { 13 | Setter newSetter(Method method); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/Converter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Represents a converter. 5 | */ 6 | public interface Converter { 7 | 8 | /** 9 | * Conversion from SQL to Java. 10 | */ 11 | T convert(Object val) throws ConverterException; 12 | 13 | /** 14 | * Conversion from Java to SQL. 15 | */ 16 | Object toDatabaseParam(T val); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/ReflectionFieldGetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.ReflectionFieldGetterFactory; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public class ReflectionFieldGetterFactoryTest extends AbstractFieldGetterFactoryTest { 9 | public ReflectionFieldGetterFactoryTest() { 10 | super(new ReflectionFieldGetterFactory()); 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/connectionsources/ConnectionSource.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.connectionsources; 2 | 3 | import java.sql.SQLException; 4 | 5 | /** 6 | * An abstraction layer for providing jdbc connection 7 | * to use from {@link org.sql2o.Connection} 8 | * Created by nickl on 09.01.17. 9 | */ 10 | public interface ConnectionSource { 11 | 12 | java.sql.Connection getConnection() throws SQLException; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/issues/pojos/Issue1Pojo.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.issues.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 10/17/11 7 | * Time: 9:08 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class Issue1Pojo { 11 | 12 | public int val; 13 | 14 | public void setVal(int val) { 15 | this.val = val + 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/ReflectionMethodGetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.ReflectionMethodGetterFactory; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public class ReflectionMethodGetterFactoryTest extends AbstractMethodGetterFactoryTest { 9 | public ReflectionMethodGetterFactoryTest() { 10 | super(new ReflectionMethodGetterFactory()); 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/annotation/EnumMapping.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.TYPE}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface EnumMapping { 11 | 12 | String value(); 13 | 14 | } -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/BigDecimalPojo.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: lars 8 | * Date: 11/15/11 9 | * Time: 10:18 AM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public class BigDecimalPojo { 13 | public int id; 14 | 15 | public BigDecimal val1; 16 | 17 | public BigDecimal val2; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/UnsafeConstructorFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.UnsafeFieldSetterFactory; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 4/9/14 8 | * Time: 10:16 PM 9 | */ 10 | public class UnsafeConstructorFactoryTest extends AbstractObjectConstructorFactoryTest { 11 | public UnsafeConstructorFactoryTest() { 12 | super(new UnsafeFieldSetterFactory()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/MethodAccessorsGeneratorMethodGetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.MethodAccessorsGenerator; 4 | 5 | /** 6 | * @author mdelapenya 7 | */ 8 | public class MethodAccessorsGeneratorMethodGetterFactoryTest extends AbstractMethodGetterFactoryTest { 9 | public MethodAccessorsGeneratorMethodGetterFactoryTest() { 10 | super(new MethodAccessorsGenerator()); 11 | } 12 | } -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/ReflectionFieldSetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.ReflectionFieldSetterFactory; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 4/9/14 8 | * Time: 9:44 PM 9 | */ 10 | public class ReflectionFieldSetterFactoryTest extends AbstractFieldSetterFactoryTest { 11 | public ReflectionFieldSetterFactoryTest() { 12 | super(new ReflectionFieldSetterFactory()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/StringConversionPojo.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 12/6/11 7 | * Time: 10:14 AM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class StringConversionPojo { 11 | 12 | public Integer val1; 13 | public long val2; 14 | public Integer val3; 15 | public int val4; 16 | public Double val5; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/ReflectionMethodSetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.ReflectionMethodSetterFactory; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 4/9/14 8 | * Time: 10:24 PM 9 | */ 10 | public class ReflectionMethodSetterFactoryTest extends AbstractMethodSetterFactoryTest { 11 | public ReflectionMethodSetterFactoryTest() { 12 | super(new ReflectionMethodSetterFactory()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/ReflectionConstructorFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.ReflectionObjectConstructorFactory; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 4/9/14 8 | * Time: 10:15 PM 9 | */ 10 | public class ReflectionConstructorFactoryTest extends AbstractObjectConstructorFactoryTest { 11 | public ReflectionConstructorFactoryTest() { 12 | super(new ReflectionObjectConstructorFactory()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/StatementRunnable.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | /** 4 | * Represents a method with a {@link Connection} and an optional argument. Implementations of this interface be used as 5 | * a parameter to one of the {@link Sql2o#runInTransaction(StatementRunnable) Sql2o.runInTransaction} overloads, to run 6 | * code safely in a transaction. 7 | */ 8 | public interface StatementRunnable { 9 | 10 | void run(Connection connection, Object argument) throws Throwable; 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/MethodAccessorsGeneratorMethodSetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.MethodAccessorsGenerator; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 4/9/14 8 | * Time: 10:25 PM 9 | */ 10 | public class MethodAccessorsGeneratorMethodSetterFactoryTest extends AbstractMethodSetterFactoryTest { 11 | public MethodAccessorsGeneratorMethodSetterFactoryTest() { 12 | super(new MethodAccessorsGenerator()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ReflectionFieldSetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: dimzon 8 | * Date: 4/6/14 9 | * Time: 12:40 AM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public class ReflectionFieldSetterFactory implements FieldSetterFactory { 13 | public Setter newSetter(Field field) { 14 | return new FieldSetter(field); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/enums/VipLevel.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.enums; 2 | 3 | import com.hellokaton.anima.annotation.EnumMapping; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | @EnumMapping("code") 8 | public enum VipLevel { 9 | 10 | VIP1(1, "初级会员"), 11 | VIP2(2, "高级会员"), 12 | VIP3(3, "至尊会员"); 13 | 14 | private int code; 15 | private String desc; 16 | 17 | VipLevel(int code, String desc) { 18 | this.code = code; 19 | this.desc = desc; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/ConverterException.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Represents an exception thrown from a converter. 5 | */ 6 | public class ConverterException extends Exception{ 7 | 8 | private static final long serialVersionUID = -6515158190992901520L; 9 | 10 | public ConverterException(String message) { 11 | super(message); 12 | } 13 | 14 | public ConverterException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ReflectionMethodSetterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: dimzon 8 | * Date: 4/6/14 9 | * Time: 12:43 AM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public class ReflectionMethodSetterFactory implements MethodSetterFactory { 13 | public Setter newSetter(Method method) { 14 | return new MethodSetter(method); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/StatementRunnableWithResult.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | /** 4 | * Represents a method with a {@link Connection} and an optional argument. Implementations of this interface be used as 5 | * a parameter to one of the {@link Sql2o#runInTransaction(StatementRunnableWithResult)} Sql2o.runInTransaction} overloads, 6 | * to run code safely in a transaction. 7 | */ 8 | public interface StatementRunnableWithResult { 9 | 10 | V run(Connection connection, Object argument) throws Throwable; 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/mysql/OrderInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.mysql; 2 | 3 | import com.hellokaton.anima.Anima; 4 | import com.hellokaton.anima.model.OrderInfo; 5 | 6 | import static com.hellokaton.anima.Anima.select; 7 | 8 | /** 9 | * @author biezhi 10 | * @date 2018/3/17 11 | */ 12 | public class OrderInfoTest { 13 | 14 | // @Test 15 | public void testQuery() { 16 | OrderInfo orderInfo = Anima.select().from(OrderInfo.class).one(); 17 | System.out.println(orderInfo); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/EntityWithPrivateFields.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 11/19/11 7 | * Time: 5:30 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class EntityWithPrivateFields { 11 | 12 | private int id; 13 | 14 | private String value; 15 | 16 | public int getId(){ 17 | return id; 18 | } 19 | 20 | public String getValue(){ 21 | return value; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/UnsafeFieldSetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.UnsafeFieldSetterFactory; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: dimzon 8 | * Date: 4/9/14 9 | * Time: 9:48 PM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public class UnsafeFieldSetterFactoryTest extends AbstractFieldSetterFactoryTest { 13 | public UnsafeFieldSetterFactoryTest() { 14 | super(new UnsafeFieldSetterFactory()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/User.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 5/18/11 7 | * Time: 8:53 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class User { 11 | 12 | public Integer id; 13 | public String name; 14 | public String text; 15 | private String email; 16 | 17 | public String getEmail() { 18 | return email; 19 | } 20 | 21 | public void setEmail(String email) { 22 | this.email = email; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/enums/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @author biezhi 8 | * @date 2018/3/16 9 | */ 10 | @Getter 11 | @AllArgsConstructor 12 | public enum ErrorCode { 13 | 14 | SQL2O_IS_NULL(1000, "Sql2o instance is not configured successfully, please check your database configuration :)"), 15 | FROM_NOT_NULL(1001, "from class cannot be null, please check :)"); 16 | 17 | private Integer code; 18 | private String msg; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/DateConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * Used by sql2o to convert a value from the database into a {@link Date}. 7 | */ 8 | public class DateConverter extends AbstractDateConverter { 9 | public static final DateConverter instance = new DateConverter(); 10 | 11 | public DateConverter() { 12 | super(Date.class); 13 | } 14 | 15 | @Override 16 | protected Date fromMilliseconds(long millisecond) { 17 | return new Date(millisecond); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/quirks/H2QuirksProvider.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.quirks; 2 | 3 | /** 4 | * Created by lars on 10.08.15. 5 | */ 6 | public class H2QuirksProvider implements QuirksProvider { 7 | 8 | @Override 9 | public Quirks provide() { 10 | return new H2Quirks(); 11 | } 12 | 13 | @Override 14 | public boolean isUsableForUrl(String url) { 15 | return url.startsWith("jdbc:h2"); 16 | } 17 | 18 | @Override 19 | public boolean isUsableForClass(String className) { 20 | return className.startsWith("org.h2"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/model/Address.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.model; 2 | 3 | import com.hellokaton.anima.Model; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * @author biezhi 11 | * @date 2018/3/19 12 | */ 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @EqualsAndHashCode(callSuper = false) 17 | public class Address extends Model { 18 | 19 | private Long orderId; 20 | private String city; 21 | private String street; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/Multi1.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 11/20/11 7 | * Time: 8:17 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class Multi1 { 11 | 12 | private Long id; 13 | private String value; 14 | 15 | public Long getId() { 16 | return id; 17 | } 18 | 19 | public String getValue() { 20 | return value; 21 | } 22 | 23 | public void setValue(String value) { 24 | this.value = value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/ComplexEntity.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 12/6/11 7 | * Time: 1:16 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class ComplexEntity { 11 | 12 | public int id; 13 | 14 | private EntityWithPrivateFields entity; 15 | 16 | public EntityWithPrivateFields getEntity() { 17 | return entity; 18 | } 19 | 20 | public void setEntity(EntityWithPrivateFields entity) { 21 | this.entity = entity; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/PostgresQuirks.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.quirks; 2 | 3 | import org.sql2o.converters.Converter; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * @author aldenquimby@gmail.com 9 | * @since 4/6/14 10 | */ 11 | public class PostgresQuirks extends NoQuirks { 12 | 13 | public PostgresQuirks() { 14 | super(); 15 | } 16 | 17 | public PostgresQuirks(Map, Converter> converters) { 18 | super(converters); 19 | } 20 | 21 | @Override 22 | public boolean returnGeneratedKeysByDefault() { 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/pojos/Multi2.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.pojos; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: lars 6 | * Date: 11/20/11 7 | * Time: 8:18 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class Multi2 { 11 | 12 | private int id; 13 | 14 | private String value2; 15 | 16 | public int getId() { 17 | return id; 18 | } 19 | 20 | public String getValue2() { 21 | return value2; 22 | } 23 | 24 | public void setValue2(String value2) { 25 | this.value2 = value2; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/ResultSetIterable.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import java.io.Closeable; 4 | 5 | /** 6 | * Iterable {@link java.sql.ResultSet}. Needs to be closeable, because allowing manual 7 | * iteration means it's impossible to know when to close the ResultSet and Connection. 8 | * 9 | * @author aldenquimby@gmail.com 10 | */ 11 | public interface ResultSetIterable extends Iterable, Closeable, AutoCloseable { 12 | // override close to not throw 13 | void close(); 14 | 15 | boolean isAutoCloseConnection(); 16 | void setAutoCloseConnection(boolean autoCloseConnection); 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/EnumTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.model.Person; 4 | import org.junit.Test; 5 | 6 | import java.util.List; 7 | 8 | import static com.hellokaton.anima.Anima.select; 9 | 10 | /** 11 | * @author biezhi 12 | * @date 2018/6/2 13 | */ 14 | public class EnumTest extends BaseTest { 15 | 16 | @Test 17 | public void testQueryEnum(){ 18 | System.out.println(Anima.select().from(Person.class).count()); 19 | List all = Anima.select().from(Person.class).all(); 20 | System.out.println(all); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/Sql2oException.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | /** 4 | * Represents an exception thrown by Sql2o. 5 | */ 6 | public class Sql2oException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -7941623550038122757L; 9 | 10 | public Sql2oException() { 11 | } 12 | 13 | public Sql2oException(String message) { 14 | super(message); 15 | } 16 | 17 | public Sql2oException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public Sql2oException(Throwable cause) { 22 | super(cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/PostgresQuirksProvider.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.quirks; 2 | 3 | /** 4 | * Created by lars on 28.10.14. 5 | */ 6 | public class PostgresQuirksProvider implements QuirksProvider { 7 | 8 | 9 | @Override 10 | public Quirks provide() { 11 | return new PostgresQuirks(); 12 | } 13 | 14 | @Override 15 | public boolean isUsableForUrl(String url) { 16 | return url.startsWith("jdbc:postgresql:"); 17 | } 18 | 19 | @Override 20 | public boolean isUsableForClass(String className) { 21 | return className.startsWith("org.postgresql."); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/model/User.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.model; 2 | 3 | import com.hellokaton.anima.Model; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @EqualsAndHashCode(callSuper = true) 13 | public class User extends Model { 14 | 15 | private Integer id; 16 | 17 | private String userName; 18 | 19 | private Integer age; 20 | 21 | public User(String userName, Integer age) { 22 | this.userName = userName; 23 | this.age = age; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/model/ZhuanJia.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.model; 2 | 3 | import com.hellokaton.anima.Model; 4 | import com.hellokaton.anima.annotation.Table; 5 | import lombok.Data; 6 | 7 | /** 8 | * 专家实体类 9 | */ 10 | @Table(name = "scott.uf_zjk") 11 | @Data 12 | public class ZhuanJia extends Model { 13 | 14 | private Integer id; 15 | 16 | private String zjxm;//姓名 17 | 18 | private String gzdw;//工作单位 19 | 20 | private String zw;//职级类型 21 | 22 | private String jszc;//技术职称 23 | 24 | private String zjlx;//专业领域 25 | 26 | private String sczy;//擅长专业 27 | 28 | private String szd;//所在地 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/model/Person.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.model; 2 | 3 | import com.hellokaton.anima.Model; 4 | import com.hellokaton.anima.enums.VipLevel; 5 | import com.hellokaton.anima.annotation.Column; 6 | import com.hellokaton.anima.enums.Gender; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | /** 12 | * @author biezhi 13 | * @date 2018/6/2 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class Person extends Model { 19 | 20 | private String name; 21 | 22 | @Column(name = "sex") 23 | private Gender gender; 24 | 25 | private VipLevel vipLevel; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/model/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.model; 2 | 3 | import com.hellokaton.anima.Model; 4 | import com.hellokaton.anima.annotation.Ignore; 5 | import com.hellokaton.anima.annotation.Table; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author biezhi 13 | * @date 2018/3/19 14 | */ 15 | @Table(name = "users") 16 | @Data 17 | @EqualsAndHashCode(callSuper=true) 18 | public class UserDto extends Model { 19 | 20 | private Integer id; 21 | 22 | private String userName; 23 | 24 | private Integer age; 25 | 26 | @Ignore 27 | private List orders; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/ByteConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into a {@link Byte}. 5 | */ 6 | public class ByteConverter extends NumberConverter { 7 | 8 | public ByteConverter(boolean primitive) { 9 | super(primitive); 10 | } 11 | 12 | @Override 13 | protected Byte convertNumberValue(Number val) { 14 | return val.byteValue(); 15 | } 16 | 17 | @Override 18 | protected Byte convertStringValue(String val) { 19 | return Byte.parseByte(val); 20 | } 21 | 22 | @Override 23 | protected String getTypeDescription() { 24 | return Byte.class.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/LongConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into a {@link Long}. 5 | */ 6 | public class LongConverter extends NumberConverter { 7 | 8 | public LongConverter(boolean primitive) { 9 | super(primitive); 10 | } 11 | 12 | @Override 13 | protected Long convertNumberValue(Number val) { 14 | return val.longValue(); 15 | } 16 | 17 | @Override 18 | protected Long convertStringValue(String val) { 19 | return Long.parseLong(val); 20 | } 21 | 22 | @Override 23 | protected String getTypeDescription() { 24 | return Long.class.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/FloatConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into a {@link Float}. 5 | */ 6 | public class FloatConverter extends NumberConverter { 7 | 8 | public FloatConverter(boolean primitive) { 9 | super(primitive); 10 | } 11 | 12 | @Override 13 | protected Float convertNumberValue(Number val) { 14 | return val.floatValue(); 15 | } 16 | 17 | @Override 18 | protected Float convertStringValue(String val) { 19 | return Float.parseFloat(val); 20 | } 21 | 22 | @Override 23 | protected String getTypeDescription() { 24 | return Float.class.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/ShortConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into a {@link Short}. 5 | */ 6 | public class ShortConverter extends NumberConverter { 7 | 8 | public ShortConverter(boolean primitive) { 9 | super(primitive); 10 | } 11 | 12 | @Override 13 | protected Short convertNumberValue(Number val) { 14 | return val.shortValue(); 15 | } 16 | 17 | @Override 18 | protected Short convertStringValue(String val) { 19 | return Short.parseShort(val); 20 | } 21 | 22 | @Override 23 | protected String getTypeDescription() { 24 | return Short.class.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/UUIDConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * Used by sql2o to convert a value from the database into a {@link UUID}. 7 | */ 8 | public class UUIDConverter extends ConverterBase { 9 | public UUID convert(Object val) throws ConverterException { 10 | if (val == null){ 11 | return null; 12 | } 13 | 14 | if (val instanceof UUID){ 15 | return (UUID)val; 16 | } 17 | 18 | if(val instanceof String){ 19 | return UUID.fromString((String) val); 20 | } 21 | 22 | throw new ConverterException("Cannot convert type " + val.getClass() + " " + UUID.class); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/DoubleConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into a {@link Double}. 5 | */ 6 | public class DoubleConverter extends NumberConverter { 7 | 8 | public DoubleConverter(boolean primitive) { 9 | super(primitive); 10 | } 11 | 12 | @Override 13 | protected Double convertNumberValue(Number val) { 14 | return val.doubleValue(); 15 | } 16 | 17 | @Override 18 | protected Double convertStringValue(String val) { 19 | return Double.parseDouble(val); 20 | } 21 | 22 | @Override 23 | protected String getTypeDescription() { 24 | return Double.class.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/IntegerConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Used by sql2o to convert a value from the database into an {@link Integer}. 5 | */ 6 | public class IntegerConverter extends NumberConverter{ 7 | 8 | public IntegerConverter(boolean primitive) { 9 | super(primitive); 10 | } 11 | 12 | @Override 13 | protected Integer convertNumberValue(Number val) { 14 | return val.intValue(); 15 | } 16 | 17 | @Override 18 | protected Integer convertStringValue(String val) { 19 | return Integer.parseInt(val); 20 | } 21 | 22 | @Override 23 | protected String getTypeDescription() { 24 | return Integer.class.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/DelegatingResultSetHandler.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | /** 7 | * User: dimzon 8 | * Date: 4/7/14 9 | * Time: 11:06 PM 10 | */ 11 | public class DelegatingResultSetHandler implements ResultSetHandler { 12 | private volatile ResultSetHandler inner = null; 13 | private final ResultSetHandlerFactory factory; 14 | 15 | public DelegatingResultSetHandler(ResultSetHandlerFactory factory) { 16 | this.factory = factory; 17 | } 18 | 19 | public E handle(ResultSet resultSet) throws SQLException { 20 | if(inner==null) inner = factory.newResultSetHandler(resultSet.getMetaData()); 21 | return inner.handle(resultSet); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/data/Column.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.data; 2 | 3 | /** 4 | * Represents a result set column 5 | */ 6 | public class Column { 7 | 8 | private String name; 9 | private Integer index; 10 | private String type; 11 | 12 | public Column(String name, Integer index, String type) { 13 | this.name = name; 14 | this.index = index; 15 | this.type = type; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public Integer getIndex() { 23 | return index; 24 | } 25 | 26 | public String getType() { 27 | return type; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return getName() + " (" + getType() + ")"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/InputStreamConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.io.ByteArrayInputStream; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * User: lars 8 | * Date: 6/13/13 9 | * Time: 11:40 PM 10 | * To change this template use File | Settings | File Templates. 11 | */ 12 | public class InputStreamConverter extends ConverterBase { 13 | public ByteArrayInputStream convert(Object val) throws ConverterException { 14 | if (val == null) return null; 15 | 16 | try { 17 | return new ByteArrayInputStream( new ByteArrayConverter().convert(val) ); 18 | } catch( ConverterException e) { 19 | throw new ConverterException("Error converting Blob to InputSteam"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/MySQLDialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | import com.hellokaton.anima.core.SQLParams; 4 | import com.hellokaton.anima.page.PageRow; 5 | 6 | /** 7 | * MySQL dialect 8 | * 9 | * @author biezhi 10 | * @date 2018/3/17 11 | */ 12 | public class MySQLDialect implements Dialect { 13 | 14 | @Override 15 | public String paginate(SQLParams sqlParams) { 16 | PageRow pageRow = sqlParams.getPageRow(); 17 | int limit = pageRow.getPageSize(); 18 | int offset = limit * (pageRow.getPageNum() - 1); 19 | String limitSQL = " LIMIT " + offset + "," + limit; 20 | 21 | StringBuilder sql = new StringBuilder(); 22 | sql.append(select(sqlParams)).append(limitSQL); 23 | return sql.toString(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/PostgreSQLDialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | import com.hellokaton.anima.core.SQLParams; 4 | import com.hellokaton.anima.page.PageRow; 5 | 6 | /** 7 | * PostgreSQL dialect 8 | * 9 | * @author biezhi 10 | * @date 2018/3/17 11 | */ 12 | public class PostgreSQLDialect implements Dialect { 13 | 14 | @Override 15 | public String paginate(SQLParams sqlParams) { 16 | PageRow pageRow = sqlParams.getPageRow(); 17 | int limit = pageRow.getPageSize(); 18 | int offset = limit * (pageRow.getPageNum() - 1); 19 | String limitSQL = " LIMIT " + limit + " OFFSET " + offset; 20 | 21 | StringBuilder sql = new StringBuilder(); 22 | sql.append(select(sqlParams)).append(limitSQL); 23 | return sql.toString(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/AbstractObjectConstructorFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import junit.framework.TestCase; 4 | import org.sql2o.reflection.ObjectConstructorFactory; 5 | 6 | /** 7 | * User: dimzon 8 | * Date: 4/9/14 9 | * Time: 10:09 PM 10 | */ 11 | public abstract class AbstractObjectConstructorFactoryTest extends TestCase { 12 | // just a class 13 | public static class POJO1{ 14 | 15 | } 16 | 17 | public final ObjectConstructorFactory ocf; 18 | 19 | public AbstractObjectConstructorFactoryTest(ObjectConstructorFactory ocf) { 20 | this.ocf = ocf; 21 | } 22 | 23 | public void testCreate(){ 24 | Object o = ocf.newConstructor(POJO1.class).newInstance(); 25 | assertNotNull(o); 26 | assertSame(POJO1.class,o.getClass()); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/converter/LevelConverter.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.converter; 2 | 3 | import com.hellokaton.anima.enums.VipLevel; 4 | import org.sql2o.converters.Converter; 5 | 6 | /** 7 | * @author biezhi 8 | * @date 2018/9/18 9 | */ 10 | public class LevelConverter implements Converter { 11 | 12 | @Override 13 | public VipLevel convert(Object val) { 14 | Integer intValue = (Integer) val; 15 | 16 | switch (intValue) { 17 | case 1: 18 | return VipLevel.VIP1; 19 | case 2: 20 | return VipLevel.VIP1; 21 | case 3: 22 | return VipLevel.VIP3; 23 | default: 24 | return null; 25 | } 26 | } 27 | 28 | @Override 29 | public Object toDatabaseParam(VipLevel val) { 30 | return val.getCode(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/enums/DMLType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.enums; 17 | 18 | /** 19 | * @author biezhi 20 | * @date 2018/3/16 21 | */ 22 | public enum DMLType { 23 | 24 | SELECT, UPDATE, INSERT, DELETE 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/FieldGetter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import org.sql2o.Sql2oException; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | /** 8 | * used internally to get property values directly from the field. Only used if no getter method is found. 9 | * 10 | * @author mdelapenya 11 | */ 12 | public class FieldGetter implements Getter { 13 | 14 | private Field field; 15 | 16 | public FieldGetter(Field field) { 17 | this.field = field; 18 | this.field.setAccessible(true); 19 | } 20 | 21 | public Object getProperty(Object obj) { 22 | try { 23 | return this.field.get(obj); 24 | } catch (IllegalAccessException e) { 25 | throw new Sql2oException("could not get field " + this.field.getName() + " on class " + obj.getClass().toString(), e); 26 | } 27 | } 28 | 29 | public Class getType() { 30 | return field.getType(); 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/BigDecimalConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * Used by sql2o to convert a value from the database into a {@link BigDecimal}. 7 | */ 8 | public class BigDecimalConverter extends NumberConverter{ 9 | 10 | public BigDecimalConverter() { 11 | super(false); 12 | } 13 | 14 | @Override 15 | protected BigDecimal convertNumberValue(Number val) { 16 | if (val instanceof BigDecimal){ 17 | return (BigDecimal)val; 18 | } 19 | else{ 20 | return BigDecimal.valueOf(val.doubleValue()); 21 | } 22 | } 23 | 24 | @Override 25 | protected BigDecimal convertStringValue(String val) { 26 | return BigDecimal.valueOf(Double.parseDouble(val)); 27 | } 28 | 29 | @Override 30 | protected String getTypeDescription() { 31 | return BigDecimal.class.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/data/LazyTable.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.data; 2 | 3 | import org.sql2o.ResultSetIterable; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author aldenquimby@gmail.com 9 | */ 10 | public class LazyTable implements AutoCloseable { 11 | private String name; 12 | private ResultSetIterable rows; 13 | private List columns; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public Iterable rows() { 24 | return rows; 25 | } 26 | 27 | public void setRows(ResultSetIterable rows) { 28 | this.rows = rows; 29 | } 30 | 31 | public List columns() { 32 | return columns; 33 | } 34 | 35 | void setColumns(List columns) { 36 | this.columns = columns; 37 | } 38 | 39 | public void close() { 40 | this.rows.close(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/OracleDateConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import oracle.sql.TIMESTAMP; 4 | 5 | import java.sql.SQLException; 6 | import java.util.Date; 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by lars on 01.05.14. 11 | */ 12 | public class OracleDateConverter extends DateConverter implements ConvertersProvider { 13 | @Override 14 | public Date convert(Object val) throws ConverterException { 15 | 16 | if (val instanceof TIMESTAMP) { 17 | try { 18 | return ((TIMESTAMP)val).timestampValue(); 19 | } catch (SQLException e) { 20 | throw new ConverterException("Error trying to convert oracle.sql.TIMESTAMP to DateTime", e); 21 | } 22 | } 23 | 24 | return super.convert(val); 25 | } 26 | 27 | @Override 28 | public void fill(Map, Converter> mapToFill) { 29 | mapToFill.put(Date.class, new OracleDateConverter()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/tools/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.tools; 2 | 3 | /** 4 | * @author Alden Quimby 5 | */ 6 | public final class ClassUtils { 7 | 8 | // private static ClassLoader getClassLoader() { 9 | // return Thread.currentThread().getContextClassLoader(); 10 | // } 11 | 12 | /** 13 | * Check whether the {@link Class} identified by the supplied name is present. 14 | * 15 | * @param className the name of the class to check 16 | * @return true if class is present, false otherwise 17 | */ 18 | public static boolean isPresent(String className) { 19 | try { 20 | // what's wrong with old plain Class.forName 21 | // this code supposed to work everywhere including containers 22 | Class.forName(className); 23 | // getClassLoader().loadClass(className); 24 | return true; 25 | } 26 | catch (Throwable ex) { 27 | return false; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/ResultSetHandlerFactoryBuilder.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import org.sql2o.quirks.Quirks; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * Created with IntelliJ IDEA. 9 | * User: dimzon 10 | * Date: 4/7/14 11 | * Time: 4:28 AM 12 | * To change this template use File | Settings | File Templates. 13 | */ 14 | public interface ResultSetHandlerFactoryBuilder { 15 | boolean isCaseSensitive(); 16 | 17 | void setCaseSensitive(boolean caseSensitive); 18 | 19 | boolean isAutoDeriveColumnNames(); 20 | 21 | void setAutoDeriveColumnNames(boolean autoDeriveColumnNames); 22 | 23 | boolean isThrowOnMappingError(); 24 | 25 | void throwOnMappingError(boolean throwOnMappingError); 26 | 27 | Map getColumnMappings(); 28 | 29 | void setColumnMappings(Map columnMappings); 30 | 31 | Quirks getQuirks(); 32 | 33 | void setQuirks(Quirks quirksMode); 34 | 35 | ResultSetHandlerFactory newFactory(Class clazz); 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/Entity.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import java.sql.Date; 4 | import java.sql.Timestamp; 5 | 6 | /** 7 | * Created by IntelliJ IDEA. 8 | * User: lars 9 | * Date: 5/21/11 10 | * Time: 10:15 PM 11 | * To change this template use File | Settings | File Templates. 12 | */ 13 | public class Entity { 14 | 15 | public long id; 16 | public String text; 17 | public Date time; 18 | public Timestamp ts; 19 | public Integer aNumber; 20 | public Long aLongNumber; 21 | 22 | 23 | public Date getTime() { 24 | return time; 25 | } 26 | 27 | public void setTime(Date time) { 28 | this.time = time; 29 | } 30 | 31 | public Timestamp getTs() { 32 | return ts; 33 | } 34 | 35 | public void setTs(Timestamp ts) { 36 | this.ts = ts; 37 | } 38 | 39 | public Integer getaNumber() { 40 | return aNumber; 41 | } 42 | 43 | public void setaNumber(Integer aNumber) { 44 | this.aNumber = aNumber; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/java8/LocalDateConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters.java8; 2 | 3 | import org.sql2o.converters.Converter; 4 | import org.sql2o.converters.ConverterException; 5 | 6 | import java.sql.Timestamp; 7 | import java.time.LocalDate; 8 | import java.time.ZoneId; 9 | 10 | public class LocalDateConverter implements Converter { 11 | 12 | @Override 13 | public LocalDate convert(Object val) throws ConverterException { 14 | if (val == null) { 15 | return null; 16 | } 17 | try { 18 | return ((Timestamp) val).toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); 19 | } catch (IllegalArgumentException ex) { 20 | throw new ConverterException("Don't know how to convert from type '" + val.getClass().getName() + "' to type '" + LocalDate.class.getName() + "'", ex); 21 | } 22 | } 23 | 24 | @Override 25 | public Object toDatabaseParam(LocalDate val) { 26 | return java.sql.Date.valueOf(val); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/page/PageRow.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.page; 17 | 18 | import lombok.Data; 19 | 20 | @Data 21 | public class PageRow { 22 | 23 | private int pageNum; 24 | private int pageSize; 25 | 26 | public PageRow(int pageNum, int pageSize) { 27 | this.pageNum = pageNum; 28 | this.pageSize = pageSize; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/connectionsources/DataSourceConnectionSource.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.connectionsources; 2 | 3 | import javax.sql.DataSource; 4 | import java.sql.Connection; 5 | import java.sql.SQLException; 6 | 7 | /** 8 | * The default implementation of {@link ConnectionSource}, 9 | * Simply delegates all calls to specified {@link DataSource } 10 | * Created by nickl on 09.01.17. 11 | */ 12 | public class DataSourceConnectionSource implements ConnectionSource { 13 | 14 | private final DataSource dataSource; 15 | 16 | /** 17 | * Creates a ConnectionSource that gets connection from specified {@link DataSource } 18 | * @param dataSource a DataSource to get connections from 19 | */ 20 | public DataSourceConnectionSource(DataSource dataSource) { 21 | this.dataSource = dataSource; 22 | } 23 | 24 | @Override 25 | public Connection getConnection() throws SQLException { 26 | return dataSource.getConnection(); 27 | } 28 | 29 | public DataSource getDataSource() { 30 | return dataSource; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/OracleDialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | import com.hellokaton.anima.core.SQLParams; 4 | import com.hellokaton.anima.page.PageRow; 5 | 6 | /** 7 | * Oracle dialect 8 | * 9 | * @author biezhi 10 | * @date 2018/3/17 11 | */ 12 | public class OracleDialect implements Dialect { 13 | 14 | @Override 15 | public String paginate(SQLParams sqlParams) { 16 | PageRow pageRow = sqlParams.getPageRow(); 17 | int limit = pageRow.getPageSize(); 18 | int pageNum = pageRow.getPageNum(); 19 | 20 | int start = (pageNum - 1) * limit + 1; 21 | int end = pageNum * limit; 22 | StringBuilder sql = new StringBuilder(); 23 | sql.append("SELECT * FROM ( SELECT row_.*, rownum rownum_ FROM ( "); 24 | sql.append(select(sqlParams)); 25 | sql.append(" ) row_ where rownum <= ").append(end).append(") table_alias"); 26 | sql.append(" WHERE table_alias.rownum_ >= ").append(start); 27 | return sql.toString(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/FieldSetter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import org.sql2o.Sql2oException; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | /** 8 | * used internally to set property values directly into the field. Only used if no setter method is found. 9 | */ 10 | public class FieldSetter implements Setter{ 11 | 12 | private Field field; 13 | 14 | public FieldSetter(Field field) { 15 | this.field = field; 16 | this.field.setAccessible(true); 17 | } 18 | 19 | public void setProperty(Object obj, Object value) { 20 | if (value == null && this.field.getType().isPrimitive()){ 21 | return; // dont try set null to a primitive field 22 | } 23 | 24 | try { 25 | this.field.set(obj, value); 26 | } catch (IllegalAccessException e) { 27 | throw new Sql2oException("could not set field " + this.field.getName() + " on class " + obj.getClass().toString(), e); 28 | } 29 | } 30 | 31 | public Class getType() { 32 | return field.getType(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/JndiDataSource.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import javax.naming.Context; 6 | import javax.naming.InitialContext; 7 | import javax.naming.NamingException; 8 | import javax.sql.DataSource; 9 | 10 | /** 11 | * Created by lars on 16.09.2014. 12 | */ 13 | @Slf4j 14 | public class JndiDataSource { 15 | 16 | static DataSource getJndiDatasource(String jndiLookup) { 17 | Context ctx = null; 18 | DataSource datasource = null; 19 | 20 | try { 21 | ctx = new InitialContext(); 22 | datasource = (DataSource) ctx.lookup(jndiLookup); 23 | } 24 | catch (NamingException e) { 25 | throw new RuntimeException(e); 26 | } 27 | finally { 28 | if (ctx != null) { 29 | try { 30 | ctx.close(); 31 | } 32 | catch (Throwable e) { 33 | log.warn("error closing context", e); 34 | } 35 | } 36 | } 37 | 38 | return datasource; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/OracleUUIDConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.util.UUID; 5 | 6 | /** 7 | * Created by lars on 12.08.15. 8 | */ 9 | public class OracleUUIDConverter implements Converter { 10 | 11 | private final UUIDConverter baseConverter = new UUIDConverter(); 12 | 13 | @Override 14 | public UUID convert(Object val) throws ConverterException { 15 | if (val instanceof byte[]) { 16 | ByteBuffer bb = ByteBuffer.wrap((byte[])val); 17 | 18 | long mostSignigcant = bb.getLong(); 19 | long leastSignificant = bb.getLong(); 20 | 21 | return new UUID(mostSignigcant, leastSignificant); 22 | } else { 23 | return baseConverter.convert(val); 24 | } 25 | } 26 | 27 | @Override 28 | public Object toDatabaseParam(UUID val) { 29 | ByteBuffer bb = ByteBuffer.wrap(new byte[16]); 30 | bb.putLong(val.getMostSignificantBits()); 31 | bb.putLong(val.getLeastSignificantBits()); 32 | return bb.array(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/DeleteTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.model.User; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | /** 8 | * Save 9 | * 10 | * @author biezhi 11 | * @date 2018/3/14 12 | */ 13 | public class DeleteTest extends BaseTest { 14 | 15 | @Test 16 | public void testDelete() { 17 | new User(9001, "test", 14).save(); 18 | int result = Anima.delete().from(User.class).where("id", 9001).execute(); 19 | Assert.assertEquals(1, result); 20 | } 21 | 22 | @Test 23 | public void testDelete2() { 24 | User user = new User(); 25 | user.setAge(15); 26 | user.setUserName("jack"); 27 | user.delete(); 28 | } 29 | 30 | @Test 31 | public void testDelete3() { 32 | Anima.deleteBatch(User.class, 1, 2, 3); 33 | } 34 | 35 | @Test 36 | public void testDelete4(){ 37 | Anima.deleteById(User.class, 5); 38 | } 39 | 40 | @Test 41 | public void testDelete5(){ 42 | Anima.execute("delete from users where id = ?", 2); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/SqlServer2012Dialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | import com.hellokaton.anima.core.SQLParams; 4 | import com.hellokaton.anima.page.PageRow; 5 | 6 | /** 7 | * SqlServer 2012+ dialect 8 | * 9 | * @author darren 10 | * @date 2018-06-13 11 | */ 12 | public class SqlServer2012Dialect implements Dialect { 13 | 14 | @Override 15 | public String paginate(SQLParams sqlParams) { 16 | PageRow pageRow = sqlParams.getPageRow(); 17 | int limit = pageRow.getPageSize(); 18 | int offset = limit * (pageRow.getPageNum() - 1); 19 | String limitSQL = " OFFSET " + offset + " ROWS FETCH NEXT " + limit+ " ROWS ONLY "; 20 | 21 | StringBuilder sql = new StringBuilder(); 22 | sql.append(select(sqlParams)); 23 | //offset-fetch 必须在order-by语句之后,因此如果用户的sql没有order-by则为其添加一个不影响顺序的按时间戳的order-by 24 | if(!sql.toString().matches("(?i).* ORDER BY[^)]+$")) { 25 | sql.append(" ORDER BY CURRENT_TIMESTAMP"); 26 | } 27 | sql.append(limitSQL); 28 | return sql.toString(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/model/OrderInfo.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.model; 2 | 3 | import com.hellokaton.anima.Model; 4 | import com.hellokaton.anima.annotation.Ignore; 5 | import com.hellokaton.anima.annotation.Column; 6 | import com.hellokaton.anima.annotation.Table; 7 | import lombok.Data; 8 | import lombok.EqualsAndHashCode; 9 | import lombok.NoArgsConstructor; 10 | 11 | import java.time.LocalDateTime; 12 | 13 | /** 14 | * @author biezhi 15 | * @date 2018/3/17 16 | */ 17 | @Table(name = "order_info") 18 | @NoArgsConstructor 19 | @Data 20 | @EqualsAndHashCode(callSuper=false) 21 | public class OrderInfo extends Model { 22 | 23 | private Long id; 24 | 25 | private Integer uid; 26 | 27 | @Column(name = "productname") 28 | private String productName; 29 | 30 | private LocalDateTime createTime; 31 | 32 | public OrderInfo(Integer uid, String productName) { 33 | this.uid = uid; 34 | this.productName = productName; 35 | this.createTime = LocalDateTime.now(); 36 | } 37 | 38 | @Ignore 39 | private User user; 40 | 41 | @Ignore 42 | private Address address; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/annotation/Table.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.annotation; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target({ElementType.TYPE}) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface Table { 26 | 27 | String name() default ""; 28 | 29 | String pk() default "id"; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/data/Table.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.data; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * Represents an offline result set with columns and rows and data. 7 | */ 8 | public class Table { 9 | private String name; 10 | private List rows; 11 | private List columns; 12 | 13 | public Table(String name, List rows, List columns) { 14 | this.name = name; 15 | this.rows = rows; 16 | this.columns = columns; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public List rows() { 24 | return rows; 25 | } 26 | 27 | public List columns() { 28 | return columns; 29 | } 30 | 31 | public List> asList() 32 | { 33 | return new AbstractList>() { 34 | @Override 35 | public Map get(int index) { 36 | return rows.get(index).asMap(); 37 | } 38 | 39 | @Override 40 | public int size() { 41 | return rows.size(); 42 | } 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/annotation/Ignore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.annotation; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * ignore class field 25 | * 26 | * @author biezhi 27 | * @date 2018/3/19 28 | */ 29 | @Target({ElementType.FIELD}) 30 | @Retention(RetentionPolicy.RUNTIME) 31 | public @interface Ignore { 32 | 33 | } -------------------------------------------------------------------------------- /src/test/java/org/sql2o/tools/UnderscoreToCamelCaseTests.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.tools; 2 | 3 | import junit.framework.TestCase; 4 | 5 | public class UnderscoreToCamelCaseTests extends TestCase { 6 | 7 | public void testBasicConversions() { 8 | assertEquals("myStringVariable", UnderscoreToCamelCase.convert("my_string_variable")); 9 | assertEquals("string", UnderscoreToCamelCase.convert("string")); 10 | assertEquals("myReallyLongStringVariableName", UnderscoreToCamelCase.convert("my_really_long_string_variable_name")); 11 | assertEquals("myString2WithNumbers4", UnderscoreToCamelCase.convert("my_string2_with_numbers_4")); 12 | assertEquals("myStringWithMixedCase", UnderscoreToCamelCase.convert("my_string_with_MixED_CaSe")); 13 | } 14 | 15 | public void testNullString() { 16 | assertNull(UnderscoreToCamelCase.convert(null)); 17 | } 18 | 19 | public void testEmptyStrings() { 20 | assertEquals("", UnderscoreToCamelCase.convert("")); 21 | assertEquals(" ", UnderscoreToCamelCase.convert(" ")); 22 | } 23 | public void testWhitespace() { 24 | assertEquals("\t", UnderscoreToCamelCase.convert("\t")); 25 | assertEquals("\n\n", UnderscoreToCamelCase.convert("\n\n")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/dml/Update.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.core.dml; 17 | 18 | import com.hellokaton.anima.Model; 19 | import com.hellokaton.anima.core.AnimaQuery; 20 | import com.hellokaton.anima.enums.DMLType; 21 | 22 | /** 23 | * Update 24 | * 25 | * @author biezhi 26 | * @date 2018/3/18 27 | */ 28 | public class Update { 29 | 30 | public AnimaQuery from(Class modelClass) { 31 | return new AnimaQuery(DMLType.UPDATE).parse(modelClass); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/ReflectionObjectConstructorFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import org.sql2o.Sql2oException; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | public class ReflectionObjectConstructorFactory implements ObjectConstructorFactory { 9 | public ObjectConstructor newConstructor(final Class clazz) { 10 | try { 11 | final Constructor ctor = clazz.getDeclaredConstructor(); 12 | ctor.setAccessible(true); 13 | return new ObjectConstructor() { 14 | public Object newInstance() { 15 | try { 16 | return ctor.newInstance((Object[])null); 17 | } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { 18 | throw new Sql2oException("Could not create a new instance of class " + clazz, e); 19 | } 20 | } 21 | }; 22 | } catch (Throwable e) { 23 | throw new Sql2oException("Could not find parameter-less constructor of class " + clazz, e); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/tools/UnderscoreToCamelCase.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.tools; 2 | 3 | /** 4 | * Takes a string formatted like: 'my_string_variable' and returns it as: 'myStringVariable' 5 | * 6 | * @author ryancarlson 7 | * @author dimzon - complete rewrite 8 | */ 9 | public class UnderscoreToCamelCase { 10 | public static String convert(String underscore){ 11 | if(underscore==null || underscore.isEmpty()) return underscore; 12 | return convert00(underscore); 13 | } 14 | 15 | private static String convert00(String underscore){ 16 | char[] chars = underscore.toCharArray(); 17 | int write=-1,len=chars.length; 18 | boolean upper=false; 19 | for (int read = 0; read < len; ++read) { 20 | char c = chars[read]; 21 | if('_'==c){ 22 | upper = true; 23 | continue; 24 | } 25 | if(upper){ 26 | upper = false; 27 | chars[++write]=Character.toUpperCase(c); 28 | } else { 29 | chars[++write]=Character.toLowerCase(c); 30 | } 31 | } 32 | return new String(chars, 0, ++write); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/dml/Delete.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.core.dml; 17 | 18 | import com.hellokaton.anima.Model; 19 | import com.hellokaton.anima.core.AnimaQuery; 20 | import com.hellokaton.anima.enums.DMLType; 21 | 22 | /** 23 | * Delete From 24 | * 25 | * @author biezhi 26 | * @date 2018/3/18 27 | */ 28 | public class Delete { 29 | 30 | public AnimaQuery from(Class modelClass) { 31 | return new AnimaQuery(DMLType.DELETE).parse(modelClass); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/SaveTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.model.User; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Save 12 | * 13 | * @author biezhi 14 | * @date 2018/3/14 15 | */ 16 | public class SaveTest extends BaseTest { 17 | 18 | @Test 19 | public void testSave() { 20 | User user = new User(); 21 | user.setUserName("save1"); 22 | user.setAge(99); 23 | Integer id = user.save().asInt(); 24 | Assert.assertNotNull(id); 25 | } 26 | 27 | @Test 28 | public void testSave2() { 29 | Integer id = new User("save2", 100).save().asInt(); 30 | Assert.assertNotNull(id); 31 | } 32 | 33 | @Test 34 | public void testSave3() { 35 | Anima.save(new User("save3", 100)); 36 | } 37 | 38 | @Test 39 | public void testSave4() { 40 | List users = new ArrayList<>(); 41 | users.add(new User("user1", 10)); 42 | users.add(new User("user2", 11)); 43 | users.add(new User("user3", 12)); 44 | Anima.saveBatch(users); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/QueryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import org.junit.Test; 4 | 5 | import javax.sql.DataSource; 6 | import java.sql.SQLException; 7 | 8 | import static org.mockito.Matchers.anyString; 9 | import static org.mockito.Mockito.*; 10 | 11 | /** 12 | * Created by lars on 25.01.15. 13 | */ 14 | public class QueryTest { 15 | 16 | /** 17 | * Test issue 161, fetch trigger generated keys from Oracle. 18 | * Fixed by calling java.sql.Connection.prepareStatement(String, String[]) overload. 19 | * @throws SQLException 20 | */ 21 | @Test 22 | public void testCreateQueryWithKeyNames() throws SQLException { 23 | DataSource dataSource = mock(DataSource.class); 24 | java.sql.Connection jdbcCon = mock(java.sql.Connection.class); 25 | 26 | when(jdbcCon.isClosed()).thenReturn(false); 27 | when(dataSource.getConnection()).thenReturn(jdbcCon); 28 | 29 | Sql2o sql2o = new Sql2o(dataSource); 30 | 31 | Connection con = sql2o.open(); 32 | con.createQuery("sql", "colname").buildPreparedStatement(); 33 | 34 | verify(jdbcCon, times(1)).prepareStatement(anyString(), new String[]{anyString()}); 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/tools/IOUtils.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.tools; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.Reader; 7 | 8 | /** 9 | * User: lars 10 | * Date: 6/14/13 11 | * Time: 12:02 AM 12 | */ 13 | public class IOUtils { 14 | 15 | private static final int EOF = -1; 16 | private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 17 | 18 | public static byte[] toByteArray(InputStream input) throws IOException { 19 | ByteArrayOutputStream output = new ByteArrayOutputStream(); 20 | byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 21 | int n; 22 | while (EOF != (n = input.read(buffer))) { 23 | output.write(buffer, 0, n); 24 | } 25 | return output.toByteArray(); 26 | } 27 | 28 | public static String toString(Reader input) throws IOException { 29 | StringBuilder output = new StringBuilder(); 30 | char[] buffer = new char[DEFAULT_BUFFER_SIZE]; 31 | int n; 32 | while (EOF != (n = input.read(buffer))) { 33 | output.append(buffer, 0, n); 34 | } 35 | return output.toString(); 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/annotation/Column.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.annotation; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * identify custom column name 25 | * 26 | * @author biezhi 27 | * @date 2018/3/19 28 | */ 29 | @Target({ElementType.METHOD, ElementType.FIELD}) 30 | @Retention(RetentionPolicy.RUNTIME) 31 | public @interface Column { 32 | 33 | String name() default ""; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/MethodGetter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import org.sql2o.Sql2oException; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * used internally to get property values via its getter method. 10 | * 11 | * @author mdelapenya 12 | */ 13 | public class MethodGetter implements Getter { 14 | 15 | private Method method; 16 | private Class type; 17 | 18 | public MethodGetter(Method method) { 19 | this.method = method; 20 | this.method.setAccessible(true); 21 | type = method.getReturnType(); 22 | } 23 | 24 | public Object getProperty(Object obj) { 25 | try { 26 | return this.method.invoke(obj); 27 | } catch (IllegalAccessException e) { 28 | throw new Sql2oException("error while calling getter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); 29 | } catch (InvocationTargetException e) { 30 | throw new Sql2oException("error while calling getter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); 31 | } 32 | } 33 | 34 | public Class getType() { 35 | return type; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/dialect/SqlServerDialect.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.dialect; 2 | 3 | import com.hellokaton.anima.core.SQLParams; 4 | import com.hellokaton.anima.page.PageRow; 5 | 6 | /** 7 | * SqlServer dialect 8 | * 9 | * @author biezhi,darren 10 | * @date 2018/3/18 11 | */ 12 | public class SqlServerDialect implements Dialect { 13 | 14 | @Override 15 | public String paginate(SQLParams sqlParams) { 16 | PageRow pageRow = sqlParams.getPageRow(); 17 | int limit = pageRow.getPageSize(); 18 | int pageNum = pageRow.getPageNum(); 19 | 20 | int end = pageNum * limit; 21 | if (end <= 0) 22 | end = limit; 23 | int begin = (pageNum - 1) * limit + 1; 24 | if (begin < 1) 25 | begin = 1; 26 | 27 | StringBuilder sql = new StringBuilder(); 28 | 29 | sql.append("with query as ( select inner_query.*, row_number() over (order by current_timestamp) as temprownumber from ( "); 30 | sql.append(select(sqlParams).replaceFirst("(?i)select(\\s+distinct\\s+)?", "$0 top("+end+")")); 31 | sql.append(" ) inner_query ) select * from query where temprownumber between "); 32 | sql.append(begin).append(" and ").append(end); 33 | return sql.toString(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/PojoResultSetIterator.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import org.sql2o.quirks.Quirks; 4 | 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | /** 9 | * Iterator for a {@link ResultSet}. Tricky part here is getting {@link #hasNext()} 10 | * to work properly, meaning it can be called multiple times without calling {@link #next()}. 11 | * 12 | * @author aldenquimby@gmail.com 13 | */ 14 | public class PojoResultSetIterator extends ResultSetIteratorBase { 15 | private ResultSetHandler handler; 16 | 17 | public PojoResultSetIterator(ResultSet rs, boolean isCaseSensitive, Quirks quirks, ResultSetHandlerFactory factory) { 18 | super(rs, isCaseSensitive, quirks); 19 | try { 20 | this.handler = factory.newResultSetHandler(rs.getMetaData()); 21 | } catch (SQLException e) { 22 | throw new Sql2oException("Database error: " + e.getMessage(), e); 23 | } 24 | } 25 | 26 | public PojoResultSetIterator(ResultSet rs, boolean isCaseSensitive, Quirks quirks, ResultSetHandler handler) { 27 | super(rs, isCaseSensitive, quirks); 28 | this.handler = handler; 29 | } 30 | 31 | @Override 32 | protected T readNext() throws SQLException { 33 | return handler.handle(rs); 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/BooleanConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: lars 6 | * Date: 6/1/13 7 | * Time: 10:54 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class BooleanConverter extends ConverterBase { 11 | 12 | public Boolean convert(Object val) throws ConverterException { 13 | if (val == null) return null; 14 | 15 | if (val instanceof Boolean) { 16 | return (Boolean) val; 17 | } 18 | 19 | if (val instanceof Number) { 20 | return ((Number)val).intValue() != 0; 21 | } 22 | 23 | if (val instanceof Character) { 24 | // cast to char is required to compile with java 8 25 | return (char)val =='Y' 26 | || (char)val =='T' 27 | || (char)val =='J'; 28 | } 29 | 30 | if (val instanceof String) { 31 | String strVal = ((String)val).trim(); 32 | return "Y".equalsIgnoreCase(strVal) || "YES".equalsIgnoreCase(strVal) || "TRUE".equalsIgnoreCase(strVal) || 33 | "T".equalsIgnoreCase(strVal) || "J".equalsIgnoreCase(strVal); 34 | } 35 | 36 | throw new ConverterException("Don't know how to convert type " + val.getClass().getName() + " to " + Boolean.class.getName()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/tools/FeatureDetector.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.tools; 2 | 3 | /** 4 | * Detects whether optional sql2o features are available. 5 | * 6 | * @author Alden Quimby 7 | */ 8 | public final class FeatureDetector { 9 | 10 | private FeatureDetector() {} 11 | 12 | static { 13 | setCacheUnderscoreToCamelcaseEnabled(true); // enabled by default 14 | } 15 | 16 | private static Boolean oracleAvailable; 17 | private static boolean cacheUnderscoreToCamelcaseEnabled; 18 | 19 | /** 20 | * @return {@code true} if oracle.sql is available, {@code false} otherwise. 21 | */ 22 | public static boolean isOracleAvailable() { 23 | if (oracleAvailable == null) { 24 | oracleAvailable = ClassUtils.isPresent("oracle.sql.TIMESTAMP"); 25 | } 26 | return oracleAvailable; 27 | } 28 | 29 | /** 30 | * @return {@code true} if caching of underscore to camelcase is enabled. 31 | */ 32 | public static boolean isCacheUnderscoreToCamelcaseEnabled() { 33 | return cacheUnderscoreToCamelcaseEnabled; 34 | } 35 | 36 | /** 37 | * Turn caching of underscore to camelcase on or off. 38 | */ 39 | public static void setCacheUnderscoreToCamelcaseEnabled(boolean cacheUnderscoreToCamelcaseEnabled) { 40 | FeatureDetector.cacheUnderscoreToCamelcaseEnabled = cacheUnderscoreToCamelcaseEnabled; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/MethodSetter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import org.sql2o.Sql2oException; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * used internally to set property values via its setter method. 10 | */ 11 | public class MethodSetter implements Setter{ 12 | 13 | private Method method; 14 | private Class type; 15 | 16 | public MethodSetter(Method method) { 17 | this.method = method; 18 | this.method.setAccessible(true); 19 | type = method.getParameterTypes()[0]; 20 | } 21 | 22 | public void setProperty(Object obj, Object value) { 23 | if (value == null && type.isPrimitive()){ 24 | return; // dont try to set null to a setter to a primitive type. 25 | } 26 | try { 27 | this.method.invoke(obj, value); 28 | } catch (IllegalAccessException e) { 29 | throw new Sql2oException("error while calling setter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); 30 | } catch (InvocationTargetException e) { 31 | throw new Sql2oException("error while calling setter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); 32 | } 33 | } 34 | 35 | public Class getType() { 36 | return type; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/oracle/OracleTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.oracle; 2 | 3 | import com.hellokaton.anima.Anima; 4 | import com.hellokaton.anima.model.ZhuanJia; 5 | import com.hellokaton.anima.page.Page; 6 | import com.hellokaton.anima.dialect.OracleDialect; 7 | import org.junit.Assert; 8 | 9 | import java.sql.Driver; 10 | import java.sql.DriverManager; 11 | 12 | import static com.hellokaton.anima.Anima.select; 13 | 14 | /** 15 | * @author biezhi 16 | * @date 2018/6/13 17 | */ 18 | public class OracleTest { 19 | 20 | // @Before 21 | public void before() { 22 | try { 23 | Class oracleDriverClass = OracleTest.class.getClassLoader().loadClass("oracle.jdbc.driver.OracleDriver"); 24 | DriverManager.registerDriver((Driver) oracleDriverClass.newInstance()); 25 | } catch (Throwable t) { 26 | t.printStackTrace(); 27 | } 28 | Anima.open("jdbc:oracle:thin:@localhost:1521:EE", "system", "oracle").dialect(new OracleDialect()); 29 | 30 | String sql = "select to_clob('test') val from dual"; 31 | String one = Anima.select().bySQL(String.class, sql).one(); 32 | Assert.assertEquals("test", one); 33 | } 34 | 35 | // @Test 36 | public void testPage(){ 37 | Page page = Anima.select().from(ZhuanJia.class).page(1, 10); 38 | System.out.println(page.getRows()); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/QuirksProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Lars Aaberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | * 6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | package org.sql2o.quirks; 12 | 13 | 14 | /* User: dimzon 15 | * Date: 4/24/14 16 | * Time: 9:31 AM 17 | */ 18 | public interface QuirksProvider { 19 | Quirks provide(); 20 | 21 | boolean isUsableForUrl(String url); 22 | boolean isUsableForClass(String className); 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/sqlserver/SqlServerTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.sqlserver; 2 | 3 | import com.hellokaton.anima.Anima; 4 | import com.hellokaton.anima.model.User; 5 | import com.hellokaton.anima.oracle.OracleTest; 6 | import com.hellokaton.anima.page.Page; 7 | import com.hellokaton.anima.dialect.SqlServer2012Dialect; 8 | 9 | import java.sql.Driver; 10 | import java.sql.DriverManager; 11 | 12 | import static com.hellokaton.anima.Anima.select; 13 | 14 | /** 15 | * @author darren 16 | * @date 2018-06-13 17 | */ 18 | public class SqlServerTest { 19 | 20 | // @Before 21 | public void before() { 22 | try { 23 | Class oracleDriverClass = OracleTest.class.getClassLoader().loadClass("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 24 | DriverManager.registerDriver((Driver) oracleDriverClass.newInstance()); 25 | } catch (Throwable t) { 26 | t.printStackTrace(); 27 | } 28 | // Anima.open("jdbc:sqlserver://192.168.123.114:1433;databaseName=dev", "sa", "Abcd1234").dialect(new SqlServerDialect()); 29 | Anima.open("jdbc:sqlserver://192.168.123.114:1433;databaseName=dev", "sa", "Abcd1234").dialect(new SqlServer2012Dialect()); 30 | } 31 | 32 | // @Test 33 | public void testPage(){ 34 | Page page = Anima.select().from(User.class).where(User::getAge).gte(3).page(2, 10); 35 | System.out.println(page.getRows()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/ExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.model.User; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.sql2o.Sql2oException; 8 | 9 | /** 10 | * Exception 11 | * 12 | * @author biezhi 13 | * @date 2018/3/13 14 | */ 15 | @Slf4j 16 | public class ExceptionTest extends BaseTest { 17 | 18 | @Test 19 | public void testCustomRollbackException() { 20 | boolean isRollback = Anima.atomic(() -> { 21 | throwCustomException(); 22 | new User("apple", 666).save(); 23 | }).catchException(e -> { }).isRollback(); 24 | 25 | Assert.assertEquals(true, isRollback); 26 | 27 | isRollback = Anima.atomic(() -> { 28 | int a = 1 / 0; 29 | System.out.println(a); 30 | new User("apple", 666).save(); 31 | }).catchException(e -> { 32 | }).isRollback(); 33 | 34 | Assert.assertEquals(true, isRollback); 35 | } 36 | 37 | @Test(expected = Sql2oException.class) 38 | public void test() { 39 | User user = new User(); 40 | user.save(); 41 | } 42 | 43 | private void throwCustomException() { 44 | throw new CustomException(); 45 | } 46 | 47 | static class CustomException extends RuntimeException { 48 | 49 | private static final long serialVersionUID = 6329605066783987521L; 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/enums/SupportedType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.enums; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public enum SupportedType { 22 | instance; 23 | 24 | public static boolean contains(String name){ 25 | return supportedTypeList.contains(name.toLowerCase()); 26 | } 27 | 28 | @SuppressWarnings({"serial"}) 29 | private static List supportedTypeList = new ArrayList(){{ 30 | add("string"); add("char"); add("character"); 31 | add("integer"); add("int"); add("short"); add("byte"); 32 | add("long"); add("float"); add("double"); 33 | add("date"); add("time"); add("timestamp"); 34 | add("boolean"); 35 | }}; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/AbstractDateConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import java.sql.Timestamp; 4 | import java.util.Date; 5 | 6 | /** 7 | * Used by sql2o to convert a value from the database into a {@link Date}. 8 | */ 9 | public abstract class AbstractDateConverter implements Converter { 10 | private final Class classOfDate; 11 | protected AbstractDateConverter(Class classOfDate) { 12 | this.classOfDate = classOfDate; 13 | } 14 | 15 | protected abstract E fromMilliseconds(long millisecond); 16 | 17 | @SuppressWarnings("unchecked") 18 | public E convert(Object val) throws ConverterException { 19 | if (val == null){ 20 | return null; 21 | } 22 | 23 | if (classOfDate.isInstance(val)){ 24 | return (E) val; 25 | } 26 | 27 | if(val instanceof Date){ 28 | return fromMilliseconds(((Date) val).getTime()); 29 | } 30 | 31 | if (val instanceof Number){ 32 | return fromMilliseconds(((Number) val).longValue()); 33 | } 34 | 35 | throw new ConverterException("Cannot convert type " + val.getClass().toString() + " to java.util.Date"); 36 | } 37 | 38 | public Object toDatabaseParam(Date val) { 39 | if(val==null) return null; 40 | return (val instanceof Timestamp) 41 | ? (Timestamp) val 42 | :new Timestamp(val.getTime()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/issues/H2Tests.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.issues; 2 | 3 | import org.h2.jdbcx.JdbcDataSource; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.sql2o.Connection; 7 | import org.sql2o.Sql2o; 8 | import org.sql2o.quirks.NoQuirks; 9 | 10 | import javax.sql.DataSource; 11 | 12 | import static org.hamcrest.CoreMatchers.*; 13 | import static org.junit.Assert.assertThat; 14 | 15 | /** 16 | * Created by lars on 05.10.2014. 17 | */ 18 | public class H2Tests { 19 | 20 | DataSource ds; 21 | 22 | String driverClassName; 23 | String url; 24 | String user; 25 | String pass; 26 | 27 | @Before 28 | public void setUp() throws Exception { 29 | driverClassName = "org.h2.Driver"; 30 | url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; 31 | user = "sa"; 32 | pass = ""; 33 | JdbcDataSource datasource = new JdbcDataSource(); 34 | datasource.setURL(url); 35 | datasource.setUser(user); 36 | datasource.setPassword(pass); 37 | 38 | ds = datasource; 39 | } 40 | 41 | @Test 42 | public void testIssue155() { 43 | 44 | Sql2o sql2o = new Sql2o(ds); 45 | 46 | assertThat(sql2o.getQuirks(), is(instanceOf(NoQuirks.class))); 47 | 48 | try (Connection connection = sql2o.open()) { 49 | int val = connection.createQuery("select 42").executeScalar(Integer.class); 50 | 51 | assertThat(val, is(equalTo(42))); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/java8/LocalDateTimeConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters.java8; 2 | 3 | import org.sql2o.converters.Converter; 4 | import org.sql2o.converters.ConverterException; 5 | 6 | import java.sql.Timestamp; 7 | import java.time.LocalDateTime; 8 | import java.time.ZoneId; 9 | 10 | /** 11 | * Used by sql2o to convert a value from the database into a {@link LocalDateTime} instance. 12 | */ 13 | public class LocalDateTimeConverter implements Converter { 14 | 15 | // it's possible to create instance for other timezone 16 | // and re-register converter 17 | public LocalDateTimeConverter(LocalDateTime localDateTime) { 18 | } 19 | 20 | public LocalDateTimeConverter() { 21 | this(LocalDateTime.now()); 22 | } 23 | 24 | public LocalDateTime convert(Object val) throws ConverterException { 25 | if (val == null) { 26 | return null; 27 | } 28 | try { 29 | Timestamp timestamp = (Timestamp) val; 30 | return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); 31 | } catch (IllegalArgumentException ex) { 32 | throw new ConverterException("Error while converting type " + val.getClass().toString() + " to jodatime", ex); 33 | } 34 | } 35 | 36 | public Object toDatabaseParam(LocalDateTime val) { 37 | return new java.sql.Date(val.atZone(ZoneId.systemDefault()).toInstant() 38 | .toEpochMilli()); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/NumberConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | /** 4 | * Base class for numeric converters. 5 | */ 6 | public abstract class NumberConverter extends ConverterBase { 7 | 8 | private boolean isPrimitive; 9 | 10 | public NumberConverter(boolean primitive) { 11 | isPrimitive = primitive; 12 | } 13 | 14 | public V convert(Object val) { 15 | if (val == null) { 16 | return isPrimitive ? convertNumberValue(0) : null; 17 | } 18 | 19 | // val.getClass().isPrimitive() is ALWAYS false 20 | // since boxing (i.e. Object val=(int)1;) 21 | // changes type from Integet.TYPE to Integer.class 22 | // learn 2 java :) 23 | 24 | else if (/*val.getClass().isPrimitive() || */val instanceof Number ) { 25 | return convertNumberValue((Number)val); 26 | } 27 | else if (val instanceof String){ 28 | String stringVal = ((String)val).trim(); 29 | stringVal = stringVal.isEmpty() ? null : stringVal; 30 | 31 | if (stringVal == null) { 32 | return isPrimitive ? convertNumberValue(0) : null; 33 | } 34 | 35 | return convertStringValue(stringVal); 36 | } 37 | else{ 38 | throw new IllegalArgumentException("Cannot convert type " + val.getClass().toString() + " to " + getTypeDescription()); 39 | } 40 | } 41 | 42 | protected abstract V convertNumberValue(Number val); 43 | 44 | protected abstract V convertStringValue(String val); 45 | 46 | protected abstract String getTypeDescription(); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/exception/AnimaException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.exception; 17 | 18 | import com.hellokaton.anima.enums.ErrorCode; 19 | import lombok.Getter; 20 | 21 | @Getter 22 | public class AnimaException extends RuntimeException { 23 | 24 | private static final long serialVersionUID = 3030374277105375809L; 25 | 26 | private Integer code; 27 | private String message; 28 | 29 | public AnimaException() { 30 | super(); 31 | } 32 | 33 | public AnimaException(ErrorCode errorCode) { 34 | super(errorCode.getMsg()); 35 | this.code = errorCode.getCode(); 36 | this.message = errorCode.getMsg(); 37 | } 38 | 39 | public AnimaException(String message, Throwable cause) { 40 | super(message, cause); 41 | } 42 | 43 | public AnimaException(String message) { 44 | super(message); 45 | } 46 | 47 | public AnimaException(Throwable cause) { 48 | super(cause); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/tools/AbstractCache.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.tools; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReadWriteLock; 7 | import java.util.concurrent.locks.ReentrantReadWriteLock; 8 | 9 | /** 10 | * just inherit and implement evaluate 11 | * User: dimzon 12 | * Date: 4/6/14 13 | * Time: 10:35 PM 14 | */ 15 | public abstract class AbstractCache { 16 | private final Map map; 17 | private final Lock rl; 18 | private final Lock wl; 19 | /*** 20 | * @param map - allows to define your own map implementation 21 | */ 22 | public AbstractCache(Map map) { 23 | this.map = map; 24 | ReadWriteLock rrwl = new ReentrantReadWriteLock(); 25 | rl = rrwl.readLock(); 26 | wl = rrwl.writeLock(); 27 | } 28 | 29 | public AbstractCache(){ 30 | this(new HashMap()); 31 | } 32 | 33 | public V get(K key,E param){ 34 | V value; 35 | 36 | try { 37 | // let's take read lock first 38 | rl.lock(); 39 | value = map.get(key); 40 | } finally { 41 | rl.unlock(); 42 | } 43 | if(value!=null) return value; 44 | 45 | try { 46 | wl.lock(); 47 | value = map.get(key); 48 | if(value==null){ 49 | value = evaluate(key, param); 50 | map.put(key,value); 51 | } 52 | } finally { 53 | wl.unlock(); 54 | } 55 | return value; 56 | } 57 | 58 | protected abstract V evaluate(K key, E param); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/ResultKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.core; 17 | 18 | import java.math.BigInteger; 19 | 20 | /** 21 | * Result Key 22 | *

23 | * Stores the return value of the primary key when the data is saved 24 | * 25 | * @author biezhi 26 | * @date 2018/3/16 27 | */ 28 | public class ResultKey { 29 | 30 | private Object key; 31 | 32 | public ResultKey(Object key) { 33 | this.key = key; 34 | } 35 | 36 | public Integer asInt() { 37 | if (key instanceof Long) { 38 | return asLong().intValue(); 39 | } 40 | if (key instanceof BigInteger) { 41 | return asBigInteger().intValue(); 42 | } 43 | return (Integer) key; 44 | } 45 | 46 | 47 | public Long asLong() { 48 | return (Long) key; 49 | } 50 | 51 | public BigInteger asBigInteger() { 52 | return (BigInteger) key; 53 | } 54 | 55 | public String asString() { 56 | return key.toString(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/ConnectionTransactionTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import org.junit.Test; 4 | import org.sql2o.quirks.NoQuirks; 5 | 6 | import javax.sql.DataSource; 7 | import java.sql.Connection; 8 | 9 | import static org.mockito.Mockito.*; 10 | 11 | /** 12 | * Test to check if the autoCommit state has been reset upon close 13 | */ 14 | public class ConnectionTransactionTest { 15 | 16 | @Test 17 | public void beginTransaction() throws Exception { 18 | final DataSource dataSource = mock(DataSource.class); 19 | final Connection connectionMock = mock(Connection.class); 20 | 21 | // mocked behaviour 22 | when(dataSource.getConnection()).thenReturn(connectionMock); 23 | when(connectionMock.getAutoCommit()).thenReturn(true); 24 | when(connectionMock.isClosed()).thenReturn(false); 25 | 26 | final Sql2o sql2o = new Sql2o(dataSource, new NoQuirks()); 27 | final org.sql2o.Connection sql2oConnection = sql2o.beginTransaction(); 28 | sql2oConnection.close(); 29 | 30 | // Verifications 31 | verify(dataSource).getConnection(); 32 | verify(connectionMock, atLeastOnce()).getAutoCommit(); 33 | // called on beginTransaction 34 | verify(connectionMock, times(1)).setAutoCommit(eq(false)); 35 | // called on closeConnection to reset autocommit state 36 | verify(connectionMock, times(1)).setAutoCommit(eq(true)); 37 | verify(connectionMock, atLeastOnce()).setTransactionIsolation(anyInt()); 38 | verify(connectionMock, times(1)).isClosed(); 39 | verify(connectionMock, times(1)).close(); 40 | verifyNoMoreInteractions(connectionMock, dataSource); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/dml/Select.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.core.dml; 17 | 18 | import com.hellokaton.anima.Model; 19 | import com.hellokaton.anima.core.AnimaQuery; 20 | import com.hellokaton.anima.core.ResultList; 21 | import lombok.NoArgsConstructor; 22 | 23 | import java.util.Map; 24 | 25 | /** 26 | * Select From 27 | * 28 | * @author biezhi 29 | * @date 2018/3/18 30 | */ 31 | @NoArgsConstructor 32 | public class Select { 33 | 34 | private String columns; 35 | 36 | public Select(String columns) { 37 | this.columns = columns; 38 | } 39 | 40 | public AnimaQuery from(Class modelClass) { 41 | return new AnimaQuery<>(modelClass).select(this.columns); 42 | } 43 | 44 | public ResultList bySQL(Class type, String sql, Object... params) { 45 | return new ResultList<>(type, sql, params); 46 | } 47 | 48 | public > ResultList bySQL(String sql, Object... params) { 49 | return new ResultList<>(null, sql, params); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/OracleQuirksProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Lars Aaberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | * 6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | package org.sql2o.quirks; 12 | 13 | /** 14 | * Created by lars on 28.10.14. 15 | */ 16 | public class OracleQuirksProvider implements QuirksProvider { 17 | @Override 18 | public Quirks provide() { 19 | return new OracleQuirks(); 20 | } 21 | 22 | @Override 23 | public boolean isUsableForUrl(String url) { 24 | return url.startsWith("jdbc:oracle:"); 25 | } 26 | 27 | @Override 28 | public boolean isUsableForClass(String className) { 29 | return className.startsWith("oracle.jdbc.") 30 | || className.startsWith("oracle.jdbc."); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/JoinParam.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.core; 2 | 3 | import com.hellokaton.anima.Model; 4 | import com.hellokaton.anima.core.functions.TypeFunction; 5 | import com.hellokaton.anima.enums.OrderBy; 6 | import com.hellokaton.anima.utils.AnimaUtils; 7 | import lombok.Data; 8 | 9 | /** 10 | * @author biezhi 11 | * @date 2018/4/16 12 | */ 13 | @Data 14 | public class JoinParam { 15 | 16 | private Class joinModel; 17 | private String onLeft; 18 | private String onRight; 19 | private String fieldName; 20 | private String orderBy; 21 | 22 | public JoinParam(Class joinModel) { 23 | this.joinModel = joinModel; 24 | } 25 | 26 | public JoinParam as(TypeFunction function) { 27 | String fieldName = AnimaUtils.getLambdaColumnName(function); 28 | this.setFieldName(fieldName); 29 | return this; 30 | } 31 | 32 | public JoinParam on(TypeFunction left, TypeFunction right) { 33 | String onLeft = AnimaUtils.getLambdaFieldName(left); 34 | String onRight = AnimaUtils.getLambdaColumnName(right); 35 | this.setOnLeft(onLeft); 36 | this.setOnRight(onRight); 37 | return this; 38 | } 39 | 40 | public JoinParam order(TypeFunction rightField, OrderBy orderBy) { 41 | String columnName = AnimaUtils.getLambdaColumnName(rightField); 42 | this.orderBy = columnName + " " + orderBy.name(); 43 | return this; 44 | } 45 | 46 | public JoinParam order(String orderBy) { 47 | this.orderBy = orderBy; 48 | return this; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/Db2QuirksProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Lars Aaberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | * 6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | package org.sql2o.quirks; 12 | 13 | /** 14 | * Created by lars on 28.10.14. 15 | */ 16 | public class Db2QuirksProvider implements QuirksProvider { 17 | @Override 18 | public Quirks provide() { 19 | return new Db2Quirks(); 20 | } 21 | 22 | @Override 23 | public boolean isUsableForUrl(String url) { 24 | return url.startsWith("jdbc:db2:") 25 | || url.startsWith("jdbc:db2j:net:") 26 | || url.startsWith("jdbc:db2os390"); 27 | } 28 | 29 | @Override 30 | public boolean isUsableForClass(String className) { 31 | return className.startsWith("com.ibm.db2.jcc.DB2"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/SQLParams.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | *

7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | *

9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package com.hellokaton.anima.core; 14 | 15 | import com.hellokaton.anima.Model; 16 | import com.hellokaton.anima.page.PageRow; 17 | import lombok.Builder; 18 | import lombok.Data; 19 | 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | /** 24 | * SQLParams 25 | *

26 | * This class is used to store the parameters of the generated SQL. 27 | * 28 | * @author biezhi 29 | * @date 2018/3/17 30 | */ 31 | @Data 32 | @Builder 33 | public class SQLParams { 34 | 35 | private Class modelClass; 36 | private Object model; 37 | private String selectColumns; 38 | private String tableName; 39 | private String pkName; 40 | private StringBuilder conditionSQL; 41 | private List columnValues; 42 | private Map updateColumns; 43 | private List excludedColumns; 44 | private PageRow pageRow; 45 | private String orderBy; 46 | private boolean isSQLLimit; 47 | 48 | private String customSQL; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/StringConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import org.sql2o.tools.IOUtils; 4 | 5 | import java.io.IOException; 6 | import java.io.Reader; 7 | import java.sql.Clob; 8 | import java.sql.SQLException; 9 | 10 | /** 11 | * Used by sql2o to convert a value from the database into a {@link String}. 12 | */ 13 | public class StringConverter extends ConverterBase { 14 | 15 | public String convert(Object val) throws ConverterException { 16 | if (val == null){ 17 | return null; 18 | } 19 | 20 | if (val instanceof Clob) { 21 | Clob clobVal = (Clob)val; 22 | try 23 | { 24 | try { 25 | return clobVal.getSubString(1, (int)clobVal.length()); 26 | } catch (SQLException e) { 27 | throw new ConverterException("error converting clob to String", e); 28 | } 29 | } finally { 30 | try { 31 | clobVal.free(); 32 | } catch (Throwable ignore) { 33 | //ignore 34 | } 35 | } 36 | } 37 | 38 | if(val instanceof Reader){ 39 | Reader reader = (Reader) val; 40 | try { 41 | try { 42 | return IOUtils.toString(reader); 43 | } catch (IOException e) { 44 | throw new ConverterException("error converting reader to String", e); 45 | } 46 | } finally { 47 | try { 48 | reader.close(); 49 | } catch (Throwable ignore) { 50 | // ignore 51 | } 52 | } 53 | } 54 | 55 | return val.toString().trim(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/ByteArrayConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import org.sql2o.tools.IOUtils; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.sql.Blob; 8 | import java.sql.SQLException; 9 | 10 | /** 11 | * User: lars 12 | * Date: 6/13/13 13 | * Time: 11:36 PM 14 | */ 15 | public class ByteArrayConverter extends ConverterBase { 16 | 17 | public byte[] convert(Object val) throws ConverterException { 18 | if (val == null) return null; 19 | 20 | if (val instanceof Blob) { 21 | Blob b = (Blob)val; 22 | InputStream stream=null; 23 | try { 24 | try { 25 | stream = b.getBinaryStream(); 26 | return IOUtils.toByteArray(stream); 27 | } finally { 28 | if(stream!=null) { 29 | try { 30 | stream.close(); 31 | } catch (Throwable ignore){ 32 | // ignore stream.close errors 33 | } 34 | } 35 | try { 36 | b.free(); 37 | } catch (Throwable ignore){ 38 | // ignore blob.free errors 39 | } 40 | } 41 | } catch (SQLException e) { 42 | throw new ConverterException("Error converting Blob to byte[]", e); 43 | } catch (IOException e) { 44 | throw new ConverterException("Error converting Blob to byte[]", e); 45 | } 46 | } 47 | 48 | if (val instanceof byte[]){ 49 | return (byte[])val; 50 | } 51 | 52 | throw new RuntimeException("could not convert " + val.getClass().getName() + " to byte[]"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/Db2Quirks.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Lars Aaberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | * 6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | package org.sql2o.quirks; 12 | 13 | import org.sql2o.converters.Converter; 14 | 15 | import java.sql.ResultSetMetaData; 16 | import java.sql.SQLException; 17 | import java.util.Map; 18 | 19 | /** 20 | * @author aldenquimby@gmail.com 21 | * @since 4/6/14 22 | */ 23 | public class Db2Quirks extends NoQuirks { 24 | 25 | public Db2Quirks() { 26 | super(); 27 | } 28 | 29 | public Db2Quirks(Map, Converter> converters) { 30 | super(converters); 31 | } 32 | 33 | // Db2 works perfect with java.sql.Timestamp 34 | // checked on DATE|TIME|TIMESTAMP column types 35 | @Override 36 | public String getColumnName(ResultSetMetaData meta, int colIdx) throws SQLException { 37 | return meta.getColumnName(colIdx); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/data/TableResultSetIterator.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.data; 2 | 3 | import org.sql2o.ResultSetIteratorBase; 4 | import org.sql2o.Sql2oException; 5 | import org.sql2o.quirks.Quirks; 6 | 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | import java.util.*; 10 | 11 | /** 12 | * @author aldenquimby@gmail.com 13 | */ 14 | public class TableResultSetIterator extends ResultSetIteratorBase { 15 | private Map columnNameToIdxMap; 16 | private List columns; 17 | 18 | public TableResultSetIterator(ResultSet rs, boolean isCaseSensitive, Quirks quirks, LazyTable lt) { 19 | super(rs, isCaseSensitive, quirks); 20 | 21 | this.columnNameToIdxMap = new HashMap(); 22 | this.columns = new ArrayList(); 23 | 24 | try { 25 | lt.setName(meta.getTableName(1)); 26 | 27 | for (int colIdx = 1; colIdx <= meta.getColumnCount(); colIdx++){ 28 | String colName = getColumnName(colIdx); 29 | String colType = meta.getColumnTypeName(colIdx); 30 | columns.add(new Column(colName, colIdx - 1, colType)); 31 | 32 | String colMapName = isCaseSensitive ? colName : colName.toLowerCase(); 33 | columnNameToIdxMap.put(colMapName, colIdx - 1); 34 | } 35 | } 36 | catch (SQLException e) { 37 | throw new Sql2oException("Error while reading metadata from database", e); 38 | } 39 | 40 | lt.setColumns(columns); 41 | } 42 | 43 | @Override 44 | protected Row readNext() throws SQLException { 45 | Row row = new Row(columnNameToIdxMap, columns.size(), isCaseSensitive,this.quirks); 46 | for (Column column : columns) { 47 | row.addValue(column.getIndex(), quirks.getRSVal(rs, column.getIndex() + 1)); 48 | } 49 | return row; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/DefaultResultSetHandlerFactoryBuilder.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import org.sql2o.quirks.Quirks; 4 | import org.sql2o.reflection.PojoMetadata; 5 | 6 | import java.util.Map; 7 | 8 | public class DefaultResultSetHandlerFactoryBuilder implements ResultSetHandlerFactoryBuilder { 9 | private boolean caseSensitive; 10 | private boolean autoDeriveColumnNames; 11 | private boolean throwOnMappingError; 12 | private Map columnMappings; 13 | private Quirks quirks; 14 | 15 | public boolean isCaseSensitive() { 16 | return caseSensitive; 17 | } 18 | 19 | public void setCaseSensitive(boolean caseSensitive) { 20 | this.caseSensitive = caseSensitive; 21 | } 22 | 23 | public boolean isAutoDeriveColumnNames() { 24 | return autoDeriveColumnNames; 25 | } 26 | 27 | public void setAutoDeriveColumnNames(boolean autoDeriveColumnNames) { 28 | this.autoDeriveColumnNames = autoDeriveColumnNames; 29 | } 30 | 31 | @Override 32 | public boolean isThrowOnMappingError() { 33 | return throwOnMappingError; 34 | } 35 | 36 | @Override 37 | public void throwOnMappingError(boolean throwOnMappingError) { 38 | this.throwOnMappingError = throwOnMappingError; 39 | } 40 | 41 | public Map getColumnMappings() { 42 | return columnMappings; 43 | } 44 | 45 | public void setColumnMappings(Map columnMappings) { 46 | this.columnMappings = columnMappings; 47 | } 48 | 49 | public Quirks getQuirks() { 50 | return quirks; 51 | } 52 | 53 | public void setQuirks(Quirks quirks) { 54 | this.quirks = quirks; 55 | } 56 | 57 | 58 | 59 | @SuppressWarnings("unchecked") 60 | public ResultSetHandlerFactory newFactory(Class clazz) { 61 | PojoMetadata pojoMetadata = new PojoMetadata(clazz, caseSensitive, autoDeriveColumnNames, columnMappings, throwOnMappingError); 62 | return new DefaultResultSetHandlerFactory(pojoMetadata, quirks); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/utils/Functions.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.utils; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.util.function.Supplier; 6 | 7 | /** 8 | * Functions 9 | * 10 | * @author biezhi 11 | * @date 2018-12-20 12 | */ 13 | @UtilityClass 14 | public class Functions { 15 | 16 | public static void ifNullThrow(K k, T e) throws T { 17 | ifThrow(k == null, e); 18 | } 19 | 20 | public static void ifThrow(boolean flag, T e) throws T { 21 | if (flag) { 22 | throw e; 23 | } 24 | } 25 | 26 | 27 | public static void ifNullThen(Object value, Runnable runnable) { 28 | ifThen(value == null, runnable); 29 | } 30 | 31 | public static void ifNotNullThen(Object value, Runnable runnable) { 32 | ifThen(value != null, runnable); 33 | } 34 | 35 | public static void ifThen(boolean flag, T t) { 36 | if (flag) { 37 | t.run(); 38 | } 39 | } 40 | 41 | public static void ifThen(boolean flag, T t1, T t2) { 42 | if (flag) { 43 | t1.run(); 44 | } else { 45 | t2.run(); 46 | } 47 | } 48 | 49 | public static T ifNotNullReturn(K value, T t1, T t2) { 50 | return ifReturn(value != null, t1, t2); 51 | } 52 | 53 | public static T ifNotNullReturn(T value, Supplier supplier) { 54 | if (null != value) { 55 | return value; 56 | } 57 | return supplier.get(); 58 | } 59 | 60 | public static T ifReturn(boolean flag, T t1, T t2) { 61 | return (flag ? t1 : t2); 62 | } 63 | 64 | public static T ifReturn(boolean flag, Supplier s1, Supplier s2) { 65 | if (flag) { 66 | return s1.get(); 67 | } 68 | return s2.get(); 69 | } 70 | 71 | public static T ifReturnOrThrow(boolean flag, T t1, RuntimeException e) { 72 | if (flag) return t1; 73 | throw e; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/Atomic.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.core; 17 | 18 | import lombok.NoArgsConstructor; 19 | 20 | import java.util.function.Consumer; 21 | import java.util.function.Function; 22 | 23 | /** 24 | * Atomic 25 | *

26 | * Used to save the exception information after the end of a transaction. 27 | * There is currently no other storage. 28 | * You can catch and handle them after an exception occurs. 29 | * 30 | * @author biezhi 31 | * @date 2018/3/15 32 | */ 33 | @NoArgsConstructor 34 | public class Atomic { 35 | 36 | private Exception e; 37 | private boolean isRollback; 38 | 39 | public Atomic(Exception e) { 40 | this.e = e; 41 | } 42 | 43 | public static Atomic ok() { 44 | return new Atomic(); 45 | } 46 | 47 | public static Atomic error(Exception e) { 48 | return new Atomic(e); 49 | } 50 | 51 | public Atomic rollback(boolean isRollback) { 52 | this.isRollback = isRollback; 53 | return this; 54 | } 55 | 56 | public boolean isRollback() { 57 | return isRollback; 58 | } 59 | 60 | public Atomic catchException(Consumer consumer) { 61 | if (null != e) { 62 | consumer.accept(e); 63 | } 64 | return this; 65 | } 66 | 67 | public R catchAndReturn(Function function) { 68 | if (null != e) { 69 | return function.apply(e); 70 | } 71 | return null; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/core/ResultList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi 王爵 (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hellokaton.anima.core; 17 | 18 | import com.hellokaton.anima.Model; 19 | import com.hellokaton.anima.page.Page; 20 | import com.hellokaton.anima.page.PageRow; 21 | 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | /** 26 | * ResultList 27 | *

28 | * Get a list of collections or single data 29 | * 30 | * @author biezhi 31 | * @date 2018/3/16 32 | */ 33 | public class ResultList { 34 | 35 | 36 | private final Class type; 37 | private final String sql; 38 | private final Object[] params; 39 | 40 | public ResultList(Class type, String sql, Object[] params) { 41 | this.type = type; 42 | this.sql = sql; 43 | this.params = params; 44 | } 45 | 46 | public T one() { 47 | return new AnimaQuery<>().useSQL().queryOne(type, sql, params); 48 | } 49 | 50 | public List all() { 51 | return new AnimaQuery<>().useSQL().queryList(type, sql, params); 52 | } 53 | 54 | public List> maps(){ 55 | return new AnimaQuery<>().useSQL().queryListMap(sql, params); 56 | } 57 | 58 | public Page page(PageRow pageRow) { 59 | Class modelType = (Class) type; 60 | return new AnimaQuery<>(modelType).useSQL().page(sql, params, pageRow); 61 | } 62 | 63 | public Page page(int page, int limit) { 64 | return this.page(new PageRow(page, limit)); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/OtherTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.model.User; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import static com.hellokaton.anima.Anima.select; 8 | 9 | /** 10 | * @author biezhi 11 | * @date 2018/3/14 12 | */ 13 | public class OtherTest extends BaseTest { 14 | 15 | @Test 16 | public void testTx1() { 17 | Anima.atomic(() -> { 18 | int a = 1 / 0; 19 | System.out.println(a); 20 | new User("apple", 666).save(); 21 | }).catchException(e -> { 22 | e.printStackTrace(); 23 | Assert.assertEquals(ArithmeticException.class, e.getClass()); 24 | }); 25 | 26 | Assert.assertEquals(8, Anima.select().from(User.class).count()); 27 | } 28 | 29 | @Test 30 | public void testTx2() { 31 | Anima.atomic(() -> new User("google", 666).save()); 32 | Assert.assertEquals(9, Anima.select().from(User.class).count()); 33 | } 34 | 35 | @Test 36 | public void testTx3() { 37 | Anima.atomic(() -> { 38 | Anima.select().from(User.class).count(); 39 | int a = 1 / 0; 40 | System.out.println(a); 41 | new User("apple2018", 666).save(); 42 | }).catchException(e -> { 43 | Assert.assertEquals(ArithmeticException.class, e.getClass()); 44 | }); 45 | 46 | Assert.assertEquals(0, Anima.select().from(User.class).where(User::getUserName, "apple2018").count()); 47 | } 48 | 49 | @Test 50 | public void testTx4() { 51 | Integer res = Anima.atomic(() -> { 52 | int a = 1 / 0; 53 | System.out.println(a); 54 | new User("apple2018", 666).save(); 55 | }).catchAndReturn(e -> { 56 | Assert.assertEquals(ArithmeticException.class, e.getClass()); 57 | return 0; 58 | }); 59 | Assert.assertEquals(Integer.valueOf(0), res); 60 | } 61 | 62 | @Test 63 | public void testExecute(){ 64 | Anima.execute("drop table if exists hello_world"); 65 | Anima.execute("create table hello_world(int integer not null)"); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/extensions/postgres/converters/JSONConverter.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.extensions.postgres.converters; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonParser; 6 | import org.postgresql.util.PGobject; 7 | import org.sql2o.converters.Converter; 8 | import org.sql2o.converters.ConverterException; 9 | import org.sql2o.converters.ConvertersProvider; 10 | import org.sql2o.converters.StringConverter; 11 | 12 | import java.util.Map; 13 | 14 | /** 15 | * User: dimzon 16 | * Date: 4/25/14 17 | * Time: 12:08 AM 18 | */ 19 | public class JSONConverter implements Converter, ConvertersProvider { 20 | 21 | public void fill(Map, Converter> mapToFill) { 22 | mapToFill.put(JsonElement.class, this); 23 | } 24 | 25 | public JsonElement convert(Object val) throws ConverterException { 26 | if (val == null) return null; 27 | if (val instanceof JsonElement) return (JsonElement) val; 28 | String jsonString; 29 | if (val instanceof String) { 30 | jsonString = (String) val; 31 | } else if (val instanceof PGobject) { 32 | // at one side this is just a demo 33 | // the better way is to unwrap PGObject to String 34 | // with type==json in Quirks.getRSVal 35 | jsonString = ((PGobject) val).getValue(); 36 | } else { 37 | jsonString = stringConverterHolder.converter.convert(val); 38 | } 39 | return parserHolder.parser.parse(jsonString); 40 | } 41 | 42 | public Object toDatabaseParam(JsonElement val) { 43 | if (val == null) return null; 44 | final StringBuilder stringBuilder = new StringBuilder(); 45 | writerHolder.gson.toJson(val, stringBuilder); 46 | return stringBuilder.toString(); 47 | } 48 | 49 | static class parserHolder { 50 | static final JsonParser parser = new JsonParser(); 51 | } 52 | 53 | static class writerHolder { 54 | static final Gson gson = new Gson(); 55 | } 56 | 57 | static class stringConverterHolder { 58 | static final StringConverter converter = new StringConverter(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/LambdaTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.enums.OrderBy; 4 | import com.hellokaton.anima.model.User; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import java.util.List; 9 | 10 | import static com.hellokaton.anima.Anima.select; 11 | 12 | /** 13 | * Java 8 lambda Test 14 | * 15 | * @author biezhi 16 | * @date 2018/3/13 17 | */ 18 | public class LambdaTest extends BaseTest { 19 | 20 | @Test 21 | public void testOne() { 22 | User user = Anima.select().from(User.class).where(User::getUserName).eq("jack").one(); 23 | Assert.assertNotNull(user); 24 | } 25 | 26 | @Test 27 | public void testAll() { 28 | List user = Anima.select().from(User.class) 29 | .where(User::getUserName).notNull() 30 | .and(User::getAge).gt(10) 31 | .order(User::getId, OrderBy.DESC) 32 | .all(); 33 | 34 | Assert.assertNotNull(user); 35 | } 36 | 37 | @Test 38 | public void testSelect() { 39 | List users = Anima.select(User::getUserName, User::getAge).from(User.class).limit(3); 40 | Assert.assertNotNull(users); 41 | Assert.assertEquals(3, users.size()); 42 | Assert.assertNull(users.get(0).getId()); 43 | } 44 | 45 | @Test 46 | public void testOrderBy() { 47 | Anima.select().from(User.class).order(User::getId, OrderBy.DESC).order(User::getAge, OrderBy.ASC).all(); 48 | } 49 | 50 | @Test 51 | public void testUpdate() { 52 | int result = Anima.update().from(User.class).set(User::getUserName, "base64").updateById(2); 53 | Assert.assertEquals(1, result); 54 | result = Anima.update().from(User.class).set(User::getUserName, "base64").where(User::getId).eq(2).execute(); 55 | Assert.assertEquals(1, result); 56 | } 57 | 58 | @Test 59 | public void testDelete() { 60 | Anima.delete().from(User.class).where(User::getId).deleteById(3); 61 | Anima.delete().from(User.class).where(User::getId).eq(1).execute(); 62 | Anima.delete().from(User.class).where(User::getAge).lte(20).execute(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/UpdateTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.model.User; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | /** 8 | * Save 9 | * 10 | * @author biezhi 11 | * @date 2018/3/14 12 | */ 13 | public class UpdateTest extends BaseTest { 14 | 15 | @Test 16 | public void testUpdate() { 17 | String newName = "biezhi_" + System.currentTimeMillis(); 18 | int result = Anima.update().from(User.class).set("user_name", newName).execute(); 19 | Assert.assertEquals(8, result); 20 | 21 | result = Anima.update().from(User.class).set("user_name", newName).where("id", 1).execute(); 22 | Assert.assertEquals(1, result); 23 | } 24 | 25 | @Test 26 | public void testUpdate2() { 27 | User user = new User(); 28 | user.setUserName("jack"); 29 | user.update(); 30 | 31 | Long start = System.currentTimeMillis(); 32 | for (int i = 0; i < 100; i++) { 33 | user = new User(); 34 | user.setUserName("jack"); 35 | user.updateById(1); 36 | } 37 | System.out.println("OK: " + (System.currentTimeMillis() - start) + "ms"); 38 | 39 | // while (true) { 40 | // try { 41 | // TimeUnit.SECONDS.sleep(2); 42 | // } catch (InterruptedException e) { 43 | // e.printStackTrace(); 44 | // } 45 | // } 46 | // Assert.assertEquals(1, result); 47 | } 48 | 49 | @Test 50 | public void testUpdate3() { 51 | new User().set("user_name", "jack").where("id", 2).update(); 52 | new User().set("user_name", "jack").updateById(3); 53 | 54 | new User().set(User::getUserName, "jack").where(User::getId, 2).update(); 55 | new User().set(User::getUserName, "jack").updateById(3); 56 | 57 | Anima.update().from(User.class).set(User::getUserName, "jack").where(User::getId, 2).execute(); 58 | Anima.update().from(User.class).set(User::getUserName, "jack").updateById(3); 59 | } 60 | 61 | @Test 62 | public void testUpdate4() { 63 | User user = new User(); 64 | user.setId(1); 65 | user.setUserName("lili"); 66 | user.update(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/MethodAccessorsGeneratorObjectConstructorFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import org.sql2o.reflection.MethodAccessorsGenerator; 4 | 5 | /** 6 | * User: dimzon 7 | * Date: 5/13/14 8 | * Time: 3:45 AM 9 | */ 10 | public class MethodAccessorsGeneratorObjectConstructorFactoryTest extends AbstractObjectConstructorFactoryTest { 11 | public class POJO2{ 12 | public boolean constructorInvoked = true; 13 | public POJO2() { 14 | fail("Constructor can't be called"); 15 | } 16 | public Object parent(){ 17 | return MethodAccessorsGeneratorObjectConstructorFactoryTest.this; 18 | } 19 | } 20 | public static class POJO3{ 21 | public boolean constructorInvoked = true; 22 | } 23 | 24 | public class POJO4 extends POJO3 { 25 | public boolean pojo4_constructorInvoked = true; 26 | 27 | public POJO4() { 28 | fail("Constructor can't be called"); 29 | } 30 | } 31 | 32 | public MethodAccessorsGeneratorObjectConstructorFactoryTest() { 33 | super(new MethodAccessorsGenerator()); 34 | } 35 | 36 | public void testCantCallConstructor(){ 37 | POJO2 pojo2 = (POJO2) ocf.newConstructor(POJO2.class).newInstance(); 38 | assertNotNull(pojo2); 39 | assertNull(pojo2.parent()); 40 | assertFalse(pojo2.constructorInvoked); 41 | } 42 | public void testCallConstructor(){ 43 | POJO3 pojo3 = (POJO3) ocf.newConstructor(POJO3.class).newInstance(); 44 | assertNotNull(pojo3); 45 | assertTrue(pojo3.constructorInvoked); 46 | } 47 | public void testCallParentConstructor(){ 48 | POJO4 pojo = (POJO4) ocf.newConstructor(POJO4.class).newInstance(); 49 | assertNotNull(pojo); 50 | assertTrue(pojo.constructorInvoked); 51 | assertFalse(pojo.pojo4_constructorInvoked); 52 | } 53 | 54 | public void testCallParentConstructor2(){ 55 | class POJO5 extends POJO4 { 56 | public boolean pojo5_constructorInvoked = true; 57 | } 58 | 59 | POJO5 pojo = (POJO5) ocf.newConstructor(POJO5.class).newInstance(); 60 | assertNotNull(pojo); 61 | assertTrue(pojo.constructorInvoked); 62 | assertFalse(pojo.pojo5_constructorInvoked); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/Quirks.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.quirks; 2 | 3 | import org.sql2o.converters.Converter; 4 | 5 | import java.io.InputStream; 6 | import java.sql.*; 7 | import java.util.Map; 8 | import java.util.UUID; 9 | 10 | /** 11 | * Interface for JDBC driver specific quirks. 12 | * See {@link NoQuirks} for defaults. 13 | * 14 | * @author aldenquimby@gmail.com 15 | * @since 4/6/14 16 | */ 17 | public interface Quirks { 18 | 19 | /** 20 | * @param ofClass 21 | * @param 22 | * @return converter for class 23 | */ 24 | Converter converterOf(Class ofClass); 25 | 26 | void addConverter(Class type, Converter converter); 27 | 28 | /** 29 | * @return name of column at index {@code colIdx} for result set {@code meta} 30 | */ 31 | String getColumnName(ResultSetMetaData meta, int colIdx) throws SQLException; 32 | 33 | /** 34 | * @return true if queries should return generated keys by default, false otherwise 35 | */ 36 | boolean returnGeneratedKeysByDefault(); 37 | 38 | void setParameter(PreparedStatement statement, int paramIdx, Object value) throws SQLException; 39 | void setParameter(PreparedStatement statement, int paramIdx, InputStream value) throws SQLException; 40 | void setParameter(PreparedStatement statement, int paramIdx, int value) throws SQLException; 41 | void setParameter(PreparedStatement statement, int paramIdx, Integer value) throws SQLException; 42 | void setParameter(PreparedStatement statement, int paramIdx, long value) throws SQLException; 43 | void setParameter(PreparedStatement statement, int paramIdx, Long value) throws SQLException; 44 | void setParameter(PreparedStatement statement, int paramIdx, String value) throws SQLException; 45 | void setParameter(PreparedStatement statement, int paramIdx, Timestamp value) throws SQLException; 46 | void setParameter(PreparedStatement statement, int paramIdx, Time value) throws SQLException; 47 | void setParameter(PreparedStatement statement, int paramIdx, boolean value) throws SQLException; 48 | void setParameter(PreparedStatement statement, int paramIdx, Boolean value) throws SQLException; 49 | void setParameter(PreparedStatement statement, int paramIdx, UUID value) throws SQLException; 50 | 51 | Object getRSVal(ResultSet rs, int idx) throws SQLException; 52 | 53 | void closeStatement(Statement statement) throws SQLException; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/Sql2oDataSourceTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import com.hellokaton.anima.Anima; 4 | import junit.framework.TestCase; 5 | import org.h2.jdbcx.JdbcConnectionPool; 6 | 7 | import javax.sql.DataSource; 8 | import java.util.List; 9 | 10 | /** 11 | * Created with IntelliJ IDEA. 12 | * User: lars 13 | * Date: 10/5/12 14 | * Time: 10:54 PM 15 | * To change this template use File | Settings | File Templates. 16 | */ 17 | public class Sql2oDataSourceTest extends TestCase { 18 | 19 | private Sql2o sql2o; 20 | 21 | private String url = "jdbc:h2:mem:test2;DB_CLOSE_DELAY=-1"; 22 | private String user = "sa"; 23 | private String pass = ""; 24 | 25 | @Override 26 | protected void setUp() throws Exception { 27 | DataSource ds = JdbcConnectionPool.create(url, user, pass); 28 | sql2o = new Sql2o(ds); 29 | Anima.open(sql2o); 30 | } 31 | 32 | public void testExecuteAndFetchWithNulls() { 33 | String sql = 34 | "create table testExecWithNullsTbl (" + 35 | "id int identity primary key, " + 36 | "text varchar(255), " + 37 | "aNumber int, " + 38 | "aLongNumber bigint)"; 39 | 40 | sql2o.open().createQuery(sql).setName("testExecuteAndFetchWithNulls").executeUpdate(); 41 | 42 | sql2o.runInTransaction((connection, argument) -> { 43 | Query insQuery = connection.createQuery("insert into testExecWithNullsTbl (text, aNumber, aLongNumber) values(?, ?, ?)"); 44 | insQuery.withParams("some text", 11, 10L).executeUpdate(); 45 | insQuery.withParams("some text", (Integer) null, 10L).executeUpdate(); 46 | insQuery.withParams((String) null, 21, (Long) null).executeUpdate(); 47 | insQuery.withParams("some text", 1221, 10).executeUpdate(); 48 | insQuery.withParams("some text", 2311, 12).executeUpdate(); 49 | }); 50 | 51 | List fetched = sql2o.open().createQuery("select * from testExecWithNullsTbl").executeAndFetch(Entity.class); 52 | 53 | assertTrue(fetched.size() == 5); 54 | assertNull(fetched.get(2).text); 55 | assertNotNull(fetched.get(3).text); 56 | 57 | assertNull(fetched.get(1).aNumber); 58 | assertNotNull(fetched.get(2).aNumber); 59 | 60 | assertNull(fetched.get(2).aLongNumber); 61 | assertNotNull(fetched.get(3).aLongNumber); 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/AbstractFieldGetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import org.sql2o.reflection.FieldGetterFactory; 6 | import org.sql2o.reflection.Getter; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author mdelapenya 12 | */ 13 | public abstract class AbstractFieldGetterFactoryTest extends TestCase { 14 | public static class POJO1{ 15 | boolean _boolean; 16 | byte _byte; 17 | short _short; 18 | int _int; 19 | long _long; 20 | float _float; 21 | double _double; 22 | char _char; 23 | Object _obj; 24 | 25 | @Override 26 | public boolean equals(Object o) { 27 | if (this == o) return true; 28 | 29 | if (o == null || getClass() != o.getClass()) return false; 30 | 31 | POJO1 pojo1 = (POJO1) o; 32 | 33 | if (_boolean != pojo1._boolean) return false; 34 | if (_byte != pojo1._byte) return false; 35 | if (_char != pojo1._char) return false; 36 | if (Double.compare(pojo1._double, _double) != 0) return false; 37 | if (Float.compare(pojo1._float, _float) != 0) return false; 38 | if (_int != pojo1._int) return false; 39 | if (_long != pojo1._long) return false; 40 | if (_short != pojo1._short) return false; 41 | if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; 42 | 43 | return true; 44 | } 45 | } 46 | 47 | public void testAllTypes() throws IllegalAccessException { 48 | POJO1 pojo = new POJO1(); 49 | pojo._boolean = true; 50 | pojo._byte = 17; 51 | pojo._short=87; 52 | pojo._int= Integer.MIN_VALUE; 53 | pojo._long= 1337; 54 | pojo._char='a'; 55 | pojo._double=Math.PI; 56 | pojo._float= (float) Math.log(93); 57 | pojo._obj = pojo; 58 | 59 | Field[] fields = pojo.getClass().getDeclaredFields(); 60 | 61 | for (Field field : fields) { 62 | Getter getter = fgf.newGetter(field); 63 | assertSame(field.getType(),getter.getType()); 64 | 65 | Object val1 = field.get(pojo); 66 | assertEquals(val1, getter.getProperty(pojo)); 67 | } 68 | } 69 | 70 | public final FieldGetterFactory fgf; 71 | 72 | protected AbstractFieldGetterFactoryTest(FieldGetterFactory fgf) { 73 | this.fgf = fgf; 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/QuirksDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Lars Aaberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | * 6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | package org.sql2o.quirks; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.ServiceLoader; 16 | 17 | /** 18 | * Automatically detects which quirks implementation to use. Falls back on NoQuirks. 19 | */ 20 | public class QuirksDetector { 21 | 22 | static final List providers = new ArrayList<>(); 23 | 24 | static { 25 | providers.add(new PostgresQuirksProvider()); 26 | providers.add(new OracleQuirksProvider()); 27 | providers.add(new Db2QuirksProvider()); 28 | } 29 | 30 | public static Quirks forURL(String jdbcUrl) { 31 | 32 | for (QuirksProvider quirksProvider : providers) { 33 | if (quirksProvider.isUsableForUrl(jdbcUrl)) { 34 | return quirksProvider.provide(); 35 | } 36 | } 37 | return new NoQuirks(); 38 | } 39 | 40 | public static Quirks forObject(Object jdbcObject) { 41 | 42 | String jdbcObjectClassName = jdbcObject.getClass().getName().contains("$") ? 43 | jdbcObject.getClass().getSuperclass().getCanonicalName() : 44 | jdbcObject.getClass().getCanonicalName(); 45 | 46 | for (QuirksProvider quirksProvider : ServiceLoader.load(QuirksProvider.class)) { 47 | if (quirksProvider.isUsableForClass(jdbcObjectClassName)) { 48 | return quirksProvider.provide(); 49 | } 50 | } 51 | 52 | return new NoQuirks(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/quirks/OracleQuirks.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Lars Aaberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | * 6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | package org.sql2o.quirks; 12 | 13 | import org.sql2o.converters.Converter; 14 | import org.sql2o.converters.OracleUUIDConverter; 15 | 16 | import java.sql.PreparedStatement; 17 | import java.sql.ResultSet; 18 | import java.sql.SQLException; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | import java.util.UUID; 22 | 23 | public class OracleQuirks extends NoQuirks { 24 | public OracleQuirks() { 25 | super(new HashMap, Converter>() {{ 26 | put(UUID.class, new OracleUUIDConverter()); 27 | }}); 28 | } 29 | 30 | public OracleQuirks(Map, Converter> converters) { 31 | super(converters); 32 | } 33 | 34 | @Override 35 | public Object getRSVal(ResultSet rs, int idx) throws SQLException { 36 | Object o = super.getRSVal(rs, idx); 37 | // oracle timestamps are not always convertible to a java Date. If ResultSet.getTimestamp is used instead of 38 | // ResultSet.getObject, a normal java.sql.Timestamp instance is returnd. 39 | if (o != null && o.getClass().getCanonicalName().startsWith("oracle.sql.TIMESTAMP")){ 40 | //TODO: use TIMESTAMP.dateValue 41 | o = rs.getTimestamp(idx); 42 | } 43 | return o; 44 | } 45 | 46 | @Override 47 | public boolean returnGeneratedKeysByDefault() { 48 | return false; 49 | } 50 | 51 | @Override 52 | public void setParameter(PreparedStatement statement, int paramIdx, UUID value) throws SQLException { 53 | statement.setBytes(paramIdx, (byte[])new OracleUUIDConverter().toDatabaseParam(value)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/Model.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.core.ResultKey; 4 | import com.hellokaton.anima.core.functions.TypeFunction; 5 | import com.hellokaton.anima.core.AnimaQuery; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * Base Model 11 | * 12 | * @author biezhi 13 | * @date 2018/3/16 14 | */ 15 | public class Model { 16 | 17 | /** 18 | * The query object for the current model. 19 | */ 20 | private transient AnimaQuery query = new AnimaQuery<>(this.getClass()); 21 | 22 | /** 23 | * Save model 24 | * 25 | * @return ResultKey 26 | */ 27 | public ResultKey save() { 28 | return query.save(this); 29 | } 30 | 31 | /** 32 | * Update model 33 | * 34 | * @return number of rows affected after execution 35 | */ 36 | public int update() { 37 | return query.updateByModel(this); 38 | } 39 | 40 | /** 41 | * Update by primary key 42 | * 43 | * @param id pk 44 | * @return number of rows affected after execution 45 | */ 46 | public int updateById(Serializable id) { 47 | return new AnimaQuery<>(this.getClass()).updateById(this, id); 48 | } 49 | 50 | /** 51 | * Delete model 52 | * 53 | * @return number of rows affected after execution 54 | */ 55 | public int delete() { 56 | return query.deleteByModel(this); 57 | } 58 | 59 | /** 60 | * Update set statement 61 | * 62 | * @param column table column name [sql] 63 | * @param value column value 64 | * @return AnimaQuery 65 | */ 66 | public AnimaQuery set(String column, Object value) { 67 | return query.set(column, value); 68 | } 69 | 70 | /** 71 | * Update set statement with lambda 72 | * 73 | * @param function table column name with lambda 74 | * @param value column value 75 | * @param 76 | * @param 77 | * @return AnimaQuery 78 | */ 79 | public AnimaQuery set(TypeFunction function, Object value) { 80 | return query.set(function, value); 81 | } 82 | 83 | /** 84 | * Where statement 85 | * 86 | * @param statement conditional clause 87 | * @param value column value 88 | * @return AnimaQuery 89 | */ 90 | public AnimaQuery where(String statement, Object value) { 91 | return query.where(statement, value); 92 | } 93 | 94 | /** 95 | * Where statement with lambda 96 | * 97 | * @param function column name with lambda 98 | * @param value column value 99 | * @param 100 | * @param 101 | * @return AnimaQuery 102 | */ 103 | public AnimaQuery where(TypeFunction function, Object value) { 104 | return query.where(function, value); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/GenericDatasource.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import javax.sql.DataSource; 4 | import java.io.PrintWriter; 5 | import java.sql.Connection; 6 | import java.sql.DriverManager; 7 | import java.sql.SQLException; 8 | import java.sql.SQLFeatureNotSupportedException; 9 | import java.util.Properties; 10 | 11 | /** 12 | * Used internally by sql2o, if the {@link Sql2o#Sql2o(String, String, String)} constructor overload. 13 | */ 14 | public class GenericDatasource implements DataSource { 15 | 16 | private final String url; 17 | private final Properties properties; 18 | 19 | public GenericDatasource(String url, String user, String password) { 20 | 21 | if (!url.startsWith("jdbc")){ 22 | url = "jdbc:" + url; 23 | } 24 | 25 | this.url = url; 26 | this.properties = new Properties(); 27 | set(properties,user,password); 28 | } 29 | 30 | private void set(Properties info, String user, String password) { 31 | if (user != null) { 32 | info.put("user", user); 33 | } 34 | if (password != null) { 35 | info.put("password", password); 36 | } 37 | } 38 | 39 | public GenericDatasource(String url, Properties properties) { 40 | 41 | if (!url.startsWith("jdbc")){ 42 | url = "jdbc:" + url; 43 | } 44 | 45 | this.url = url; 46 | this.properties = properties; 47 | } 48 | 49 | public String getUrl() { 50 | return url; 51 | } 52 | 53 | public String getUser() { 54 | return properties.getProperty("user"); 55 | } 56 | 57 | public String getPassword() { 58 | return properties.getProperty("password"); 59 | } 60 | 61 | public Connection getConnection() throws SQLException { 62 | return DriverManager.getConnection(this.getUrl(), properties); 63 | } 64 | 65 | public Connection getConnection(String username, String password) throws SQLException { 66 | Properties info = new Properties(this.properties); 67 | set(info,username,password); 68 | return DriverManager.getConnection(this.getUrl(), info); 69 | } 70 | 71 | public PrintWriter getLogWriter() throws SQLException { 72 | return DriverManager.getLogWriter(); 73 | } 74 | 75 | public void setLogWriter(PrintWriter printWriter) throws SQLException { 76 | DriverManager.setLogWriter(printWriter); 77 | } 78 | 79 | public void setLoginTimeout(int i) throws SQLException { 80 | DriverManager.setLoginTimeout(i); 81 | } 82 | 83 | public int getLoginTimeout() throws SQLException { 84 | return DriverManager.getLoginTimeout(); 85 | } 86 | 87 | public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { 88 | throw new SQLFeatureNotSupportedException(); 89 | } 90 | 91 | public T unwrap(Class tClass) throws SQLException { 92 | throw new SQLFeatureNotSupportedException(); 93 | } 94 | 95 | public boolean isWrapperFor(Class aClass) throws SQLException { 96 | return false; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/JoinTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.core.Joins; 4 | import com.hellokaton.anima.enums.OrderBy; 5 | import com.hellokaton.anima.model.Address; 6 | import com.hellokaton.anima.model.OrderInfo; 7 | import com.hellokaton.anima.model.User; 8 | import com.hellokaton.anima.model.UserDto; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import java.util.List; 13 | 14 | import static com.hellokaton.anima.Anima.select; 15 | 16 | /** 17 | * Join test 18 | * 19 | * @author biezhi 20 | * @date 2018/4/16 21 | */ 22 | public class JoinTest extends BaseTest { 23 | 24 | @Test 25 | public void testJoin() { 26 | // HasOne 27 | OrderInfo orderInfo = Anima.select().from(OrderInfo.class) 28 | .join( 29 | Joins.with(Address.class).as(OrderInfo::getAddress) 30 | .on(OrderInfo::getId, Address::getOrderId) 31 | ) 32 | .byId(3); 33 | 34 | Assert.assertNotNull(orderInfo); 35 | Assert.assertNotNull(orderInfo.getAddress()); 36 | 37 | orderInfo = Anima.select().from(OrderInfo.class) 38 | .join( 39 | Joins.with(Address.class).as(OrderInfo::getAddress) 40 | .on(OrderInfo::getId, Address::getOrderId) 41 | ) 42 | .join( 43 | Joins.with(User.class).as(OrderInfo::getUser) 44 | .on(OrderInfo::getUid, User::getId) 45 | ) 46 | .byId(3); 47 | 48 | Assert.assertNotNull(orderInfo); 49 | Assert.assertNotNull(orderInfo.getAddress()); 50 | Assert.assertNotNull(orderInfo.getUser()); 51 | 52 | // ManyToOne 53 | orderInfo = Anima.select().from(OrderInfo.class) 54 | .join( 55 | Joins.with(User.class).as(OrderInfo::getUser) 56 | .on(OrderInfo::getUid, User::getId) 57 | ) 58 | .byId(3); 59 | 60 | Assert.assertNotNull(orderInfo); 61 | Assert.assertNotNull(orderInfo.getUser()); 62 | } 63 | 64 | @Test 65 | public void testOneToMany(){ 66 | List userDto = Anima.select().from(UserDto.class).join( 67 | Joins.with(OrderInfo.class).as(UserDto::getOrders) 68 | .on(UserDto::getId, OrderInfo::getUid) 69 | ).all(); 70 | Assert.assertNotNull(userDto); 71 | Assert.assertNotNull(userDto.get(0).getOrders()); 72 | } 73 | @Test 74 | public void testOrderBy() { 75 | // OneToMany 76 | UserDto userDto = Anima.select().from(UserDto.class).join( 77 | Joins.with(OrderInfo.class).as(UserDto::getOrders) 78 | .on(UserDto::getId, OrderInfo::getUid) 79 | .order(OrderInfo::getId, OrderBy.DESC) 80 | ).byId(1); 81 | 82 | userDto = Anima.select().from(UserDto.class).join( 83 | Joins.with(OrderInfo.class).as(UserDto::getOrders) 84 | .on(UserDto::getId, OrderInfo::getUid) 85 | .order("id asc") 86 | ).byId(1); 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/FactoryFacade.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | 6 | @SuppressWarnings("Unsafe") 7 | public class FactoryFacade { 8 | 9 | private final static FactoryFacade instance; 10 | 11 | static { 12 | MethodGetterFactory mg; 13 | MethodSetterFactory m; 14 | ObjectConstructorFactory o; 15 | try { 16 | m = (MethodSetterFactory) Class 17 | .forName("org.sql2o.reflection.MethodAccessorsGenerator") 18 | .newInstance(); 19 | mg = (MethodGetterFactory) m; 20 | o = (ObjectConstructorFactory) m; 21 | } catch (Throwable ex) { 22 | mg = new ReflectionMethodGetterFactory(); 23 | m = new ReflectionMethodSetterFactory(); 24 | o = null; 25 | } 26 | FieldGetterFactory fg; 27 | FieldSetterFactory f; 28 | try { 29 | Class clsg = Class.forName("org.sql2o.reflection.UnsafeFieldGetterFactory"); 30 | fg = (FieldGetterFactory) clsg.newInstance(); 31 | Class cls = Class.forName("org.sql2o.reflection.UnsafeFieldSetterFactory"); 32 | f = (FieldSetterFactory) cls.newInstance(); 33 | if(o==null) o = (ObjectConstructorFactory) f; 34 | } catch (Throwable ex) { 35 | fg = new ReflectionFieldGetterFactory(); 36 | f = new ReflectionFieldSetterFactory(); 37 | o = new ReflectionObjectConstructorFactory(); 38 | } 39 | instance = new FactoryFacade(fg, mg, f, m, o); 40 | } 41 | 42 | private final FieldGetterFactory fieldGetterFactory; 43 | private final MethodGetterFactory methodGetterFactory; 44 | private final FieldSetterFactory fieldSetterFactory; 45 | private final MethodSetterFactory methodSetterFactory; 46 | private final ObjectConstructorFactory objectConstructorFactory; 47 | 48 | public FactoryFacade( 49 | FieldGetterFactory fieldGetterFactory, MethodGetterFactory methodGetterFactory, 50 | FieldSetterFactory fieldSetterFactory, MethodSetterFactory methodSetterFactory, 51 | ObjectConstructorFactory objectConstructorFactory) { 52 | 53 | this.fieldGetterFactory = fieldGetterFactory; 54 | this.methodGetterFactory = methodGetterFactory; 55 | this.fieldSetterFactory = fieldSetterFactory; 56 | this.methodSetterFactory = methodSetterFactory; 57 | this.objectConstructorFactory = objectConstructorFactory; 58 | } 59 | 60 | public static FactoryFacade getInstance() { 61 | return instance; 62 | } 63 | 64 | public Getter newGetter(Field field) { 65 | return fieldGetterFactory.newGetter(field); 66 | } 67 | 68 | public Getter newGetter(Method method) { 69 | return methodGetterFactory.newGetter(method); 70 | } 71 | 72 | public Setter newSetter(Field field) { 73 | return fieldSetterFactory.newSetter(field); 74 | } 75 | 76 | public Setter newSetter(Method method) { 77 | return methodSetterFactory.newSetter(method); 78 | } 79 | 80 | public ObjectConstructor newConstructor(Class cls) { 81 | return objectConstructorFactory.newConstructor(cls); 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Eclipse template 3 | 4 | .metadata 5 | bin/ 6 | tmp/ 7 | *.tmp 8 | *.bak 9 | *.swp 10 | *~.nib 11 | local.properties 12 | .settings/ 13 | .loadpath 14 | .recommenders 15 | .project 16 | .classpath 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # PyDev specific (Python IDE for Eclipse) 25 | *.pydevproject 26 | 27 | # CDT-specific (C/C++ Development Tooling) 28 | .cproject 29 | 30 | # CDT- autotools 31 | .autotools 32 | 33 | # Java annotation processor (APT) 34 | .factorypath 35 | 36 | # PDT-specific (PHP Development Tools) 37 | .buildpath 38 | 39 | # sbteclipse plugin 40 | .target 41 | 42 | # Tern plugin 43 | .tern-project 44 | 45 | # TeXlipse plugin 46 | .texlipse 47 | 48 | # STS (Spring Tool Suite) 49 | .springBeans 50 | 51 | # Code Recommenders 52 | .recommenders/ 53 | 54 | # Scala IDE specific (Scala & Java development for Eclipse) 55 | .cache-main 56 | .scala_dependencies 57 | .worksheet 58 | ### JetBrains template 59 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 60 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 61 | 62 | # User-specific stuff: 63 | .idea/**/workspace.xml 64 | .idea/**/tasks.xml 65 | .idea/dictionaries 66 | 67 | # Sensitive or high-churn files: 68 | .idea/**/dataSources/ 69 | .idea/**/dataSources.ids 70 | .idea/**/dataSources.xml 71 | .idea/**/dataSources.local.xml 72 | .idea/**/sqlDataSources.xml 73 | .idea/**/dynamic.xml 74 | .idea/**/uiDesigner.xml 75 | *.iml 76 | 77 | # Gradle: 78 | .idea/**/gradle.xml 79 | .idea/**/libraries 80 | 81 | # CMake 82 | cmake-build-debug/ 83 | cmake-build-release/ 84 | 85 | # Mongo Explorer plugin: 86 | .idea/**/mongoSettings.xml 87 | 88 | ## File-based project format: 89 | *.iws 90 | 91 | ## Plugin-specific files: 92 | 93 | # IntelliJ 94 | out/ 95 | 96 | # mpeltonen/sbt-idea plugin 97 | .idea_modules/ 98 | 99 | # JIRA plugin 100 | atlassian-ide-plugin.xml 101 | 102 | # Cursive Clojure plugin 103 | .idea/replstate.xml 104 | 105 | # Crashlytics plugin (for Android Studio and IntelliJ) 106 | com_crashlytics_export_strings.xml 107 | crashlytics.properties 108 | crashlytics-build.properties 109 | fabric.properties 110 | ### VisualStudioCode template 111 | .vscode/* 112 | !.vscode/settings.json 113 | !.vscode/tasks.json 114 | !.vscode/launch.json 115 | !.vscode/extensions.json 116 | ### Java template 117 | # Compiled class file 118 | *.class 119 | 120 | # Log file 121 | *.log 122 | 123 | # BlueJ files 124 | *.ctxt 125 | 126 | # Mobile Tools for Java (J2ME) 127 | .mtj.tmp/ 128 | 129 | # Package Files # 130 | *.jar 131 | *.war 132 | *.ear 133 | *.zip 134 | *.rar 135 | 136 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 137 | hs_err_pid* 138 | ### Maven template 139 | target/ 140 | pom.xml.tag 141 | pom.xml.releaseBackup 142 | pom.xml.versionsBackup 143 | pom.xml.next 144 | release.properties 145 | dependency-reduced-pom.xml 146 | buildNumber.properties 147 | .mvn/timing.properties 148 | 149 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 150 | !/.mvn/wrapper/maven-wrapper.jar 151 | 152 | .idea -------------------------------------------------------------------------------- /src/main/java/org/sql2o/ResultSetIteratorBase.java: -------------------------------------------------------------------------------- 1 | package org.sql2o; 2 | 3 | import org.sql2o.quirks.Quirks; 4 | 5 | import java.sql.ResultSet; 6 | import java.sql.ResultSetMetaData; 7 | import java.sql.SQLException; 8 | import java.util.Iterator; 9 | import java.util.NoSuchElementException; 10 | 11 | /** 12 | * Iterator for a {@link ResultSet}. Tricky part here is getting {@link #hasNext()} 13 | * to work properly, meaning it can be called multiple times without calling {@link #next()}. 14 | * 15 | * @author aldenquimby@gmail.com 16 | */ 17 | public abstract class ResultSetIteratorBase implements Iterator { 18 | // fields needed to read result set 19 | protected ResultSet rs; 20 | protected boolean isCaseSensitive; 21 | protected Quirks quirks; 22 | protected ResultSetMetaData meta; 23 | 24 | public ResultSetIteratorBase(ResultSet rs, boolean isCaseSensitive, Quirks quirks) { 25 | this.rs = rs; 26 | this.isCaseSensitive = isCaseSensitive; 27 | this.quirks = quirks; 28 | try { 29 | meta = rs.getMetaData(); 30 | } 31 | catch(SQLException ex) { 32 | throw new Sql2oException("Database error: " + ex.getMessage(), ex); 33 | } 34 | } 35 | 36 | // fields needed to properly implement 37 | private ResultSetValue next; // keep track of next item in case hasNext() is called multiple times 38 | private boolean resultSetFinished; // used to note when result set exhausted 39 | 40 | public boolean hasNext() { 41 | // check if we already fetched next item 42 | if (next != null) { 43 | return true; 44 | } 45 | 46 | // check if result set already finished 47 | if (resultSetFinished) { 48 | return false; 49 | } 50 | 51 | // now fetch next item 52 | next = safeReadNext(); 53 | 54 | // check if we got something 55 | if (next != null) { 56 | return true; 57 | } 58 | 59 | // no more items 60 | resultSetFinished = true; 61 | 62 | return false; 63 | } 64 | 65 | public T next() { 66 | if (!hasNext()) { 67 | throw new NoSuchElementException(); 68 | } 69 | 70 | T result = next.value; 71 | 72 | next = null; 73 | 74 | return result; 75 | } 76 | 77 | public void remove() { 78 | throw new UnsupportedOperationException(); 79 | } 80 | 81 | private ResultSetValue safeReadNext() 82 | { 83 | try { 84 | if (!rs.next()) 85 | return null; 86 | ResultSetValue resultSetValue = new ResultSetValue(readNext()); 87 | return resultSetValue; 88 | } 89 | catch (SQLException ex) { 90 | throw new Sql2oException("Database error: " + ex.getMessage(), ex); 91 | } 92 | } 93 | 94 | protected abstract T readNext() throws SQLException; 95 | 96 | protected String getColumnName(int colIdx) throws SQLException { 97 | return quirks.getColumnName(meta, colIdx); 98 | } 99 | 100 | private final class ResultSetValue { 101 | public final S value; 102 | 103 | public ResultSetValue(S value){ 104 | this.value = value; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/ReadColumnAnnotationTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import com.hellokaton.anima.annotation.Column; 5 | import junit.framework.TestCase; 6 | import org.junit.Test; 7 | import org.sql2o.reflection.PojoMetadata; 8 | 9 | @SuppressWarnings("unused") 10 | public class ReadColumnAnnotationTest extends TestCase { 11 | 12 | @Test 13 | public void testNoAnnotationPojo() { 14 | PojoMetadata metadata = newPojoMetadata(NoAnnotation.class); 15 | assertNotNull(metadata.getPropertySetterIfExists("field1")); 16 | } 17 | 18 | @Test 19 | public void testNoAnnotationSetterPojo() { 20 | PojoMetadata metadata = newPojoMetadata(NoAnnotationSetter.class); 21 | assertNotNull(metadata.getPropertySetterIfExists("field1")); 22 | } 23 | 24 | @Test 25 | public void testOnlyOneAnnotationFieldPojo() { 26 | PojoMetadata metadata = newPojoMetadata(OnlyOneAnnotationField.class); 27 | assertNotNull(metadata.getPropertySetterIfExists("field_1")); 28 | } 29 | 30 | @Test 31 | public void testOneAnnotationFieldPojo() { 32 | PojoMetadata metadata = newPojoMetadata(OneAnnotationField.class); 33 | assertNotNull(metadata.getPropertySetterIfExists("field_1")); 34 | assertNotNull(metadata.getPropertySetterIfExists("field2")); 35 | } 36 | 37 | @Test 38 | public void testAnnotationFieldAndSetterPojo() { 39 | PojoMetadata metadata = newPojoMetadata(AnnotationFieldAndASetter.class); 40 | assertNotNull(metadata.getPropertySetterIfExists("field_1")); 41 | assertNotNull(metadata.getPropertySetterIfExists("field2")); 42 | assertNotNull(metadata.getPropertySetterIfExists("field_3")); 43 | assertNotNull(metadata.getPropertySetterIfExists("field4")); 44 | } 45 | 46 | @Test 47 | public void testUppercaseAnnotationFieldPojo() { 48 | PojoMetadata metadata = newPojoMetadata(UpperCaseAnnotationField.class); 49 | assertNotNull(metadata.getPropertySetterIfExists("field_1")); 50 | } 51 | 52 | private PojoMetadata newPojoMetadata(Class clazz) { 53 | return new PojoMetadata(clazz, false, false, ImmutableMap. of(), true); 54 | } 55 | 56 | private static class NoAnnotation { 57 | private String field1; 58 | } 59 | 60 | private static class NoAnnotationSetter { 61 | private String field1; 62 | 63 | void setField1(String field1) { 64 | this.field1 = field1; 65 | } 66 | } 67 | 68 | private static class OnlyOneAnnotationField { 69 | @Column(name = "field_1") 70 | private String field1; 71 | } 72 | 73 | private static class OneAnnotationField { 74 | @Column(name = "field_1") 75 | private String field1; 76 | private String field2; 77 | } 78 | 79 | private static class AnnotationFieldAndASetter { 80 | @Column(name = "field_1") 81 | private String field1; 82 | private String field2; 83 | private String field3; 84 | private String field4; 85 | 86 | @Column(name = "field_3") 87 | void setField3(String field3) { 88 | this.field3 = field3; 89 | } 90 | 91 | void setField4(String field4) { 92 | this.field4 = field4; 93 | } 94 | } 95 | 96 | private static class UpperCaseAnnotationField { 97 | @Column(name = "FIELD_1") 98 | private String field1; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/hellokaton/anima/utils/TwoFormInflector.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | public abstract class TwoFormInflector { 9 | private interface Rule { 10 | String getPlural(String singular); 11 | } 12 | 13 | private static class RegExpRule implements Rule { 14 | private final Pattern singular; 15 | private final String plural; 16 | 17 | private RegExpRule(Pattern singular, String plural) { 18 | this.singular = singular; 19 | this.plural = plural; 20 | } 21 | 22 | @Override 23 | public String getPlural(String word) { 24 | StringBuffer buffer = new StringBuffer(); 25 | Matcher matcher = singular.matcher(word); 26 | if (matcher.find()) { 27 | matcher.appendReplacement(buffer, plural); 28 | matcher.appendTail(buffer); 29 | return buffer.toString(); 30 | } 31 | return null; 32 | } 33 | } 34 | 35 | private static class CategoryRule implements Rule { 36 | private final String[] list; 37 | private final String singular; 38 | private final String plural; 39 | 40 | public CategoryRule(String[] list, String singular, String plural) { 41 | this.list = list; 42 | this.singular = singular; 43 | this.plural = plural; 44 | } 45 | 46 | @Override 47 | public String getPlural(String word) { 48 | String lowerWord = word.toLowerCase(); 49 | for (String suffix : list) { 50 | if (lowerWord.endsWith(suffix)) { 51 | if (!lowerWord.endsWith(singular)) { 52 | throw new RuntimeException("Internal error"); 53 | } 54 | return word.substring(0, word.length() - singular.length()) + plural; 55 | } 56 | } 57 | return null; 58 | } 59 | } 60 | 61 | private final List rules = new ArrayList(); 62 | 63 | protected String getPlural(String word) { 64 | for (Rule rule : rules) { 65 | String result = rule.getPlural(word); 66 | if (result != null) { 67 | return result; 68 | } 69 | } 70 | return null; 71 | } 72 | 73 | protected void uncountable(String[] list) { 74 | rules.add(new CategoryRule(list, "", "")); 75 | } 76 | 77 | protected void irregular(String singular, String plural) { 78 | if (singular.charAt(0) == plural.charAt(0)) { 79 | rules.add(new RegExpRule(Pattern.compile("(?i)(" + singular.charAt(0) + ")" + singular.substring(1) 80 | + "$"), "$1" + plural.substring(1))); 81 | } else { 82 | rules.add(new RegExpRule(Pattern.compile(Character.toUpperCase(singular.charAt(0)) + "(?i)" 83 | + singular.substring(1) + "$"), Character.toUpperCase(plural.charAt(0)) 84 | + plural.substring(1))); 85 | rules.add(new RegExpRule(Pattern.compile(Character.toLowerCase(singular.charAt(0)) + "(?i)" 86 | + singular.substring(1) + "$"), Character.toLowerCase(plural.charAt(0)) 87 | + plural.substring(1))); 88 | } 89 | } 90 | 91 | protected void irregular(String[][] list) { 92 | for (String[] pair : list) { 93 | irregular(pair[0], pair[1]); 94 | } 95 | } 96 | 97 | protected void rule(String singular, String plural) { 98 | rules.add(new RegExpRule(Pattern.compile(singular, Pattern.CASE_INSENSITIVE), plural)); 99 | } 100 | 101 | protected void rule(String[][] list) { 102 | for (String[] pair : list) { 103 | rules.add(new RegExpRule(Pattern.compile(pair[0], Pattern.CASE_INSENSITIVE), pair[1])); 104 | } 105 | } 106 | 107 | protected void categoryRule(String[] list, String singular, String plural) { 108 | rules.add(new CategoryRule(list, singular, plural)); 109 | } 110 | } -------------------------------------------------------------------------------- /src/main/java/org/sql2o/converters/DefaultEnumConverterFactory.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.converters; 2 | 3 | import com.hellokaton.anima.annotation.EnumMapping; 4 | import com.hellokaton.anima.exception.AnimaException; 5 | 6 | import java.lang.reflect.Field; 7 | import java.util.EnumSet; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * Default implementation of {@link EnumConverterFactory}, 13 | * used by sql2o to convert a value from the database into an {@link Enum}. 14 | */ 15 | public class DefaultEnumConverterFactory implements EnumConverterFactory { 16 | 17 | private static Map fieldMap = new HashMap<>(); 18 | 19 | private static E getEnum(Object target, Class enumType) { 20 | EnumMapping enumMapping = enumType.getAnnotation(EnumMapping.class); 21 | 22 | if (!fieldMap.containsKey(enumMapping)) { 23 | try { 24 | Field field = enumType.getDeclaredField(enumMapping.value()); 25 | fieldMap.put(enumMapping, field); 26 | } catch (Exception e) { 27 | e.printStackTrace(); 28 | } 29 | } 30 | 31 | Field field = fieldMap.get(enumMapping); 32 | field.setAccessible(true); 33 | return (E) EnumSet.allOf(enumType).stream() 34 | .filter(e -> filterEnumValue(target, field, e)) 35 | .findFirst().get(); 36 | } 37 | 38 | private static boolean filterEnumValue(Object target, Field field, Object e) { 39 | try { 40 | Object o = field.get(e); 41 | return target.toString().equals(o.toString()); 42 | } catch (IllegalAccessException e1) { 43 | e1.printStackTrace(); 44 | } 45 | return false; 46 | } 47 | 48 | public Converter newConverter(final Class enumType) { 49 | return new Converter() { 50 | @SuppressWarnings("unchecked") 51 | public E convert(Object val) throws ConverterException { 52 | if (val == null) { 53 | return null; 54 | } 55 | try { 56 | EnumMapping enumMapping = enumType.getAnnotation(EnumMapping.class); 57 | if (null != enumMapping) { 58 | return getEnum(val, enumType); 59 | } 60 | if (val instanceof String) { 61 | return (E) Enum.valueOf(enumType, val.toString()); 62 | } else if (val instanceof Number) { 63 | return enumType.getEnumConstants()[((Number) val).intValue()]; 64 | } 65 | } catch (Throwable t) { 66 | throw new ConverterException("Error converting value '" + val.toString() + "' to " + enumType.getName(), t); 67 | } 68 | throw new ConverterException("Cannot convert type '" + val.getClass().getName() + "' to an Enum"); 69 | } 70 | 71 | public Object toDatabaseParam(Enum val) { 72 | EnumMapping enumMapping = val.getClass().getAnnotation(EnumMapping.class); 73 | if (null != enumMapping) { 74 | try { 75 | Field field = val.getClass().getDeclaredField(enumMapping.value()); 76 | field.setAccessible(true); 77 | return field.get(val); 78 | } catch (Exception e) { 79 | throw new AnimaException(e); 80 | } 81 | } 82 | return val.name(); 83 | } 84 | }; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/AbstractFieldSetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import junit.framework.TestCase; 4 | import org.sql2o.reflection.FieldSetterFactory; 5 | import org.sql2o.reflection.Setter; 6 | 7 | import java.lang.reflect.Field; 8 | 9 | /** 10 | * User: dimzon 11 | * Date: 4/9/14 12 | * Time: 9:46 PM 13 | */ 14 | public abstract class AbstractFieldSetterFactoryTest extends TestCase { 15 | public static class POJO1{ 16 | boolean _boolean; 17 | byte _byte; 18 | short _short; 19 | int _int; 20 | long _long; 21 | float _float; 22 | double _double; 23 | char _char; 24 | Object _obj; 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if (this == o) return true; 29 | if (o == null || getClass() != o.getClass()) return false; 30 | 31 | POJO1 pojo1 = (POJO1) o; 32 | 33 | if (_boolean != pojo1._boolean) return false; 34 | if (_byte != pojo1._byte) return false; 35 | if (_char != pojo1._char) return false; 36 | if (Double.compare(pojo1._double, _double) != 0) return false; 37 | if (Float.compare(pojo1._float, _float) != 0) return false; 38 | if (_int != pojo1._int) return false; 39 | if (_long != pojo1._long) return false; 40 | if (_short != pojo1._short) return false; 41 | if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; 42 | 43 | return true; 44 | } 45 | } 46 | 47 | 48 | public void testAllTypes() throws IllegalAccessException { 49 | POJO1 pojo1 = new POJO1(); 50 | pojo1._boolean = true; 51 | pojo1._byte = 17; 52 | pojo1._short=87; 53 | pojo1._int= Integer.MIN_VALUE; 54 | pojo1._long= 1337; 55 | pojo1._char='a'; 56 | pojo1._double=Math.PI; 57 | pojo1._float= (float) Math.log(93); 58 | pojo1._obj = pojo1; 59 | 60 | POJO1 pojo2 = new POJO1(); 61 | 62 | assertFalse(pojo1.equals(pojo2)); 63 | 64 | Field[] fields = pojo1.getClass().getDeclaredFields(); 65 | for (Field field : fields) { 66 | Setter setter = fsf.newSetter(field); 67 | assertSame(field.getType(),setter.getType()); 68 | Object val1 = field.get(pojo1); 69 | Object val2 = field.get(pojo2); 70 | assertFalse(val1.equals(val2)); 71 | setter.setProperty(pojo2,val1); 72 | Object val3 = field.get(pojo2); 73 | assertEquals(val1,val3); 74 | } 75 | 76 | assertEquals(pojo1,pojo2); 77 | 78 | // let's reset all values to NULL 79 | // primitive fields will not be affected 80 | for (Field field : fields) { 81 | Setter setter = fsf.newSetter(field); 82 | Object val1 = field.get(pojo1); 83 | assertNotNull(val1); 84 | 85 | setter.setProperty(pojo1,null); 86 | 87 | Object val2 = field.get(pojo1); 88 | if(!setter.getType().isPrimitive()){ 89 | assertNull(val2); 90 | continue; 91 | } 92 | assertNotNull(val2); 93 | // not affected 94 | assertEquals(val1,val2); 95 | } 96 | pojo2._obj = null; 97 | assertEquals(pojo2,pojo1); 98 | } 99 | 100 | 101 | public final FieldSetterFactory fsf; 102 | 103 | protected AbstractFieldSetterFactoryTest(FieldSetterFactory fsf) { 104 | this.fsf = fsf; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/AbstractMethodGetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import org.sql2o.reflection.Getter; 6 | import org.sql2o.reflection.MethodGetterFactory; 7 | 8 | import java.lang.reflect.Field; 9 | import java.lang.reflect.Method; 10 | 11 | /** 12 | * @author mdelapenya 13 | */ 14 | public abstract class AbstractMethodGetterFactoryTest extends TestCase { 15 | public static class POJO1{ 16 | public boolean get_boolean() { 17 | return this._boolean; 18 | } 19 | 20 | public byte set_byte() { 21 | return this._byte; 22 | } 23 | 24 | public short set_short() { 25 | return this._short; 26 | } 27 | 28 | public int set_int() { 29 | return this._int; 30 | } 31 | 32 | public long set_long() { 33 | return this._long; 34 | } 35 | 36 | public float set_float() { 37 | return this._float; 38 | } 39 | 40 | public double set_double() { 41 | return this._double; 42 | } 43 | 44 | public char set_char() { 45 | return this._char; 46 | } 47 | 48 | public Object set_obj() { 49 | return this._obj; 50 | } 51 | 52 | boolean _boolean; 53 | byte _byte; 54 | short _short; 55 | int _int; 56 | long _long; 57 | float _float; 58 | double _double; 59 | char _char; 60 | Object _obj; 61 | 62 | @Override 63 | public boolean equals(Object o) { 64 | if (this == o) return true; 65 | if (o == null || getClass() != o.getClass()) return false; 66 | 67 | POJO1 pojo1 = (POJO1) o; 68 | 69 | if (_boolean != pojo1._boolean) return false; 70 | if (_byte != pojo1._byte) return false; 71 | if (_char != pojo1._char) return false; 72 | if (Double.compare(pojo1._double, _double) != 0) return false; 73 | if (Float.compare(pojo1._float, _float) != 0) return false; 74 | if (_int != pojo1._int) return false; 75 | if (_long != pojo1._long) return false; 76 | if (_short != pojo1._short) return false; 77 | if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; 78 | 79 | return true; 80 | } 81 | } 82 | 83 | 84 | public void testAllTypes() throws IllegalAccessException, NoSuchFieldException { 85 | POJO1 pojo = new POJO1(); 86 | pojo._boolean = true; 87 | pojo._byte = 17; 88 | pojo._short=87; 89 | pojo._int= Integer.MIN_VALUE; 90 | pojo._long= 1337; 91 | pojo._char='a'; 92 | pojo._double=Math.PI; 93 | pojo._float= (float) Math.log(93); 94 | pojo._obj = pojo; 95 | 96 | Method[] methods = pojo.getClass().getDeclaredMethods(); 97 | for (Method method : methods) { 98 | if(!method.getName().startsWith("get_")) continue; 99 | 100 | Field field = pojo.getClass() 101 | .getDeclaredField(method.getName().substring(3)); 102 | 103 | Getter getter = mgf.newGetter(method); 104 | assertSame(field.getType(),getter.getType()); 105 | 106 | Object val1 = field.get(pojo); 107 | assertEquals(val1, getter.getProperty(pojo)); 108 | } 109 | } 110 | 111 | 112 | public final MethodGetterFactory mgf; 113 | 114 | public AbstractMethodGetterFactoryTest(MethodGetterFactory mgf) { 115 | this.mgf = mgf; 116 | } 117 | } -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/AnimaTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.zaxxer.hikari.HikariDataSource; 4 | import com.hellokaton.anima.converter.LevelConverter; 5 | import com.hellokaton.anima.core.SQLParams; 6 | import com.hellokaton.anima.dialect.Dialect; 7 | import com.hellokaton.anima.exception.AnimaException; 8 | import org.junit.Test; 9 | import org.sql2o.Sql2o; 10 | import org.sql2o.quirks.NoQuirks; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | /** 15 | * AnimaTest 16 | * 17 | * @author biezhi 18 | * @date 2018-12-15 19 | */ 20 | public class AnimaTest { 21 | 22 | // @Test(expected = AnimaException.class) 23 | // public void testSql2oIsNull() { 24 | // Anima.of(); 25 | // } 26 | 27 | @Test 28 | public void testCreateAnimaByNew() { 29 | Anima anima = new Anima(new Sql2o("jdbc:h2:file:~/demo;", "sa", "")); 30 | assertNotNull(anima); 31 | assertNotNull(Anima.of()); 32 | 33 | HikariDataSource ds = new HikariDataSource(); 34 | ds.setJdbcUrl("jdbc:h2:file:~/demo;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192"); 35 | ds.setUsername("sa"); 36 | ds.setPassword(""); 37 | 38 | anima = new Anima(ds); 39 | assertNotNull(anima); 40 | assertNotNull(Anima.of()); 41 | 42 | anima = new Anima("jdbc:h2:file:~/demo;", "sa", ""); 43 | assertNotNull(anima); 44 | assertNotNull(Anima.of()); 45 | } 46 | 47 | @Test 48 | public void testCreateAnimaByOpen() { 49 | Anima anima = Anima.open(new Sql2o("jdbc:h2:file:~/demo;", "sa", "")); 50 | assertNotNull(anima); 51 | assertNotNull(Anima.of()); 52 | 53 | anima = Anima.open("jdbc:sqlite:./test_create.db"); 54 | assertNotNull(anima); 55 | assertNotNull(Anima.of()); 56 | 57 | anima = Anima.open("jdbc:h2:file:~/demo;", "sa", ""); 58 | assertNotNull(anima); 59 | assertNotNull(Anima.of()); 60 | 61 | HikariDataSource ds = new HikariDataSource(); 62 | ds.setJdbcUrl("jdbc:h2:file:~/demo;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192"); 63 | ds.setUsername("sa"); 64 | ds.setPassword(""); 65 | 66 | anima = Anima.open(ds); 67 | assertNotNull(anima); 68 | assertNotNull(Anima.of()); 69 | } 70 | 71 | @Test 72 | public void testCreateAnimaWithQuirk() { 73 | Anima anima = Anima.open("jdbc:sqlite:./test_create.db", new NoQuirks()); 74 | assertNotNull(anima); 75 | assertEquals(NoQuirks.class, anima.getSql2o().getQuirks().getClass()); 76 | assertNotNull(Anima.of()); 77 | 78 | HikariDataSource ds = new HikariDataSource(); 79 | ds.setJdbcUrl("jdbc:h2:file:~/demo;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192"); 80 | ds.setUsername("sa"); 81 | ds.setPassword(""); 82 | 83 | anima = Anima.open(ds, new NoQuirks()); 84 | assertNotNull(anima); 85 | assertEquals(NoQuirks.class, anima.getSql2o().getQuirks().getClass()); 86 | assertNotNull(Anima.of()); 87 | 88 | anima = Anima.open("jdbc:h2:file:~/demo;", "sa", "", new NoQuirks()); 89 | assertNotNull(anima); 90 | assertEquals(NoQuirks.class, anima.getSql2o().getQuirks().getClass()); 91 | assertNotNull(Anima.of()); 92 | } 93 | 94 | @Test 95 | public void testChangeRollbackException() { 96 | Anima anima = createH2Anima().rollbackException(Exception.class); 97 | assertEquals(Exception.class, anima.rollbackException()); 98 | } 99 | 100 | @Test 101 | public void testSetTablePrefix() { 102 | Anima anima = createH2Anima().tablePrefix("t_"); 103 | assertEquals("t_", anima.tablePrefix()); 104 | } 105 | 106 | static class MyDialect implements Dialect { 107 | @Override 108 | public String paginate(SQLParams sqlParams) { 109 | return null; 110 | } 111 | } 112 | 113 | @Test 114 | public void testSetDialect() { 115 | Anima anima = createH2Anima().dialect(new MyDialect()); 116 | assertEquals(MyDialect.class, anima.dialect().getClass()); 117 | } 118 | 119 | @Test 120 | public void testEnableSQLStatistic() { 121 | Anima anima = createH2Anima().enableSQLStatistic(false); 122 | assertFalse(anima.isEnableSQLStatistic()); 123 | } 124 | 125 | @Test 126 | public void testUseSQLLimit() { 127 | Anima anima = createH2Anima().useSQLLimit(false); 128 | assertFalse(anima.isUseSQLLimit()); 129 | } 130 | 131 | @Test(expected = AnimaException.class) 132 | public void testAddNullConverter(){ 133 | Anima anima = createH2Anima(); 134 | anima.addConverter(null); 135 | } 136 | 137 | @Test 138 | public void testAddConverter(){ 139 | createH2Anima().addConverter(new LevelConverter()); 140 | } 141 | 142 | private Anima createH2Anima(){ 143 | return Anima.open("jdbc:h2:file:~/demo;", "sa", ""); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/test/java/org/sql2o/reflect/AbstractMethodSetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflect; 2 | 3 | import junit.framework.TestCase; 4 | import org.sql2o.reflection.MethodSetterFactory; 5 | import org.sql2o.reflection.Setter; 6 | 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * User: dimzon 12 | * Date: 4/9/14 13 | * Time: 10:18 PM 14 | */ 15 | public abstract class AbstractMethodSetterFactoryTest extends TestCase { 16 | public static class POJO1{ 17 | public void set_boolean(boolean _boolean) { 18 | this._boolean = _boolean; 19 | } 20 | 21 | public void set_byte(byte _byte) { 22 | this._byte = _byte; 23 | } 24 | 25 | public void set_short(short _short) { 26 | this._short = _short; 27 | } 28 | 29 | public void set_int(int _int) { 30 | this._int = _int; 31 | } 32 | 33 | public void set_long(long _long) { 34 | this._long = _long; 35 | } 36 | 37 | public void set_float(float _float) { 38 | this._float = _float; 39 | } 40 | 41 | public void set_double(double _double) { 42 | this._double = _double; 43 | } 44 | 45 | public void set_char(char _char) { 46 | this._char = _char; 47 | } 48 | 49 | public void set_obj(Object _obj) { 50 | this._obj = _obj; 51 | } 52 | 53 | boolean _boolean; 54 | byte _byte; 55 | short _short; 56 | int _int; 57 | long _long; 58 | float _float; 59 | double _double; 60 | char _char; 61 | Object _obj; 62 | 63 | @Override 64 | public boolean equals(Object o) { 65 | if (this == o) return true; 66 | if (o == null || getClass() != o.getClass()) return false; 67 | 68 | POJO1 pojo1 = (POJO1) o; 69 | 70 | if (_boolean != pojo1._boolean) return false; 71 | if (_byte != pojo1._byte) return false; 72 | if (_char != pojo1._char) return false; 73 | if (Double.compare(pojo1._double, _double) != 0) return false; 74 | if (Float.compare(pojo1._float, _float) != 0) return false; 75 | if (_int != pojo1._int) return false; 76 | if (_long != pojo1._long) return false; 77 | if (_short != pojo1._short) return false; 78 | if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; 79 | 80 | return true; 81 | } 82 | } 83 | 84 | 85 | public void testAllTypes() throws IllegalAccessException, NoSuchFieldException { 86 | POJO1 pojo1 = new POJO1(); 87 | pojo1._boolean = true; 88 | pojo1._byte = 17; 89 | pojo1._short=87; 90 | pojo1._int= Integer.MIN_VALUE; 91 | pojo1._long= 1337; 92 | pojo1._char='a'; 93 | pojo1._double=Math.PI; 94 | pojo1._float= (float) Math.log(93); 95 | pojo1._obj = pojo1; 96 | 97 | POJO1 pojo2 = new POJO1(); 98 | 99 | assertFalse(pojo1.equals(pojo2)); 100 | 101 | Method[] methods = pojo1.getClass().getDeclaredMethods(); 102 | for (Method method : methods) { 103 | if(!method.getName().startsWith("set_")) continue; 104 | Field field = pojo1.getClass() 105 | .getDeclaredField(method.getName().substring(3)); 106 | Setter setter = msf.newSetter(method); 107 | assertSame(field.getType(),setter.getType()); 108 | Object val1 = field.get(pojo1); 109 | Object val2 = field.get(pojo2); 110 | assertFalse(val1.equals(val2)); 111 | setter.setProperty(pojo2,val1); 112 | Object val3 = field.get(pojo2); 113 | assertEquals(val1,val3); 114 | } 115 | 116 | assertEquals(pojo1,pojo2); 117 | 118 | // let's reset all values to NULL 119 | // primitive fields will not be affected 120 | for (Method method : methods) { 121 | if(!method.getName().startsWith("set_")) continue; 122 | Field field = pojo1.getClass() 123 | .getDeclaredField(method.getName().substring(3)); 124 | Setter setter = msf.newSetter(method); 125 | Object val1 = field.get(pojo1); 126 | assertNotNull(val1); 127 | 128 | setter.setProperty(pojo1,null); 129 | 130 | Object val2 = field.get(pojo1); 131 | if(!setter.getType().isPrimitive()){ 132 | assertNull(val2); 133 | continue; 134 | } 135 | assertNotNull(val2); 136 | // not affected 137 | assertEquals(val1,val2); 138 | } 139 | pojo2._obj = null; 140 | assertEquals(pojo2,pojo1); 141 | } 142 | 143 | 144 | public final MethodSetterFactory msf; 145 | 146 | public AbstractMethodSetterFactoryTest(MethodSetterFactory msf) { 147 | this.msf = msf; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/org/sql2o/reflection/PojoIntrospector.java: -------------------------------------------------------------------------------- 1 | package org.sql2o.reflection; 2 | 3 | import org.sql2o.tools.AbstractCache; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Member; 8 | import java.lang.reflect.Method; 9 | import java.util.*; 10 | 11 | import static java.beans.Introspector.decapitalize; 12 | import static java.lang.reflect.Modifier.isPrivate; 13 | import static java.lang.reflect.Modifier.isStatic; 14 | 15 | /** 16 | * User: dimzon 17 | * Date: 4/9/14 18 | * Time: 1:10 AM 19 | */ 20 | 21 | // TODO: move introspection code from PojoMetadata to PojoIntrospector 22 | 23 | @SuppressWarnings("UnusedDeclaration") 24 | public class PojoIntrospector { 25 | private static final AbstractCache, Map, Void> rpCache = 26 | new AbstractCache, Map, Void>() { 27 | @Override 28 | protected Map evaluate(Class key, Void param) { 29 | return collectReadableProperties(key); 30 | } 31 | }; 32 | 33 | private static Map collectReadableProperties(Class cls) { 34 | Map map = new HashMap(); 35 | List> classList = classInheritanceHierarhy(cls, Object.class); 36 | for (Class aClass : classList) { 37 | collectPropertyGetters(map, aClass); 38 | } 39 | for (Class aClass : classList) { 40 | collectReadableFields(map, aClass); 41 | } 42 | return Collections.unmodifiableMap(map); 43 | } 44 | 45 | public static Map readableProperties(Class ofClass) { 46 | return rpCache.get(ofClass, null); 47 | } 48 | 49 | private static void collectReadableFields(Map map, Class cls) { 50 | for (final Field m : cls.getDeclaredFields()) { 51 | if (isStaticOrPrivate(m)) continue; 52 | String propName = m.getName(); 53 | if (map.containsKey(propName)) continue; 54 | Class returnType = m.getType(); 55 | m.setAccessible(true); 56 | ReadableProperty rp = new ReadableProperty(propName, returnType) { 57 | @Override 58 | public Object get(Object instance) throws InvocationTargetException, IllegalAccessException { 59 | return m.get(instance); 60 | } 61 | }; 62 | map.put(propName, rp); 63 | } 64 | } 65 | 66 | private static boolean isStaticOrPrivate(Member m) { 67 | final int modifiers = m.getModifiers(); 68 | return isStatic(modifiers) || isPrivate(modifiers); 69 | } 70 | 71 | private static void collectPropertyGetters(Map map, Class cls) { 72 | for (final Method m : cls.getDeclaredMethods()) { 73 | if (isStatic(m.getModifiers())) continue; 74 | if (isPrivate(m.getModifiers())) continue; 75 | if (0 != m.getParameterTypes().length) continue; 76 | Class returnType = m.getReturnType(); 77 | if (returnType == Void.TYPE || returnType == Void.class) continue; 78 | String name = m.getName(); 79 | String propName = null; 80 | if (name.startsWith("get") && name.length() > 3) { 81 | propName = decapitalize(name.substring(3)); 82 | } else if (name.startsWith("is") && name.length() > 2 && returnType == Boolean.TYPE) { 83 | propName = decapitalize(name.substring(2)); 84 | } 85 | if (propName == null) continue; 86 | if (map.containsKey(propName)) continue; 87 | m.setAccessible(true); 88 | ReadableProperty rp = new ReadableProperty(propName, returnType) { 89 | @Override 90 | public Object get(Object instance) throws InvocationTargetException, IllegalAccessException { 91 | return m.invoke(instance, (Object[]) null); 92 | } 93 | }; 94 | map.put(propName, rp); 95 | } 96 | } 97 | 98 | private static List> classInheritanceHierarhy(Class cls, Class stopAt) { 99 | ArrayList> list = new ArrayList>(); 100 | while (cls != null && cls != stopAt) { 101 | list.add(cls); 102 | cls = cls.getSuperclass(); 103 | } 104 | return list; 105 | } 106 | 107 | public abstract static class ReadableProperty { 108 | public final String name; 109 | public final Class type; 110 | 111 | private ReadableProperty(String name, Class type) { 112 | this.name = name; 113 | this.type = type; 114 | } 115 | 116 | public abstract Object get(Object instance) throws InvocationTargetException, IllegalAccessException; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/com/hellokaton/anima/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.hellokaton.anima; 2 | 3 | import com.hellokaton.anima.converter.LevelConverter; 4 | import com.hellokaton.anima.enums.VipLevel; 5 | import com.hellokaton.anima.model.Address; 6 | import com.hellokaton.anima.model.OrderInfo; 7 | import com.hellokaton.anima.model.Person; 8 | import com.hellokaton.anima.model.User; 9 | import com.zaxxer.hikari.HikariDataSource; 10 | import com.hellokaton.anima.enums.Gender; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.junit.BeforeClass; 13 | import org.sql2o.Connection; 14 | import org.sql2o.Sql2o; 15 | 16 | /** 17 | * @author biezhi 18 | * @date 2018/3/13 19 | */ 20 | @Slf4j 21 | public class BaseTest { 22 | 23 | @BeforeClass 24 | public static void before() { 25 | h2(); 26 | initData(); 27 | System.out.println(); 28 | log.info("============== Start Test Code =============="); 29 | System.out.println(); 30 | } 31 | 32 | protected static void initData() { 33 | new User("jack", 25).save(); 34 | new User("rose", 23).save(); 35 | new User("tom", 24).save(); 36 | new User("biezhi", 8).save(); 37 | new User("lilei", 19).save(); 38 | new User("john", 38).save(); 39 | new User("king", 32).save(); 40 | new User("王尼玛", 30).save(); 41 | 42 | new OrderInfo(1, "橘子").save(); 43 | new OrderInfo(2, "果汁").save(); 44 | new OrderInfo(1, "芒果").save(); 45 | new OrderInfo(1, "葡萄干").save(); 46 | 47 | new Address(3L, "上海", "浦东新区").save(); 48 | new Address(2L, "北京", "朝阳区").save(); 49 | 50 | new Person("biezhi", Gender.MALE, VipLevel.VIP2).save(); 51 | new Person("rose", Gender.FEMALE, VipLevel.VIP3).save(); 52 | new Person("tom", Gender.MALE, VipLevel.VIP1).save(); 53 | } 54 | 55 | protected static void h2() { 56 | 57 | HikariDataSource ds = new HikariDataSource(); 58 | ds.setJdbcUrl("jdbc:h2:file:~/demo;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192"); 59 | ds.setUsername("sa"); 60 | ds.setPassword(""); 61 | 62 | Sql2o sql2o = Anima.open(ds).getSql2o(); 63 | 64 | // Sql2o sql2o = Anima.open("jdbc:h2:file:~/demo;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192", "sa", "").getSql2o(); 65 | 66 | String sql = "DROP TABLE IF EXISTS `users`;\n" + 67 | "CREATE TABLE `users` (" + 68 | "`id` IDENTITY PRIMARY KEY, " + 69 | "`user_name` varchar(50) NOT NULL, " + 70 | "`age` int(11)," + 71 | ");" + 72 | "DROP TABLE IF EXISTS `order_info`;\n" + 73 | "CREATE TABLE `order_info` (" + 74 | "`id` IDENTITY PRIMARY KEY," + 75 | "`uid` int(11) NOT NULL," + 76 | "`productname` varchar(100) NOT NULL," + 77 | "`create_time` datetime NOT NULL" + 78 | ");" + 79 | "DROP TABLE IF EXISTS `addresses`;\n" + 80 | "CREATE TABLE `addresses` (" + 81 | "`order_id` bigint(20) PRIMARY KEY," + 82 | "`city` varchar(100) NOT NULL," + 83 | "`street` varchar(200) NOT NULL" + 84 | ");" + 85 | "DROP TABLE IF EXISTS `persons`;\n" + 86 | "CREATE TABLE `persons` (" + 87 | "`name` varchar(50) PRIMARY KEY," + 88 | "`sex` varchar(10) NOT NULL," + 89 | "`vip_level` int(4) NOT NULL" + 90 | ");"; 91 | 92 | try (Connection con = sql2o.open()) { 93 | con.createQuery(sql).executeUpdate(); 94 | } 95 | } 96 | 97 | protected static void sqlite() { 98 | Sql2o sql2o = Anima.open("jdbc:sqlite:./demo.db") 99 | .addConverter(new LevelConverter()) 100 | .getSql2o(); 101 | 102 | sql2o.setIsolationLevel(java.sql.Connection.TRANSACTION_SERIALIZABLE); 103 | 104 | try (Connection con = sql2o.open()) { 105 | con.createQuery("drop table if exists users").executeUpdate(); 106 | con.createQuery("create table users (" + 107 | "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " + 108 | "user_name varchar(50) NOT NULL, " + 109 | "age INTEGER" + 110 | ");").executeUpdate(); 111 | } 112 | } 113 | 114 | protected static void mysql() { 115 | Anima.open("jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "123456"); 116 | } 117 | 118 | protected static void mysql8() { 119 | //CREATE TABLE `demo`.`无标题` ( 120 | // `id` int(10) NOT NULL AUTO_INCREMENT, 121 | // `user_name` varchar(50) NOT NULL, 122 | // `age` tinyint(2) NULL DEFAULT NULL, 123 | // PRIMARY KEY (`id`) USING BTREE 124 | //) ENGINE = InnoDB CHARACTER ROW_FORMAT = Dynamic; 125 | 126 | // Anima.open("jdbc:mysql://127.0.0.1:3317/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "123456"); 127 | 128 | HikariDataSource ds = new HikariDataSource(); 129 | ds.setJdbcUrl("jdbc:mysql://localhost:3317/demo"); 130 | ds.setUsername("root"); 131 | ds.setPassword("123456"); 132 | Anima.open(ds); 133 | Anima.delete().from(User.class).execute(); 134 | } 135 | 136 | } 137 | --------------------------------------------------------------------------------