Added a totally type-safe mechanism for selecting ad-hoc query results into

pojos which hold the results of the query. The caller can decide if they want
to use the magic of selectInto(), and be careful not to screw up the types and
order of their pojo fields, or they can boil up some plates and create a
builder for their pojo, which will be type-checked, soup to nuts.
This commit is contained in:
Michael Bayne
2010-12-13 19:29:50 +00:00
parent 90b04e68b8
commit 5e10393463
10 changed files with 253 additions and 37 deletions
+59 -11
View File
@@ -428,8 +428,8 @@ public class Query<T extends PersistentRecord>
*/
public <V1, V2> List<Tuple2<V1,V2>> select (SQLExpression<V1> exp1, SQLExpression<V2> exp2)
{
return _ctx.invoke(new FindAllQuery.Projection<T,Tuple2<V1,V2>>(
_ctx, Projector.create(_pclass, exp1, exp2), getClauses()));
Builder2<Tuple2<V1,V2>,V1,V2> builder = Tuple2.builder();
return select(builder, exp1, exp2);
}
/**
@@ -438,8 +438,8 @@ public class Query<T extends PersistentRecord>
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()));
Builder3<Tuple3<V1,V2,V3>,V1,V2,V3> builder = Tuple3.builder();
return select(builder, exp1, exp2, exp3);
}
/**
@@ -449,9 +449,8 @@ public class Query<T extends PersistentRecord>
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()));
Builder4<Tuple4<V1,V2,V3,V4>,V1,V2,V3,V4> builder = Tuple4.builder();
return select(builder, exp1, exp2, exp3, exp4);
}
/**
@@ -461,13 +460,15 @@ public class Query<T extends PersistentRecord>
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()));
Builder5<Tuple5<V1,V2,V3,V4,V5>,V1,V2,V3,V4,V5> builder = Tuple5.builder();
return select(builder, exp1, exp2, exp3, exp4, exp5);
}
/**
* Returns just the supplied expression from the rows matching the query.
* Selects the supplied expressions and writes their values into the supplied result class. The
* result expressions will be matched to the fields of the result class in declaration order.
* The fields of the result class must match the types of the selected expressions modulo the
* automatic conversions applied by reflective assignment (unboxing and widening).
*/
public <V> List<V> selectInto (Class<V> resultClass, SQLExpression<?>... selexps)
{
@@ -475,6 +476,53 @@ public class Query<T extends PersistentRecord>
return _ctx.invoke(new FindAllQuery.Projection<T,V>(_ctx, proj, getClauses()));
}
/**
* Selects the supplied expressions and constructs a result record using their values using the
* supplied record builder.
*/
public <R,V1,V2> List<R> select (
Builder2<R,V1,V2> builder, SQLExpression<V1> exp1, SQLExpression<V2> exp2)
{
Projector<T, R> proj = Projector.create(_pclass, builder, exp1, exp2);
return _ctx.invoke(new FindAllQuery.Projection<T,R>(_ctx, proj, getClauses()));
}
/**
* Selects the supplied expressions and constructs a result record using their values using the
* supplied record builder.
*/
public <R, V1, V2, V3> List<R> select (
Builder3<R,V1,V2,V3> builder, SQLExpression<V1> exp1, SQLExpression<V2> exp2,
SQLExpression<V3> exp3)
{
Projector<T, R> proj = Projector.create(_pclass, builder, exp1, exp2, exp3);
return _ctx.invoke(new FindAllQuery.Projection<T,R>(_ctx, proj, getClauses()));
}
/**
* Selects the supplied expressions and constructs a result record using their values using the
* supplied record builder.
*/
public <R, V1, V2, V3, V4> List<R> select (
Builder4<R,V1,V2,V3,V4> builder, SQLExpression<V1> exp1, SQLExpression<V2> exp2,
SQLExpression<V3> exp3, SQLExpression<V4> exp4)
{
Projector<T, R> proj = Projector.create(_pclass, builder, exp1, exp2, exp3, exp4);
return _ctx.invoke(new FindAllQuery.Projection<T,R>(_ctx, proj, getClauses()));
}
/**
* Selects the supplied expressions and constructs a result record using their values using the
* supplied record builder.
*/
public <R, V1, V2, V3, V4, V5> List<R> select (
Builder5<R,V1,V2,V3,V4,V5> builder, SQLExpression<V1> exp1, SQLExpression<V2> exp2,
SQLExpression<V3> exp3, SQLExpression<V4> exp4, SQLExpression<V5> exp5)
{
Projector<T, R> proj = Projector.create(_pclass, builder, exp1, exp2, exp3, exp4, exp5);
return _ctx.invoke(new FindAllQuery.Projection<T,R>(_ctx, proj, 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
@@ -45,63 +45,63 @@ public abstract class Projector<T extends PersistentRecord,R>
};
}
public static <T extends PersistentRecord, V1, V2> Projector<T,Tuple2<V1,V2>> create (
Class<T> ptype, SQLExpression<V1> col1, SQLExpression<V2> col2)
public static <T extends PersistentRecord, R, V1, V2> Projector<T,R> create (
Class<T> ptype, final Builder2<R, V1, V2> builder,
SQLExpression<V1> col1, SQLExpression<V2> col2)
{
return new Projector<T, Tuple2<V1,V2>>(ptype, new SQLExpression<?>[] { col1, col2 }) {
@Override public Tuple2<V1,V2> createObject (Object[] results) {
return new Projector<T, R>(ptype, new SQLExpression<?>[] { col1, col2 }) {
@Override public R createObject (Object[] results) {
@SuppressWarnings("unchecked") V1 r1 = (V1)results[0];
@SuppressWarnings("unchecked") V2 r2 = (V2)results[1];
return new Tuple2<V1,V2>(r1, r2);
return builder.build(r1, r2);
}
};
}
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)
public static <T extends PersistentRecord, R, V1, V2, V3> Projector<T,R> create (
Class<T> ptype, final Builder3<R, V1, V2, V3> builder,
SQLExpression<V1> col1, SQLExpression<V2> col2, SQLExpression<V3> col3)
{
return new Projector<T, Tuple3<V1,V2,V3>>(
return new Projector<T, R>(
ptype, new SQLExpression<?>[] { col1, col2, col3 }) {
@Override public Tuple3<V1,V2,V3> createObject (Object[] results) {
@Override public R 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);
return builder.build(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)
public static <T extends PersistentRecord, R, V1, V2, V3, V4> Projector<T,R> create (
Class<T> ptype, final Builder4<R, V1, V2, V3, V4> builder,
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 }) {
@Override public Tuple4<V1,V2,V3,V4> createObject (Object[] results) {
return new Projector<T, R>(ptype, new SQLExpression<?>[] { col1, col2, col3, col4 }) {
@Override public R 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);
return builder.build(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)
public static <T extends PersistentRecord, R, V1, V2, V3, V4, V5> Projector<T,R> create (
Class<T> ptype, final Builder5<R, V1, V2, V3, V4, V5> builder,
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 }) {
@Override public Tuple5<V1,V2,V3,V4,V5> createObject (Object[] results) {
return new Projector<T, R>(ptype, new SQLExpression<?>[] { col1, col2, col3, col4, col5 }) {
@Override public R 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);
return builder.build(r1, r2, r3, r4, r5);
}
};
}
@@ -0,0 +1,32 @@
//
// $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;
/**
* A type-safe builder used to construct objects from the columns selected from Depot queries.
*/
public interface Builder2<T, A, B>
{
/**
* Builds an instance, using the supplied data.
*/
public T build (A a, B b);
}
@@ -0,0 +1,32 @@
//
// $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;
/**
* A type-safe builder used to construct objects from the columns selected from Depot queries.
*/
public interface Builder3<T, A, B, C>
{
/**
* Builds an instance, using the supplied data.
*/
public T build (A a, B b, C c);
}
@@ -0,0 +1,32 @@
//
// $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;
/**
* A type-safe builder used to construct objects from the columns selected from Depot queries.
*/
public interface Builder4<T, A, B, C, D>
{
/**
* Builds an instance, using the supplied data.
*/
public T build (A a, B b, C c, D d);
}
@@ -0,0 +1,32 @@
//
// $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;
/**
* A type-safe builder used to construct objects from the columns selected from Depot queries.
*/
public interface Builder5<T, A, B, C, D, E>
{
/**
* Builds an instance, using the supplied data.
*/
public T build (A a, B b, C c, D d, E e);
}
@@ -43,6 +43,16 @@ public class Tuple2<A,B> implements Serializable
return new Tuple2<A, B>(a, b);
}
/** Creates a builder for 2-tuples. */
public static <A, B> Builder2<Tuple2<A, B>, A, B> builder ()
{
return new Builder2<Tuple2<A, B>, A, B>() {
public Tuple2<A, B> build (A a, B b) {
return create(a, b);
}
};
}
/** Constructs an initialized two tuple. */
public Tuple2 (A a, B b)
{
@@ -46,6 +46,16 @@ public class Tuple3<A,B,C> implements Serializable
return new Tuple3<A, B, C>(a, b, c);
}
/** Creates a builder for 3-tuples. */
public static <A, B, C> Builder3<Tuple3<A, B, C>, A, B, C> builder ()
{
return new Builder3<Tuple3<A, B, C>, A, B, C>() {
public Tuple3<A, B, C> build (A a, B b, C c) {
return create(a, b, c);
}
};
}
/** Constructs an initialized tuple. */
public Tuple3 (A a, B b, C c)
{
@@ -49,6 +49,16 @@ public class Tuple4<A,B,C,D> implements Serializable
return new Tuple4<A, B, C, D>(a, b, c, d);
}
/** Creates a builder for 4-tuples. */
public static <A, B, C, D> Builder4<Tuple4<A, B, C, D>, A, B, C, D> builder ()
{
return new Builder4<Tuple4<A, B, C, D>, A, B, C, D>() {
public Tuple4<A, B, C, D> build (A a, B b, C c, D d) {
return create(a, b, c, d);
}
};
}
/** Constructs an initialized tuple. */
public Tuple4 (A a, B b, C c, D d)
{
@@ -52,6 +52,16 @@ public class Tuple5<A,B,C,D,E> implements Serializable
return new Tuple5<A, B, C, D, E>(a, b, c, d, e);
}
/** Creates a builder for 5-tuples. */
public static <A, B, C, D, E> Builder5<Tuple5<A, B, C, D, E>, A, B, C, D, E> builder ()
{
return new Builder5<Tuple5<A, B, C, D, E>, A, B, C, D, E>() {
public Tuple5<A, B, C, D, E> build (A a, B b, C c, D d, E e) {
return create(a, b, c, d, e);
}
};
}
/** Constructs an initialized tuple. */
public Tuple5 (A a, B b, C c, D d, E e)
{