/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jdbi.v3.core.mapper;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Objects;
import java.util.stream.IntStream;
import org.jdbi.v3.core.Handle;
import org.jdbi.v3.core.mapper.reflect.ConstructorMapper;
import org.jdbi.v3.core.rule.H2DatabaseRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
public class JoinRowMapperTest
{
@Rule
public H2DatabaseRule dbRule = new H2DatabaseRule();
private Handle h;
@Before
public void setUp()
{
h = dbRule.getSharedHandle();
h.execute("CREATE TABLE user (" +
"uid INTEGER NOT NULL," +
"name VARCHAR NOT NULL" +
")");
h.execute("CREATE TABLE article (" +
"aid INTEGER NOT NULL," +
"title VARCHAR NOT NULL" +
")");
h.execute("CREATE TABLE author (" +
"uid INTEGER NOT NULL," +
"aid INTEGER NOT NULL" +
")");
IntStream.rangeClosed(1, 3).forEach(u ->
h.execute("INSERT INTO user (uid, name) VALUES (?, ?)", u, "u" + u));
IntStream.rangeClosed(1, 3).forEach(a ->
h.execute("INSERT INTO article (aid, title) VALUES (?, ?)", a, "a" + a));
h.prepareBatch("INSERT INTO author (uid, aid) VALUES (?,?)")
.bind(0, 1).bind(1, 2).add()
.bind(0, 3).bind(1, 1).add()
.bind(0, 3).bind(1, 3).add()
.execute();
// tag::mapperSetup[]
h.registerRowMapper(ConstructorMapper.factory(User.class));
h.registerRowMapper(ConstructorMapper.factory(Article.class));
// end::mapperSetup[]
}
@Test
public void testCartesianProduct() throws Exception
{
Multimap<User, Article> product = HashMultimap.create();
h.createQuery("SELECT * FROM user, article")
.map(JoinRowMapper.forTypes(User.class, Article.class))
.forEach(jr -> product.put(jr.get(User.class), jr.get(Article.class)));
Multimap<User, Article> expected = HashMultimap.create();
IntStream.rangeClosed(1, 3).forEach(u ->
IntStream.rangeClosed(1, 3).forEach(a ->
expected.put(u(u), a(a))));
assertThat(product).isEqualTo(expected);
}
@Test
public void testJoin() throws Exception
{
// tag::multimap[]
Multimap<User, Article> joined = HashMultimap.create();
h.createQuery("SELECT * FROM user NATURAL JOIN author NATURAL JOIN article")
.map(JoinRowMapper.forTypes(User.class, Article.class))
.forEach(jr -> joined.put(jr.get(User.class), jr.get(Article.class)));
// end::multimap[]
assertThat(joined).isEqualTo(getExpected());
}
public static Multimap<User, Article> getExpected()
{
Multimap<User, Article> expected = HashMultimap.create();
expected.put(u(1), a(2));
expected.put(u(3), a(1));
expected.put(u(3), a(3));
return expected;
}
private static User u(int uid) {
return new User(uid, "u" + uid);
}
private static Article a(int aid) {
return new Article(aid, "a" + aid);
}
public static class User
{
private final int uid;
private final String name;
public User(int uid, String name) { this.uid = uid; this.name = name; }
@Override
public int hashCode() { return Objects.hash(uid, name); }
@Override
public boolean equals(Object obj)
{
if(obj instanceof User)
{
User that = (User) obj;
return Objects.equals(uid, that.uid) && Objects.equals(name, that.name);
}
return false;
}
}
public static class Article
{
private final int aid;
private final String title;
public Article(int aid, String title) { this.aid = aid; this.title = title; }
@Override
public int hashCode() { return Objects.hash(aid, title); }
@Override
public boolean equals(Object obj)
{
if(obj instanceof Article)
{
Article that = (Article) obj;
return Objects.equals(aid, that.aid) && Objects.equals(title, that.title);
}
return false;
}
}
}