Roll everything on up to Tuple5. We boil the plates so that you don't have to!

This commit is contained in:
Michael Bayne
2010-12-09 01:44:27 +00:00
parent de6feea1eb
commit 84738f9c57
9 changed files with 392 additions and 6 deletions
@@ -29,8 +29,9 @@ import com.google.common.collect.Lists;
import com.samskivert.depot.clause.*;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.impl.Projector;
import com.samskivert.depot.impl.FindAllQuery;
import com.samskivert.depot.impl.Projector;
import com.samskivert.depot.util.*; // TupleN
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
@@ -378,6 +379,35 @@ public class QueryBuilder<T extends PersistentRecord>
return select(exp1, exp2).get(0); // TODO: revamp FindOneQuery and use that
}
/**
* Returns the value from the first row that matches the configured query clauses.
*/
public <V1, V2, V3> Tuple3<V1, V2, V3> load (
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3)
{
return select(exp1, exp2, exp3).get(0); // TODO: revamp FindOneQuery and use that
}
/**
* Returns the value from the first row that matches the configured query clauses.
*/
public <V1, V2, V3, V4> Tuple4<V1, V2, V3, V4> load (
SQLExpression<V1> exp1, SQLExpression<V2> exp2,
SQLExpression<V3> exp3, SQLExpression<V4> exp4)
{
return select(exp1, exp2, exp3, exp4).get(0); // TODO: revamp FindOneQuery and use that
}
/**
* Returns the value from the first row that matches the configured query clauses.
*/
public <V1, V2, V3, V4, V5> Tuple5<V1, V2, V3, V4, V5> load (
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3,
SQLExpression<V4> exp4, SQLExpression<V5> exp5)
{
return select(exp1, exp2, exp3, exp4, exp5).get(0); // TODO: use revamped FindOneQuery
}
/**
* Returns just the supplied expression from the rows matching the query.
*/
@@ -396,6 +426,40 @@ public class QueryBuilder<T extends PersistentRecord>
_ctx, Projector.create(_pclass, exp1, exp2), getClauses()));
}
/**
* Returns just the supplied expressions from the rows matching the query.
*/
public <V1, V2, V3> List<Tuple3<V1,V2,V3>> select (
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3)
{
return _ctx.invoke(new FindAllQuery.Projection<T,Tuple3<V1,V2,V3>>(
_ctx, Projector.create(_pclass, exp1, exp2, exp3), getClauses()));
}
/**
* Returns just the supplied expressions from the rows matching the query.
*/
public <V1, V2, V3, V4> List<Tuple4<V1,V2,V3,V4>> select (
SQLExpression<V1> exp1, SQLExpression<V2> exp2,
SQLExpression<V3> exp3, SQLExpression<V4> exp4)
{
return _ctx.invoke(new FindAllQuery.Projection<T,Tuple4<V1,V2,V3,V4>>(
_ctx, Projector.create(_pclass, exp1, exp2, exp3, exp4),
getClauses()));
}
/**
* Returns just the supplied expressions from the rows matching the query.
*/
public <V1, V2, V3, V4, V5> List<Tuple5<V1,V2,V3,V4,V5>> select (
SQLExpression<V1> exp1, SQLExpression<V2> exp2, SQLExpression<V3> exp3,
SQLExpression<V4> exp4, SQLExpression<V5> exp5)
{
return _ctx.invoke(new FindAllQuery.Projection<T,Tuple5<V1,V2,V3,V4,V5>>(
_ctx, Projector.create(_pclass, exp1, exp2, exp3, exp4, exp5),
getClauses()));
}
/**
* Deletes the records that match the configured query clauses. Note that only the where
* clauses are used to evaluate a deletion. Attempts to use other clauses will result in
@@ -21,8 +21,8 @@
package com.samskivert.depot.impl;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.Tuple2;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.util.*; // TupleN
/**
* Contains a set of selection expressions which are to be projected (selected) from a set of
@@ -53,6 +53,54 @@ public abstract class Projector<T extends PersistentRecord,R>
};
}
public static <T extends PersistentRecord, V1, V2, V3> Projector<T,Tuple3<V1,V2,V3>> create (
Class<T> ptype, SQLExpression<V1> col1, SQLExpression<V2> col2, SQLExpression<V3> col3)
{
return new Projector<T, Tuple3<V1,V2,V3>>(ptype, new SQLExpression[] { col1, col2, col3 }) {
public Tuple3<V1,V2,V3> createObject (Object[] results) {
@SuppressWarnings("unchecked") V1 r1 = (V1)results[0];
@SuppressWarnings("unchecked") V2 r2 = (V2)results[1];
@SuppressWarnings("unchecked") V3 r3 = (V3)results[2];
return new Tuple3<V1,V2,V3>(r1, r2, r3);
}
};
}
public static <T extends PersistentRecord, V1, V2, V3, V4>
Projector<T,Tuple4<V1,V2,V3,V4>> create (
Class<T> ptype, SQLExpression<V1> col1, SQLExpression<V2> col2, SQLExpression<V3> col3,
SQLExpression<V4> col4)
{
return new Projector<T, Tuple4<V1,V2,V3,V4>>(
ptype, new SQLExpression[] { col1, col2, col3, col4 }) {
public Tuple4<V1,V2,V3,V4> createObject (Object[] results) {
@SuppressWarnings("unchecked") V1 r1 = (V1)results[0];
@SuppressWarnings("unchecked") V2 r2 = (V2)results[1];
@SuppressWarnings("unchecked") V3 r3 = (V3)results[2];
@SuppressWarnings("unchecked") V4 r4 = (V4)results[3];
return new Tuple4<V1,V2,V3,V4>(r1, r2, r3, r4);
}
};
}
public static <T extends PersistentRecord, V1, V2, V3, V4, V5>
Projector<T,Tuple5<V1,V2,V3,V4,V5>> create (
Class<T> ptype, SQLExpression<V1> col1, SQLExpression<V2> col2, SQLExpression<V3> col3,
SQLExpression<V4> col4, SQLExpression<V5> col5)
{
return new Projector<T, Tuple5<V1,V2,V3,V4,V5>>(
ptype, new SQLExpression[] { col1, col2, col3, col4, col5 }) {
public Tuple5<V1,V2,V3,V4,V5> createObject (Object[] results) {
@SuppressWarnings("unchecked") V1 r1 = (V1)results[0];
@SuppressWarnings("unchecked") V2 r2 = (V2)results[1];
@SuppressWarnings("unchecked") V3 r3 = (V3)results[2];
@SuppressWarnings("unchecked") V4 r4 = (V4)results[3];
@SuppressWarnings("unchecked") V5 r5 = (V5)results[4];
return new Tuple5<V1,V2,V3,V4,V5>(r1, r2, r3, r4, r5);
}
};
}
public final Class<T> ptype;
public final SQLExpression<?>[] selexps;
@@ -18,7 +18,7 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot;
package com.samskivert.depot.util;
import java.io.Serializable;
@@ -0,0 +1,79 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2010 Michael Bayne and Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot.util;
import java.io.Serializable;
import com.google.common.base.Objects;
/**
* Contains a three column result. This class is immutable and the objects it references are also
* meant to be immutable. They will generally contain only Depot primitive types (Java primitives,
* SQL primitives and some array types), which should be treated as immutable.
*/
public class Tuple3<A,B,C> implements Serializable
{
/** The first column of the result. */
public final A a;
/** The second column of the result. */
public final B b;
/** The third column of the result. */
public final C c;
/** Constructs an initialized tuple. */
public static <A, B, C> Tuple3<A, B, C> create (A a, B b, C c)
{
return new Tuple3<A, B, C>(a, b, c);
}
/** Constructs an initialized tuple. */
public Tuple3 (A a, B b, C c)
{
this.a = a;
this.b = b;
this.c = c;
}
@Override
public String toString ()
{
return "[" + a + "," + b + "," + c + "]";
}
@Override
public int hashCode ()
{
return Objects.hashCode(a, b, c);
}
@Override
public boolean equals (Object other)
{
if (other instanceof Tuple3<?,?,?>) {
Tuple3<?,?,?> otup = (Tuple3<?,?,?>)other;
return Objects.equal(a, otup.a) && Objects.equal(b, otup.b) && Objects.equal(c, otup.c);
} else {
return false;
}
}
}
@@ -0,0 +1,84 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2010 Michael Bayne and Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot.util;
import java.io.Serializable;
import com.google.common.base.Objects;
/**
* Contains a four column result. This class is immutable and the objects it references are also
* meant to be immutable. They will generally contain only Depot primitive types (Java primitives,
* SQL primitives and some array types), which should be treated as immutable.
*/
public class Tuple4<A,B,C,D> implements Serializable
{
/** The first column of the result. */
public final A a;
/** The second column of the result. */
public final B b;
/** The third column of the result. */
public final C c;
/** The fourth column of the result. */
public final D d;
/** Constructs an initialized tuple. */
public static <A, B, C, D> Tuple4<A, B, C, D> create (A a, B b, C c, D d)
{
return new Tuple4<A, B, C, D>(a, b, c, d);
}
/** Constructs an initialized tuple. */
public Tuple4 (A a, B b, C c, D d)
{
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
@Override
public String toString ()
{
return "[" + a + "," + b + "," + c + "," + d + "]";
}
@Override
public int hashCode ()
{
return Objects.hashCode(a, b, c, d);
}
@Override
public boolean equals (Object other)
{
if (other instanceof Tuple4<?,?,?,?>) {
Tuple4<?,?,?,?> otup = (Tuple4<?,?,?,?>)other;
return Objects.equal(a, otup.a) && Objects.equal(b, otup.b) &&
Objects.equal(c, otup.c) && Objects.equal(d, otup.d);
} else {
return false;
}
}
}
@@ -0,0 +1,88 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2010 Michael Bayne and Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot.util;
import java.io.Serializable;
import com.google.common.base.Objects;
/**
* Contains a five column result. This class is immutable and the objects it references are also
* meant to be immutable. They will generally contain only Depot primitive types (Java primitives,
* SQL primitives and some array types), which should be treated as immutable.
*/
public class Tuple5<A,B,C,D,E> implements Serializable
{
/** The first column of the result. */
public final A a;
/** The second column of the result. */
public final B b;
/** The third column of the result. */
public final C c;
/** The fourth column of the result. */
public final D d;
/** The fifth column of the result. */
public final E e;
/** Constructs an initialized tuple. */
public static <A, B, C, D, E> Tuple5<A, B, C, D, E> create (A a, B b, C c, D d, E e)
{
return new Tuple5<A, B, C, D, E>(a, b, c, d, e);
}
/** Constructs an initialized tuple. */
public Tuple5 (A a, B b, C c, D d, E e)
{
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
}
@Override
public String toString ()
{
return "[" + a + "," + b + "," + c + "," + d + "," + e + "]";
}
@Override
public int hashCode ()
{
return Objects.hashCode(a, b, c, d, e);
}
@Override
public boolean equals (Object other)
{
if (other instanceof Tuple5<?,?,?,?,?>) {
Tuple5<?,?,?,?,?> otup = (Tuple5<?,?,?,?,?>)other;
return Objects.equal(a, otup.a) && Objects.equal(b, otup.b) &&
Objects.equal(c, otup.c) && Objects.equal(d, otup.d) && Objects.equal(e, otup.e);
} else {
return false;
}
}
}
@@ -23,7 +23,7 @@ package com.samskivert.depot;
import java.util.List;
import com.google.common.collect.Lists;
import com.samskivert.depot.Tuple2;
import com.samskivert.depot.util.*; // TupleN
import org.junit.After;
import org.junit.Before;
@@ -31,9 +31,9 @@ import org.junit.Test;
import static org.junit.Assert.*;
/**
* Tests individual field selection.
* Tests projection selections, aggregates, etc.
*/
public class SelectFieldsTest extends TestBase
public class ProjectionTest extends TestBase
{
@Before public void createRecords ()
{
@@ -70,6 +70,24 @@ public class SelectFieldsTest extends TestBase
assertEquals(data, want);
}
@Test public void testTupleN ()
{
assertEquals(Tuple2.create(1, "Elvis"),
_repo.from(TestRecord.class).where(TestRecord.RECORD_ID.eq(1)).
load(TestRecord.RECORD_ID, TestRecord.NAME));
assertEquals(Tuple3.create(1, "Elvis", 99),
_repo.from(TestRecord.class).where(TestRecord.RECORD_ID.eq(1)).
load(TestRecord.RECORD_ID, TestRecord.NAME, TestRecord.AGE));
assertEquals(Tuple4.create(1, "Elvis", 99, "Right here"),
_repo.from(TestRecord.class).where(TestRecord.RECORD_ID.eq(1)).
load(TestRecord.RECORD_ID, TestRecord.NAME, TestRecord.AGE,
TestRecord.HOME_TOWN));
assertEquals(Tuple5.create(1, "Elvis", 99, "Right here", EnumKeyRecord.Type.A),
_repo.from(TestRecord.class).where(TestRecord.RECORD_ID.eq(1)).
load(TestRecord.RECORD_ID, TestRecord.NAME, TestRecord.AGE,
TestRecord.HOME_TOWN, TestRecord.TYPE));
}
@Test public void testProjectedJoin ()
{
// test a basic join
@@ -75,6 +75,7 @@ public abstract class TestBase
rec.age = 99;
rec.created = now;
rec.homeTown = "Right here";
rec.type = EnumKeyRecord.Type.A;
rec.lastModified = tnow;
rec.numbers = new int[] { 9, 0, 2, 1, 0 };
return rec;
@@ -90,6 +91,7 @@ public abstract class TestBase
assertEquals(expect.age, got.age);
assertEquals(expect.created, got.created);
assertEquals(expect.homeTown, got.homeTown);
assertEquals(expect.type, got.type);
assertEquals(expect.lastModified, got.lastModified);
assertTrue(Arrays.equals(expect.numbers, got.numbers));
}
@@ -42,6 +42,7 @@ public class TestRecord extends PersistentRecord
public static final ColumnExp<String> NAME = colexp(_R, "name");
public static final ColumnExp<Integer> AGE = colexp(_R, "age");
public static final ColumnExp<String> HOME_TOWN = colexp(_R, "homeTown");
public static final ColumnExp<EnumKeyRecord.Type> TYPE = colexp(_R, "type");
public static final ColumnExp<Date> CREATED = colexp(_R, "created");
public static final ColumnExp<Timestamp> LAST_MODIFIED = colexp(_R, "lastModified");
public static final ColumnExp<int[]> NUMBERS = colexp(_R, "numbers");
@@ -58,6 +59,8 @@ public class TestRecord extends PersistentRecord
public String homeTown;
public EnumKeyRecord.Type type;
@Index
public Date created;