From 84738f9c5774b32362daa92123b7d0681ebe4d39 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Thu, 9 Dec 2010 01:44:27 +0000 Subject: [PATCH] Roll everything on up to Tuple5. We boil the plates so that you don't have to! --- .../com/samskivert/depot/QueryBuilder.java | 66 +++++++++++++- .../com/samskivert/depot/impl/Projector.java | 50 ++++++++++- .../samskivert/depot/{ => util}/Tuple2.java | 2 +- .../com/samskivert/depot/util/Tuple3.java | 79 +++++++++++++++++ .../com/samskivert/depot/util/Tuple4.java | 84 ++++++++++++++++++ .../com/samskivert/depot/util/Tuple5.java | 88 +++++++++++++++++++ ...ectFieldsTest.java => ProjectionTest.java} | 24 ++++- .../java/com/samskivert/depot/TestBase.java | 2 + .../java/com/samskivert/depot/TestRecord.java | 3 + 9 files changed, 392 insertions(+), 6 deletions(-) rename src/main/java/com/samskivert/depot/{ => util}/Tuple2.java (98%) create mode 100644 src/main/java/com/samskivert/depot/util/Tuple3.java create mode 100644 src/main/java/com/samskivert/depot/util/Tuple4.java create mode 100644 src/main/java/com/samskivert/depot/util/Tuple5.java rename src/test/java/com/samskivert/depot/{SelectFieldsTest.java => ProjectionTest.java} (77%) diff --git a/src/main/java/com/samskivert/depot/QueryBuilder.java b/src/main/java/com/samskivert/depot/QueryBuilder.java index f7e0ceb..7e6c121 100644 --- a/src/main/java/com/samskivert/depot/QueryBuilder.java +++ b/src/main/java/com/samskivert/depot/QueryBuilder.java @@ -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 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 Tuple3 load ( + SQLExpression exp1, SQLExpression exp2, SQLExpression 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 Tuple4 load ( + SQLExpression exp1, SQLExpression exp2, + SQLExpression exp3, SQLExpression 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 Tuple5 load ( + SQLExpression exp1, SQLExpression exp2, SQLExpression exp3, + SQLExpression exp4, SQLExpression 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 _ctx, Projector.create(_pclass, exp1, exp2), getClauses())); } + /** + * Returns just the supplied expressions from the rows matching the query. + */ + public List> select ( + SQLExpression exp1, SQLExpression exp2, SQLExpression exp3) + { + return _ctx.invoke(new FindAllQuery.Projection>( + _ctx, Projector.create(_pclass, exp1, exp2, exp3), getClauses())); + } + + /** + * Returns just the supplied expressions from the rows matching the query. + */ + public List> select ( + SQLExpression exp1, SQLExpression exp2, + SQLExpression exp3, SQLExpression exp4) + { + return _ctx.invoke(new FindAllQuery.Projection>( + _ctx, Projector.create(_pclass, exp1, exp2, exp3, exp4), + getClauses())); + } + + /** + * Returns just the supplied expressions from the rows matching the query. + */ + public List> select ( + SQLExpression exp1, SQLExpression exp2, SQLExpression exp3, + SQLExpression exp4, SQLExpression exp5) + { + return _ctx.invoke(new FindAllQuery.Projection>( + _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 diff --git a/src/main/java/com/samskivert/depot/impl/Projector.java b/src/main/java/com/samskivert/depot/impl/Projector.java index 1fe9903..dd4acac 100644 --- a/src/main/java/com/samskivert/depot/impl/Projector.java +++ b/src/main/java/com/samskivert/depot/impl/Projector.java @@ -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 }; } + public static Projector> create ( + Class ptype, SQLExpression col1, SQLExpression col2, SQLExpression col3) + { + return new Projector>(ptype, new SQLExpression[] { col1, col2, col3 }) { + public Tuple3 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(r1, r2, r3); + } + }; + } + + public static + Projector> create ( + Class ptype, SQLExpression col1, SQLExpression col2, SQLExpression col3, + SQLExpression col4) + { + return new Projector>( + ptype, new SQLExpression[] { col1, col2, col3, col4 }) { + public Tuple4 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(r1, r2, r3, r4); + } + }; + } + + public static + Projector> create ( + Class ptype, SQLExpression col1, SQLExpression col2, SQLExpression col3, + SQLExpression col4, SQLExpression col5) + { + return new Projector>( + ptype, new SQLExpression[] { col1, col2, col3, col4, col5 }) { + public Tuple5 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(r1, r2, r3, r4, r5); + } + }; + } + public final Class ptype; public final SQLExpression[] selexps; diff --git a/src/main/java/com/samskivert/depot/Tuple2.java b/src/main/java/com/samskivert/depot/util/Tuple2.java similarity index 98% rename from src/main/java/com/samskivert/depot/Tuple2.java rename to src/main/java/com/samskivert/depot/util/Tuple2.java index a61ebf1..b998429 100644 --- a/src/main/java/com/samskivert/depot/Tuple2.java +++ b/src/main/java/com/samskivert/depot/util/Tuple2.java @@ -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; diff --git a/src/main/java/com/samskivert/depot/util/Tuple3.java b/src/main/java/com/samskivert/depot/util/Tuple3.java new file mode 100644 index 0000000..9000ed0 --- /dev/null +++ b/src/main/java/com/samskivert/depot/util/Tuple3.java @@ -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 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 Tuple3 create (A a, B b, C c) + { + return new Tuple3(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; + } + } +} diff --git a/src/main/java/com/samskivert/depot/util/Tuple4.java b/src/main/java/com/samskivert/depot/util/Tuple4.java new file mode 100644 index 0000000..09932d6 --- /dev/null +++ b/src/main/java/com/samskivert/depot/util/Tuple4.java @@ -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 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 Tuple4 create (A a, B b, C c, D d) + { + return new Tuple4(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; + } + } +} diff --git a/src/main/java/com/samskivert/depot/util/Tuple5.java b/src/main/java/com/samskivert/depot/util/Tuple5.java new file mode 100644 index 0000000..c12f271 --- /dev/null +++ b/src/main/java/com/samskivert/depot/util/Tuple5.java @@ -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 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 Tuple5 create (A a, B b, C c, D d, E e) + { + return new Tuple5(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; + } + } +} diff --git a/src/test/java/com/samskivert/depot/SelectFieldsTest.java b/src/test/java/com/samskivert/depot/ProjectionTest.java similarity index 77% rename from src/test/java/com/samskivert/depot/SelectFieldsTest.java rename to src/test/java/com/samskivert/depot/ProjectionTest.java index 1a391f1..e00ae16 100644 --- a/src/test/java/com/samskivert/depot/SelectFieldsTest.java +++ b/src/test/java/com/samskivert/depot/ProjectionTest.java @@ -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 diff --git a/src/test/java/com/samskivert/depot/TestBase.java b/src/test/java/com/samskivert/depot/TestBase.java index 45f6db5..4e939d9 100644 --- a/src/test/java/com/samskivert/depot/TestBase.java +++ b/src/test/java/com/samskivert/depot/TestBase.java @@ -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)); } diff --git a/src/test/java/com/samskivert/depot/TestRecord.java b/src/test/java/com/samskivert/depot/TestRecord.java index c82d1c4..27513e5 100644 --- a/src/test/java/com/samskivert/depot/TestRecord.java +++ b/src/test/java/com/samskivert/depot/TestRecord.java @@ -42,6 +42,7 @@ public class TestRecord extends PersistentRecord public static final ColumnExp NAME = colexp(_R, "name"); public static final ColumnExp AGE = colexp(_R, "age"); public static final ColumnExp HOME_TOWN = colexp(_R, "homeTown"); + public static final ColumnExp TYPE = colexp(_R, "type"); public static final ColumnExp CREATED = colexp(_R, "created"); public static final ColumnExp LAST_MODIFIED = colexp(_R, "lastModified"); public static final ColumnExp NUMBERS = colexp(_R, "numbers"); @@ -58,6 +59,8 @@ public class TestRecord extends PersistentRecord public String homeTown; + public EnumKeyRecord.Type type; + @Index public Date created;