Changeset 7018


Ignore:
Timestamp:
Nov 18, 2015, 1:57:20 PM (7 years ago)
Author:
Nicklas Nordborg
Message:

Fixes #1968: Add support for filtering on more columns in the trashcan

The ConditionalQueryElement provides the support we need for selectively enable/disable a restriction based on the return type of the query. This means that a single restriction can be used to filter on 'name' for nameable items while staying out of the way (1=1) for other items.

All columns in the trashcan should now provide a filtering functionality. Also added 'Shared to' column.

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/core/net/sf/basedb/core/Trashcan.java

    r7017 r7018  
    2626import net.sf.basedb.core.data.BasicData;
    2727import net.sf.basedb.core.data.RemovableData;
     28import net.sf.basedb.core.query.Hql;
     29import net.sf.basedb.core.query.Restriction;
     30import net.sf.basedb.core.query.Restrictions;
    2831import net.sf.basedb.core.query.ResultList;
    2932import net.sf.basedb.core.signal.ThreadSignalHandler;
     33import net.sf.basedb.util.filter.Filter;
    3034
    3135import java.util.ArrayList;
     
    5963
    6064  /**
    61     @see #getItems(DbControl, Set, int, int)
     65    @see #getItems(DbControl, Set, int, int, Restriction)
    6266  */
    6367  public static ResultList<Removable> getItems(DbControl dc, Item itemType, int firstItem, int maxItems)
     
    6569  {
    6670    return getItems(dc, itemType == null ? null : Collections.singleton(itemType),
    67       firstItem, maxItems);
    68   }
    69 
    70   /**
    71     Load all items flagged for deletion that are owned by the logged in user.
     71      firstItem, maxItems, null);
     72  }
     73
     74  /**
     75    @see #getItems(DbControl, Set, int, int, Restriction)
     76  */
     77  public static ResultList<Removable> getItems(DbControl dc, Set<Item> itemTypes,
     78    int firstItem, int maxItems)
     79    throws BaseException
     80  {
     81    return getItems(dc, itemTypes, firstItem, maxItems, null);
     82  }
     83
     84  /**
     85    Load all items flagged for deletion that are owned by or removed
     86    by the logged in user. A restriction may be specified to limit the
     87    returned items. Note that separate queries are used for each item type
     88    but the same restriction is applied to all of them. It is recommended
     89    that the restriction is created with {@link
     90    Restrictions#conditionalRestriction(Filter, Restriction, Restriction)}
     91    so that a restriction on, for example, the 'name' is only applied
     92    to {@link Nameable} items.
    7293
    7394    @param dc The <code>DbControl</code> to use for database access
     
    7697    @param firstItem The index of the first item to return (0-based)
    7798    @param maxItems The maximum number of items to return, or 0 to return all items
     99    @param restriction A restriction to apply when loading items
    78100    @return A list containing removable items
    79101    @throws BaseException If there is an error of some kind
    80     @since 2.7.1
     102    @since 3.7
    81103  */
    82104  public static ResultList<Removable> getItems(DbControl dc, Set<Item> itemTypes,
    83     int firstItem, int maxItems)
     105    int firstItem, int maxItems, Restriction restriction)
    84106    throws BaseException
    85107  {
     
    95117      filter.setParameter("user", sc.getLoggedInUserId());
    96118      List<RemovableData> removed = new ArrayList<RemovableData>();
     119      Restriction isRemoved = Restrictions.neq(Hql.property("removedBy"), null);
     120     
    97121      for (Item item : itemTypes)
    98122      {
    99123        if (RemovableData.class.isAssignableFrom(item.getDataClass()))
    100124        {
    101           org.hibernate.Query query = HibernateUtil.createQuery(session,
    102             "SELECT trash FROM " + item.getDataClass().getName() + " trash " +
    103             "WHERE NOT trash.removedBy IS NULL");
    104           removed.addAll(HibernateUtil.loadList(RemovableData.class, query, sc));
     125          // Query to load all "removed" items of a specific item type
     126          AbstractEntityQuery hql = new AbstractEntityQuery(item, null, false){};
     127          hql.restrict(isRemoved);
     128          if (restriction != null) hql.restrict(restriction);
     129          removed.addAll(HibernateUtil.loadList(RemovableData.class, hql.getMainHqlQuery(dc), sc));
    105130        }
    106131      }
  • trunk/src/core/net/sf/basedb/core/query/Expressions.java

    r6898 r7018  
    2828import net.sf.basedb.core.NumberOutOfRangeException;
    2929import net.sf.basedb.util.MD5;
     30import net.sf.basedb.util.filter.Filter;
    3031
    3132import java.util.regex.Pattern;
     
    455456 
    456457  /**
     458    Create an expression that falls back to one of two expression
     459    depending on if the query passes a filter or not.
     460   
     461    @param filter A filter, if null the 'ifTrue' expression is returned
     462    @param ifTrue The epxression to use if the filter evaluates to TRUE
     463    @param ifFalse The expression to use if the filter evaluates to FALSE
     464    @return A conditional expression, or the 'ifTrue' expression if the filter is null, or
     465      null if both expressions are null
     466    @since 3.7
     467  */
     468  @SuppressWarnings("unchecked")
     469  public static Expression conditionalRestriction(Filter<? extends Query> filter, Expression ifTrue, Expression ifFalse)
     470  {
     471    if (filter == null || (ifTrue == null && ifFalse == null)) return ifTrue;
     472    return new ConditionalQueryElement((Filter<Query>)filter, ifTrue, ifFalse);
     473  }
     474 
     475  /**
    457476    Test if there is null in the array.
    458477    @return The index of the first null element,
  • trunk/src/core/net/sf/basedb/core/query/Restrictions.java

    r6880 r7018  
    2626import net.sf.basedb.core.InvalidDataException;
    2727import net.sf.basedb.core.InvalidUseOfNullException;
     28import net.sf.basedb.util.filter.Filter;
    2829
    2930import java.util.ArrayList;
     
    458459 
    459460  /**
     461    Create a restriction that falls back to one of two restrictions
     462    depending on if the query passes a filter or not. A typical use
     463    case is to apply a restriction depending on the return type of
     464    the query. This method will allow "null" restrictions but they
     465    are converted to "1=1" (or similar that doesn't limit the result).
     466   
     467    @param filter A filter, if null the 'ifTrue' restriction is returned
     468    @param ifTrue The restriction to apply if the filter evaluates to TRUE, or null to not apply
     469      any restriction in this case
     470    @param ifFalse The restriction to apply if the filter evaluates to FALSE, or null to not apply
     471      any restriction in this case
     472    @return A conditional restriction, or the 'ifTrue' restriction if the filter is null, or
     473      null if both restrictions are null
     474    @since 3.7
     475  */
     476  @SuppressWarnings("unchecked")
     477  public static Restriction conditionalRestriction(Filter<? extends Query> filter, Restriction ifTrue, Restriction ifFalse)
     478  {
     479    if (filter == null || (ifTrue == null && ifFalse == null)) return ifTrue;
     480   
     481    if (ifTrue == null) ifTrue = Restrictions.eq(Expressions.integer(1), Expressions.integer(1));
     482    if (ifFalse == null) ifFalse = Restrictions.eq(Expressions.integer(1), Expressions.integer(1));
     483    return new ConditionalQueryElement((Filter<Query>)filter, ifTrue, ifFalse);
     484  }
     485 
     486  /**
    460487    Test if there is null in the array.
    461488    @return The index of the first null element,
  • trunk/www/views/trashcan/list_trash.jsp

    r7016 r7018  
    3535  import="net.sf.basedb.core.Nameable"
    3636  import="net.sf.basedb.core.Ownable"
     37  import="net.sf.basedb.core.Shareable"
     38  import="net.sf.basedb.core.SharedItem"
    3739  import="net.sf.basedb.core.File"
    3840  import="net.sf.basedb.core.Directory"
     
    4143  import="net.sf.basedb.core.ItemNotFoundException"
    4244  import="net.sf.basedb.core.PermissionDeniedException"
     45  import="net.sf.basedb.core.ItemQuery"
     46  import="net.sf.basedb.core.query.EntityQuery"
    4347  import="net.sf.basedb.core.query.ResultList"
     48  import="net.sf.basedb.core.query.Restriction"
     49  import="net.sf.basedb.core.query.Restrictions"
    4450  import="net.sf.basedb.util.Enumeration"
     51  import="net.sf.basedb.util.ShareableUtil"
     52  import="net.sf.basedb.util.filter.Filter"
    4553  import="net.sf.basedb.clients.web.Base"
    4654  import="net.sf.basedb.clients.web.util.HTML"
     
    5260  import="net.sf.basedb.clients.web.extensions.list.ListColumnUtil"
    5361  import="net.sf.basedb.util.extensions.ExtensionsInvoker"
     62  import="java.util.Iterator"
    5463  import="java.util.Set"
    5564  import="java.util.HashSet"
     
    7079    }
    7180  }
     81 
     82  static class ReturnClassFilter
     83    implements Filter<EntityQuery>
     84  {
     85    private final Class<?> returnClass;
     86    ReturnClassFilter(Class<?> returnClass)
     87    {
     88      this.returnClass = returnClass;
     89    }
     90   
     91    public boolean evaluate(EntityQuery query)
     92    {
     93      return returnClass.isAssignableFrom(query.getItemType().getItemClass());
     94    }
     95  }
    7296%>
    7397<%
     
    81105{
    82106  long totalCount = 0;
     107  final ItemQuery<User> userQuery = User.getQuery();
    83108  try
    84109  {
     
    93118      }
    94119    }
    95     trash = Trashcan.getItems(dc, itemTypes, cc.getPage() * cc.getRowsPerPage(), cc.getRowsPerPage());
     120    Restriction id = cc.getFilterRestriction("id", dc, null);
     121    Restriction removedBy = cc.getFilterRestriction("removedBy", dc, null);
     122    Restriction name = Restrictions.conditionalRestriction(new ReturnClassFilter(Nameable.class),
     123        cc.getFilterRestriction("name", dc, null), null);
     124    Restriction description = Restrictions.conditionalRestriction(new ReturnClassFilter(Nameable.class),
     125        cc.getFilterRestriction("description", dc, null), null);
     126    Restriction owner = Restrictions.conditionalRestriction(new ReturnClassFilter(Ownable.class),
     127        cc.getFilterRestriction("owner", dc, null), null);
     128    Restriction sharedTo = Restrictions.conditionalRestriction(new ReturnClassFilter(Shareable.class),
     129        cc.getFilterRestriction("!sharedTo.name", dc, null), null);
     130    Restriction restriction = Restrictions.nullSafeAnd(id, removedBy, name, description, owner, sharedTo);
     131
     132    trash = Trashcan.getItems(dc, itemTypes, cc.getPage() * cc.getRowsPerPage(), cc.getRowsPerPage(), restriction);
    96133    totalCount = trash.getTotalCount();
    97134  }
     
    139176        title="Name"
    140177        show="always"
     178        filterable="true"
     179        filterproperty="name"
     180        datatype="string"
    141181      />
    142182      <tbl:columndef
     
    146186        title="ID"
    147187        exportable="true"
    148       />
     188        filterable="true"
     189      />
     190      <%
     191      Enumeration<String, String> users = new Enumeration<String, String>();
     192      for (User u : userQuery.list(dc))
     193      {
     194        users.add(Integer.toString(u.getId()), HTML.encodeTags(u.getName()));
     195      }
     196      %>
    149197      <tbl:columndef
    150198        id="owner"
    151199        title="Owner"
     200        property="owner"
     201        datatype="int"
     202        filterable="true"
     203        enumeration="<%=users%>"
    152204      />
    153205      <tbl:columndef
    154206        id="removedBy"
    155207        title="Removed by"
     208        property="removedBy"
     209        datatype="int"
     210        filterable="true"
     211        enumeration="<%=users%>"
    156212      />
    157213      <tbl:columndef
    158214        id="description"
    159215        title="Description"
     216        property="description"
     217        filterable="true"
     218        datatype="string"
     219      />
     220      <tbl:columndef
     221        id="sharedTo"
     222        title="Shared to"
     223        filterable="true"
     224        filterproperty="!sharedTo.name"
     225        datatype="string"
    160226      />
    161227      <tbl:columndef
     
    330396                  }
    331397                  %></tbl:cell>
     398                <tbl:cell column="sharedTo"><%
     399                  if (item instanceof SharedItem)
     400                  {
     401                    Iterator<Nameable> sharees = ShareableUtil.getSharedTo(dc, (SharedItem)item).iterator();
     402                    while(sharees.hasNext())
     403                    {
     404                      Nameable n = sharees.next();
     405                      out.write(Base.getLinkedName(ID, n, false, true));
     406                      out.write(sharees.hasNext() ? ", " : "");
     407                    }
     408                  }
     409                  %></tbl:cell>
    332410                <tbl:cell column="description"><%=HTML.encodeTags(description)%></tbl:cell>
    333411                <tbl:xt-cells dc="<%=dc%>" item="<%=item%>">
Note: See TracChangeset for help on using the changeset viewer.