/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Transaction;
import com.sleepycat.persist.EntityJoin;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.ForwardCursor;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.util.test.TxnTestCase;
/**
* @author Mark Hayes
*/
@RunWith(Parameterized.class)
public class JoinTest extends TxnTestCase {
private static final int N_RECORDS = 5;
@Parameters
public static List<Object[]> genParams() {
return getTxnParams(null, false);
}
public JoinTest(String type){
initEnvConfig();
txnType = type;
isTransactional = (txnType != TXN_NULL);
customName = txnType;
}
private EntityStore store;
private PrimaryIndex<Integer, MyEntity> primary;
private SecondaryIndex<Integer, Integer, MyEntity> sec1;
private SecondaryIndex<Integer, Integer, MyEntity> sec2;
private SecondaryIndex<Integer, Integer, MyEntity> sec3;
/**
* Opens the store.
*/
private void open()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setAllowCreate(envConfig.getAllowCreate());
config.setTransactional(envConfig.getTransactional());
store = new EntityStore(env, "test", config);
primary = store.getPrimaryIndex(Integer.class, MyEntity.class);
sec1 = store.getSecondaryIndex(primary, Integer.class, "k1");
sec2 = store.getSecondaryIndex(primary, Integer.class, "k2");
sec3 = store.getSecondaryIndex(primary, Integer.class, "k3");
}
/**
* Closes the store.
*/
private void close()
throws DatabaseException {
store.close();
}
@Test
public void testJoin()
throws DatabaseException {
open();
/*
* Primary keys: { 0, 1, 2, 3, 4 }
* Secondary k1: { 0:0, 0:1, 0:2, 0:3, 0:4 }
* Secondary k2: { 0:0, 1:1, 0:2, 1:3, 0:4 }
* Secondary k3: { 0:0, 1:1, 2:2, 0:3, 1:4 }
*/
Transaction txn = txnBegin();
for (int i = 0; i < N_RECORDS; i += 1) {
MyEntity e = new MyEntity(i, 0, i % 2, i % 3);
boolean ok = primary.putNoOverwrite(txn, e);
assertTrue(ok);
}
txnCommit(txn);
/*
* k1, k2, k3, -> { primary keys }
* -1 means don't include the key in the join.
*/
doJoin( 0, 0, 0, new int[] { 0 });
doJoin( 0, 0, 1, new int[] { 4 });
doJoin( 0, 0, -1, new int[] { 0, 2, 4 });
doJoin(-1, 1, 1, new int[] { 1 });
doJoin(-1, 2, 2, new int[] { });
doJoin(-1, -1, 2, new int[] { 2 });
close();
}
private void doJoin(int k1, int k2, int k3, int[] expectKeys)
throws DatabaseException {
List<Integer> expect = new ArrayList<Integer>();
for (int i : expectKeys) {
expect.add(i);
}
EntityJoin join = new EntityJoin(primary);
if (k1 >= 0) {
join.addCondition(sec1, k1);
}
if (k2 >= 0) {
join.addCondition(sec2, k2);
}
if (k3 >= 0) {
join.addCondition(sec3, k3);
}
List<Integer> found;
Transaction txn = txnBegin();
/* Keys */
found = new ArrayList<Integer>();
ForwardCursor<Integer> keys = join.keys(txn, null);
for (int i : keys) {
found.add(i);
}
keys.close();
assertEquals(expect, found);
/* Entities */
found = new ArrayList<Integer>();
ForwardCursor<MyEntity> entities = join.entities(txn, null);
for (MyEntity e : entities) {
found.add(e.id);
}
entities.close();
assertEquals(expect, found);
txnCommit(txn);
}
@Entity
private static class MyEntity {
@PrimaryKey
int id;
@SecondaryKey(relate=MANY_TO_ONE)
int k1;
@SecondaryKey(relate=MANY_TO_ONE)
int k2;
@SecondaryKey(relate=MANY_TO_ONE)
int k3;
private MyEntity() {}
MyEntity(int id, int k1, int k2, int k3) {
this.id = id;
this.k1 = k1;
this.k2 = k2;
this.k3 = k3;
}
@Override
public String toString() {
return "MyEntity " + id + ' ' + k1 + ' ' + k2 + ' ' + k3;
}
}
}