This is possibly getting a little too jiggy, but I'm having all Depot methods

that return a collection return an XList which extends List and adds the
method:

    public <R> Iterable<R> map (Function<T, R> mapper);

which allows you to do things the following:

    return findAll(CategoryRecord.class,
                   new Where(CategoryRecord.PARENT_ID.eq(parentId))).
            map(CategoryRecord.TO_CATEGORY);

which is sufficiently awesome that I think it merits taking these liberties.
Plus it opens the door to adding other transformations that one might want to
do with a collection just loaded from the database.
This commit is contained in:
Michael Bayne
2009-07-09 20:02:00 +00:00
parent 4c697b06a4
commit 65f4c8dff4
5 changed files with 108 additions and 29 deletions
@@ -264,7 +264,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<T> loadAll ( protected <T extends PersistentRecord> XList<T> loadAll (
Class<T> type, Collection<? extends Comparable<?>> primaryKeys) Class<T> type, Collection<? extends Comparable<?>> primaryKeys)
throws DatabaseException throws DatabaseException
{ {
@@ -282,10 +282,10 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<T> loadAll (Collection<Key<T>> keys) protected <T extends PersistentRecord> XList<T> loadAll (Collection<Key<T>> keys)
throws DatabaseException throws DatabaseException
{ {
return (keys.size() == 0) ? Collections.<T>emptyList() : return (keys.size() == 0) ? new XArrayList<T>() :
_ctx.invoke(new FindAllQuery.WithKeys<T>(_ctx, keys)); _ctx.invoke(new FindAllQuery.WithKeys<T>(_ctx, keys));
} }
@@ -294,7 +294,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<T> findAll (Class<T> type, QueryClause... clauses) protected <T extends PersistentRecord> XList<T> findAll (Class<T> type, QueryClause... clauses)
throws DatabaseException throws DatabaseException
{ {
return findAll(type, Arrays.asList(clauses)); return findAll(type, Arrays.asList(clauses));
@@ -313,7 +313,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<T> findAll ( protected <T extends PersistentRecord> XList<T> findAll (
Class<T> type, Collection<? extends QueryClause> clauses) Class<T> type, Collection<? extends QueryClause> clauses)
throws DatabaseException throws DatabaseException
{ {
@@ -325,7 +325,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<T> findAll ( protected <T extends PersistentRecord> XList<T> findAll (
Class<T> type, CacheStrategy strategy, QueryClause... clauses) Class<T> type, CacheStrategy strategy, QueryClause... clauses)
throws DatabaseException throws DatabaseException
{ {
@@ -337,7 +337,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<T> findAll ( protected <T extends PersistentRecord> XList<T> findAll (
Class<T> type, CacheStrategy cache, Collection<? extends QueryClause> clauses) Class<T> type, CacheStrategy cache, Collection<? extends QueryClause> clauses)
throws DatabaseException throws DatabaseException
{ {
@@ -395,7 +395,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<Key<T>> findAllKeys ( protected <T extends PersistentRecord> XList<Key<T>> findAllKeys (
Class<T> type, boolean forUpdate, QueryClause... clause) Class<T> type, boolean forUpdate, QueryClause... clause)
throws DatabaseException throws DatabaseException
{ {
@@ -413,7 +413,7 @@ public abstract class DepotRepository
* *
* @throws DatabaseException if any problem is encountered communicating with the database. * @throws DatabaseException if any problem is encountered communicating with the database.
*/ */
protected <T extends PersistentRecord> List<Key<T>> findAllKeys ( protected <T extends PersistentRecord> XList<Key<T>> findAllKeys (
Class<T> type, boolean forUpdate, Collection<? extends QueryClause> clauses) Class<T> type, boolean forUpdate, Collection<? extends QueryClause> clauses)
throws DatabaseException throws DatabaseException
{ {
@@ -0,0 +1,40 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2009 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;
import java.util.ArrayList;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
/**
* An array list specialization that implements {@link XList}. Depot returns this list from all of
* its methods to make it easy for callers to map the results to runtime records as desired.
*/
public class XArrayList<T> extends ArrayList<T>
implements XList<T>
{
// from interface XList<T>
public <R> Iterable<R> map (Function<T, R> mapper)
{
return Iterables.transform(this, mapper);
}
}
+38
View File
@@ -0,0 +1,38 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2009 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;
import java.util.List;
import com.google.common.base.Function;
/**
* Extends the {@link List} interface with a method {@link #map} that makes it easy to convert the
* contents of the list to an {@link Iterable} of a different type via the application of a {@link
* Function}.
*/
public interface XList<T> extends List<T>
{
/**
* Returns an iterable over a mapping of this list via the specified mapping function.
*/
public <R> Iterable<R> map (Function<T, R> mapper);
}
@@ -21,15 +21,12 @@
package com.samskivert.depot.impl; package com.samskivert.depot.impl;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import com.google.common.collect.Lists;
import com.samskivert.jdbc.DatabaseLiaison; import com.samskivert.jdbc.DatabaseLiaison;
import com.samskivert.jdbc.JDBCUtil; import com.samskivert.jdbc.JDBCUtil;
@@ -38,6 +35,8 @@ import com.samskivert.depot.Key;
import com.samskivert.depot.PersistenceContext; import com.samskivert.depot.PersistenceContext;
import com.samskivert.depot.PersistentRecord; import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.Stats; import com.samskivert.depot.Stats;
import com.samskivert.depot.XArrayList;
import com.samskivert.depot.XList;
import com.samskivert.depot.clause.QueryClause; import com.samskivert.depot.clause.QueryClause;
import com.samskivert.depot.clause.SelectClause; import com.samskivert.depot.clause.SelectClause;
@@ -46,7 +45,7 @@ import static com.samskivert.depot.Log.log;
/** /**
* Loads all primary keys for the records matching the supplied clause. * Loads all primary keys for the records matching the supplied clause.
*/ */
public class FindAllKeysQuery<T extends PersistentRecord> extends Query<List<Key<T>>> public class FindAllKeysQuery<T extends PersistentRecord> extends Query<XList<Key<T>>>
{ {
public FindAllKeysQuery (PersistenceContext ctx, Class<T> type, boolean forUpdate, public FindAllKeysQuery (PersistenceContext ctx, Class<T> type, boolean forUpdate,
Collection<? extends QueryClause> clauses) Collection<? extends QueryClause> clauses)
@@ -66,16 +65,16 @@ public class FindAllKeysQuery<T extends PersistentRecord> extends Query<List<Key
} }
@Override // from Query @Override // from Query
public List<Key<T>> getCachedResult (PersistenceContext ctx) public XList<Key<T>> getCachedResult (PersistenceContext ctx)
{ {
return null; // TODO return null; // TODO
} }
// from Query // from Query
public List<Key<T>> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) public XList<Key<T>> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException throws SQLException
{ {
List<Key<T>> keys = Lists.newArrayList(); XList<Key<T>> keys = new XArrayList<Key<T>>();
PreparedStatement stmt = _builder.prepare(conn); PreparedStatement stmt = _builder.prepare(conn);
try { try {
ResultSet rs = stmt.executeQuery(); ResultSet rs = stmt.executeQuery();
@@ -48,6 +48,8 @@ import com.samskivert.depot.PersistenceContext;
import com.samskivert.depot.PersistentRecord; import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.SimpleCacheKey; import com.samskivert.depot.SimpleCacheKey;
import com.samskivert.depot.Stats; import com.samskivert.depot.Stats;
import com.samskivert.depot.XArrayList;
import com.samskivert.depot.XList;
import com.samskivert.depot.clause.FieldOverride; import com.samskivert.depot.clause.FieldOverride;
import com.samskivert.depot.clause.QueryClause; import com.samskivert.depot.clause.QueryClause;
import com.samskivert.depot.clause.SelectClause; import com.samskivert.depot.clause.SelectClause;
@@ -59,7 +61,7 @@ import static com.samskivert.depot.Log.log;
* This class implements the functionality required by {@link DepotRepository#findAll}: fetch * This class implements the functionality required by {@link DepotRepository#findAll}: fetch
* a collection of persistent objects using one of two included strategies. * a collection of persistent objects using one of two included strategies.
*/ */
public abstract class FindAllQuery<T extends PersistentRecord> extends Query<List<T>> public abstract class FindAllQuery<T extends PersistentRecord> extends Query<XList<T>>
{ {
/** /**
* The two-pass collection query implementation. See {@link DepotRepository#findAll} for * The two-pass collection query implementation. See {@link DepotRepository#findAll} for
@@ -103,7 +105,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
} }
@Override // from Query @Override // from Query
public List<T> getCachedResult (PersistenceContext ctx) public XList<T> getCachedResult (PersistenceContext ctx)
{ {
if (_qkey == null) { if (_qkey == null) {
return null; return null;
@@ -118,7 +120,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
} }
// from Query // from Query
public List<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) public XList<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException throws SQLException
{ {
// we want this to remain null if our key set came from the cache // we want this to remain null if our key set came from the cache
@@ -179,7 +181,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
} }
@Override // from Query @Override // from Query
public List<T> getCachedResult (PersistenceContext ctx) public XList<T> getCachedResult (PersistenceContext ctx)
{ {
// look up what we can from the cache // look up what we can from the cache
_fetchKeys = loadFromCache(ctx, _keys, _entities); _fetchKeys = loadFromCache(ctx, _keys, _entities);
@@ -189,7 +191,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
} }
// from Query // from Query
public List<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) public XList<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException throws SQLException
{ {
return loadAndResolve(ctx, conn, _keys, _fetchKeys, _entities, null); return loadAndResolve(ctx, conn, _keys, _fetchKeys, _entities, null);
@@ -222,7 +224,7 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
} }
@Override // from Query @Override // from Query
public List<T> getCachedResult (PersistenceContext ctx) public XList<T> getCachedResult (PersistenceContext ctx)
{ {
if (_qkey != null) { if (_qkey != null) {
_cachedQueries++; _cachedQueries++;
@@ -232,10 +234,10 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
} }
// from Query // from Query
public List<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) public XList<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException throws SQLException
{ {
List<T> result = Lists.newArrayList(); XList<T> result = new XArrayList<T>();
SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select)); SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
builder.newQuery(_select); builder.newQuery(_select);
PreparedStatement stmt = builder.prepare(conn); PreparedStatement stmt = builder.prepare(conn);
@@ -297,9 +299,9 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
return fetchKeys; return fetchKeys;
} }
protected List<T> resolve (Iterable<Key<T>> allKeys, Map<Key<T>, T> entities) protected XList<T> resolve (Iterable<Key<T>> allKeys, Map<Key<T>, T> entities)
{ {
List<T> result = Lists.newArrayList(); XList<T> result = new XArrayList<T>();
for (Key<T> key : allKeys) { for (Key<T> key : allKeys) {
T value = entities.get(key); T value = entities.get(key);
if (value != null) { if (value != null) {
@@ -309,9 +311,9 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<Lis
return result; return result;
} }
protected List<T> loadAndResolve (PersistenceContext ctx, Connection conn, protected XList<T> loadAndResolve (PersistenceContext ctx, Connection conn,
Iterable<Key<T>> allKeys, Set<Key<T>> fetchKeys, Iterable<Key<T>> allKeys, Set<Key<T>> fetchKeys,
Map<Key<T>, T> entities, String origStmt) Map<Key<T>, T> entities, String origStmt)
throws SQLException throws SQLException
{ {
if (PersistenceContext.CACHE_DEBUG && fetchKeys.size() > 0) { if (PersistenceContext.CACHE_DEBUG && fetchKeys.size() > 0) {