// Path: src/test/java/com/github/mjdbc/test/asset/model/User.java
// public final class User {
//     /**
//      * It is recommended to have type safe IDs.
//      */
//     public UserId id;
//     public String login;
//     public String firstName;
//     public String lastName;
//     public Gender gender;
//     public long score;
//     public Timestamp registrationDate;
// 
//     /**
//      * Class to create User object from result set.
//      */
//     @Mapper
//     public static final DbMapper<User> MAPPER = (r) -> {
//         User user = new User();
//         user.id = new UserId(r.getInt("id"));
//         user.login = r.getString("login");
//         user.firstName = r.getString("first_name");
//         user.lastName = r.getString("last_name");
//         user.gender = Gender.fromDbValue(r.getInt("gender"));
//         user.score = r.getLong("score");
//         user.registrationDate = r.getTimestamp("reg_date");
//         return user;
//     };
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
//         User user = (User) o;
//         return score == user.score &&
//                 Objects.equals(id, user.id) &&
//                 Objects.equals(login, user.login) &&
//                 Objects.equals(firstName, user.firstName) &&
//                 Objects.equals(lastName, user.lastName) &&
//                 gender == user.gender &&
//                 Objects.equals(registrationDate, user.registrationDate);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(id, login, firstName, lastName, gender, score, registrationDate);
//     }
// }
// 
// Path: src/test/java/com/github/mjdbc/test/asset/sql/ReaderSql.java
// public interface ReaderSql {
// 
//     @Sql("UPDATE users SET first_name = :firstName  WHERE login = :login")
//     void updateFirstNameWithReader(@Bind("login") String login, @Bind("firstName") Reader r);
// }
// 
// Path: src/test/java/com/github/mjdbc/test/asset/sql/error/AmbiguousTypeSql.java
// public interface AmbiguousTypeSql {
//     @Sql("SELECT count(*) FROM users WHERE id = :id")
//     int call(@Bind("id") AmbiguousTypeValue value);
// }


import com.github.mjdbc.test.asset.model.DbType1;
import com.github.mjdbc.test.asset.model.DbType2;
import com.github.mjdbc.test.asset.model.User;
import com.github.mjdbc.test.asset.model.UserId;
import com.github.mjdbc.test.asset.sql.ReaderSql;
import com.github.mjdbc.test.asset.sql.UserSql;
import com.github.mjdbc.test.asset.sql.error.AmbiguousTypeSql;
import java.io.Reader;
import java.io.StringReader;
import java.sql.PreparedStatement;
import org.junit.Before;
import org.junit.Test;
        ReaderSql q1 = db.attachSql(ReaderSql.class);
        q1.updateFirstNameWithReader("u1", new StringReader("x"));

        UserSql q2 = db.attachSql(UserSql.class);
        User u = q2.getUserByLogin("u1");
        assertNotNull(u);
        assertEquals("x", u.firstName);
    }

    /**
     * Check that registration of null binder triggers IllegalArgumentException
     */
    @Test(expected = NullPointerException.class)
    public void nullBinderTypeTriggersNullPointerException() {
        //noinspection ConstantConditions,RedundantCast
        db.registerBinder((Class<Reader>) null, PreparedStatement::setCharacterStream);
    }

    @Test(expected = NullPointerException.class)
    public void nullBinderFunctionTriggersNullPointerException() {
        //noinspection ConstantConditions
        db.registerBinder(Reader.class, null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void multipleBindersForSameObjectThrowException() {
        db.registerBinder(DbType1.class, (statement, idx, value) -> {
        });
        db.registerBinder(DbType2.class, (statement, idx, value) -> {
        });
// Path: src/test/java/com/github/mjdbc/test/asset/model/User.java
// public final class User {
//     /**
//      * It is recommended to have type safe IDs.
//      */
//     public UserId id;
//     public String login;
//     public String firstName;
//     public String lastName;
//     public Gender gender;
//     public long score;
//     public Timestamp registrationDate;
// 
//     /**
//      * Class to create User object from result set.
//      */
//     @Mapper
//     public static final DbMapper<User> MAPPER = (r) -> {
//         User user = new User();
//         user.id = new UserId(r.getInt("id"));
//         user.login = r.getString("login");
//         user.firstName = r.getString("first_name");
//         user.lastName = r.getString("last_name");
//         user.gender = Gender.fromDbValue(r.getInt("gender"));
//         user.score = r.getLong("score");
//         user.registrationDate = r.getTimestamp("reg_date");
//         return user;
//     };
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
//         User user = (User) o;
//         return score == user.score &&
//                 Objects.equals(id, user.id) &&
//                 Objects.equals(login, user.login) &&
//                 Objects.equals(firstName, user.firstName) &&
//                 Objects.equals(lastName, user.lastName) &&
//                 gender == user.gender &&
//                 Objects.equals(registrationDate, user.registrationDate);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(id, login, firstName, lastName, gender, score, registrationDate);
//     }
// }
// 
// Path: src/test/java/com/github/mjdbc/test/asset/sql/ReaderSql.java
// public interface ReaderSql {
// 
//     @Sql("UPDATE users SET first_name = :firstName  WHERE login = :login")
//     void updateFirstNameWithReader(@Bind("login") String login, @Bind("firstName") Reader r);
// }
// 
// Path: src/test/java/com/github/mjdbc/test/asset/sql/error/AmbiguousTypeSql.java
// public interface AmbiguousTypeSql {
//     @Sql("SELECT count(*) FROM users WHERE id = :id")
//     int call(@Bind("id") AmbiguousTypeValue value);
// }


// Path: src/test/java/com/github/mjdbc/test/DbRegisterBinderTest.java
import com.github.mjdbc.test.asset.model.DbType1;
import com.github.mjdbc.test.asset.model.DbType2;
import com.github.mjdbc.test.asset.model.User;
import com.github.mjdbc.test.asset.model.UserId;
import com.github.mjdbc.test.asset.sql.ReaderSql;
import com.github.mjdbc.test.asset.sql.UserSql;
import com.github.mjdbc.test.asset.sql.error.AmbiguousTypeSql;
import java.io.Reader;
import java.io.StringReader;
import java.sql.PreparedStatement;
import org.junit.Before;
import org.junit.Test;

        ReaderSql q1 = db.attachSql(ReaderSql.class);
        q1.updateFirstNameWithReader("u1", new StringReader("x"));

        UserSql q2 = db.attachSql(UserSql.class);
        User u = q2.getUserByLogin("u1");
        assertNotNull(u);
        assertEquals("x", u.firstName);
    }

    /**
     * Check that registration of null binder triggers IllegalArgumentException
     */
    @Test(expected = NullPointerException.class)
    public void nullBinderTypeTriggersNullPointerException() {
        //noinspection ConstantConditions,RedundantCast
        db.registerBinder((Class<Reader>) null, PreparedStatement::setCharacterStream);
    }

    @Test(expected = NullPointerException.class)
    public void nullBinderFunctionTriggersNullPointerException() {
        //noinspection ConstantConditions
        db.registerBinder(Reader.class, null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void multipleBindersForSameObjectThrowException() {
        db.registerBinder(DbType1.class, (statement, idx, value) -> {
        });
        db.registerBinder(DbType2.class, (statement, idx, value) -> {
        });
        db.attachSql(AmbiguousTypeSql.class);