You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RowFilter.java 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. Copyright (c) 2008 Health Market Science, Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package com.healthmarketscience.jackcess.util;
  14. import java.util.Iterator;
  15. import java.util.Map;
  16. import java.util.NoSuchElementException;
  17. import java.util.Objects;
  18. import com.healthmarketscience.jackcess.Column;
  19. import com.healthmarketscience.jackcess.Row;
  20. /**
  21. * The RowFilter class encapsulates a filter test for a table row. This can
  22. * be used by the {@link #apply(Iterable)} method to create an Iterable over a
  23. * table which returns only rows matching some criteria.
  24. *
  25. * @author Patricia Donaldson, Xerox Corporation
  26. * @usage _general_class_
  27. */
  28. public abstract class RowFilter
  29. {
  30. /**
  31. * Returns {@code true} if the given table row matches the Filter criteria,
  32. * {@code false} otherwise.
  33. * @param row current row to test for inclusion in the filter
  34. */
  35. public abstract boolean matches(Row row);
  36. /**
  37. * Returns an iterable which filters the given iterable based on this
  38. * filter.
  39. *
  40. * @param iterable row iterable to filter
  41. *
  42. * @return a filtering iterable
  43. */
  44. public Iterable<Row> apply(Iterable<? extends Row> iterable)
  45. {
  46. return new FilterIterable(iterable);
  47. }
  48. /**
  49. * Creates a filter based on a row pattern.
  50. *
  51. * @param rowPattern Map from column names to the values to be matched.
  52. * A table row will match the target if
  53. * {@code Objects.equals(rowPattern.get(s), row.get(s))}
  54. * for all column names in the pattern map.
  55. * @return a filter which matches table rows which match the values in the
  56. * row pattern
  57. */
  58. public static RowFilter matchPattern(final Map<String,?> rowPattern)
  59. {
  60. return new RowFilter() {
  61. @Override
  62. public boolean matches(Row row)
  63. {
  64. for(Map.Entry<String,?> e : rowPattern.entrySet()) {
  65. if(!Objects.equals(e.getValue(), row.get(e.getKey()))) {
  66. return false;
  67. }
  68. }
  69. return true;
  70. }
  71. };
  72. }
  73. /**
  74. * Creates a filter based on a single value row pattern.
  75. *
  76. * @param columnPattern column to be matched
  77. * @param valuePattern value to be matched.
  78. * A table row will match the target if
  79. * {@code Objects.equals(valuePattern, row.get(columnPattern.getName()))}.
  80. * @return a filter which matches table rows which match the value in the
  81. * row pattern
  82. */
  83. public static RowFilter matchPattern(final Column columnPattern,
  84. final Object valuePattern)
  85. {
  86. return new RowFilter() {
  87. @Override
  88. public boolean matches(Row row)
  89. {
  90. return Objects.equals(valuePattern, columnPattern.getRowValue(row));
  91. }
  92. };
  93. }
  94. /**
  95. * Creates a filter which inverts the sense of the given filter (rows which
  96. * are matched by the given filter will not be matched by the returned
  97. * filter, and vice versa).
  98. *
  99. * @param filter filter which to invert
  100. *
  101. * @return a RowFilter which matches rows not matched by the given filter
  102. */
  103. public static RowFilter invert(final RowFilter filter)
  104. {
  105. return new RowFilter() {
  106. @Override
  107. public boolean matches(Row row)
  108. {
  109. return !filter.matches(row);
  110. }
  111. };
  112. }
  113. /**
  114. * Returns an iterable which filters the given iterable based on the given
  115. * rowFilter.
  116. *
  117. * @param rowFilter the filter criteria, may be {@code null}
  118. * @param iterable row iterable to filter
  119. *
  120. * @return a filtering iterable (or the given iterable if a {@code null}
  121. * filter was given)
  122. */
  123. @SuppressWarnings("unchecked")
  124. public static Iterable<Row> apply(RowFilter rowFilter,
  125. Iterable<? extends Row> iterable)
  126. {
  127. return((rowFilter != null) ? rowFilter.apply(iterable) :
  128. (Iterable<Row>)iterable);
  129. }
  130. /**
  131. * Iterable which creates a filtered view of a another row iterable.
  132. */
  133. private class FilterIterable implements Iterable<Row>
  134. {
  135. private final Iterable<? extends Row> _iterable;
  136. private FilterIterable(Iterable<? extends Row> iterable)
  137. {
  138. _iterable = iterable;
  139. }
  140. /**
  141. * Returns an iterator which iterates through the rows of the underlying
  142. * iterable, returning only rows for which the {@link RowFilter#matches}
  143. * method returns {@code true}
  144. */
  145. @Override
  146. public Iterator<Row> iterator()
  147. {
  148. return new Iterator<Row>() {
  149. private final Iterator<? extends Row> _iter = _iterable.iterator();
  150. private Row _next;
  151. @Override
  152. public boolean hasNext() {
  153. while(_iter.hasNext()) {
  154. _next = _iter.next();
  155. if(RowFilter.this.matches(_next)) {
  156. return true;
  157. }
  158. }
  159. _next = null;
  160. return false;
  161. }
  162. @Override
  163. public Row next() {
  164. if(_next == null) {
  165. throw new NoSuchElementException();
  166. }
  167. return _next;
  168. }
  169. @Override
  170. public void remove() {
  171. throw new UnsupportedOperationException();
  172. }
  173. };
  174. }
  175. }
  176. }