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 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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 java.util.function.Predicate;
  19. import java.util.stream.Stream;
  20. import java.util.stream.StreamSupport;
  21. import com.healthmarketscience.jackcess.Column;
  22. import com.healthmarketscience.jackcess.Row;
  23. /**
  24. * The RowFilter class encapsulates a filter test for a table row. This can
  25. * be used by the {@link #apply(Iterable)} method to create an Iterable over a
  26. * table which returns only rows matching some criteria.
  27. *
  28. * @author Patricia Donaldson, Xerox Corporation
  29. * @usage _general_class_
  30. */
  31. public abstract class RowFilter implements Predicate<Row>
  32. {
  33. /**
  34. * Returns {@code true} if the given table row matches the Filter criteria,
  35. * {@code false} otherwise.
  36. * @param row current row to test for inclusion in the filter
  37. */
  38. public abstract boolean matches(Row row);
  39. /**
  40. * Adaptation of this class for {@link Predicate} support. Uses the
  41. * {@link #matches} method.
  42. */
  43. @Override
  44. public boolean test(Row row) {
  45. return matches(row);
  46. }
  47. /**
  48. * Returns an iterable which filters the given iterable based on this
  49. * filter.
  50. *
  51. * @param iterable row iterable to filter
  52. *
  53. * @return a filtering iterable
  54. */
  55. public Iterable<Row> apply(Iterable<? extends Row> iterable)
  56. {
  57. return new FilterIterable(iterable);
  58. }
  59. /**
  60. * Convenience method to apply this filter to the given iterable and return
  61. * it as a Stream.
  62. */
  63. public Stream<Row> filter(Iterable<? extends Row> iterable) {
  64. return StreamSupport.stream(
  65. new FilterIterable(iterable).spliterator(), false)
  66. .filter(this);
  67. }
  68. /**
  69. * Creates a filter based on a row pattern.
  70. *
  71. * @param rowPattern Map from column names to the values to be matched.
  72. * A table row will match the target if
  73. * {@code Objects.equals(rowPattern.get(s), row.get(s))}
  74. * for all column names in the pattern map.
  75. * @return a filter which matches table rows which match the values in the
  76. * row pattern
  77. */
  78. public static RowFilter matchPattern(final Map<String,?> rowPattern)
  79. {
  80. return new RowFilter() {
  81. @Override
  82. public boolean matches(Row row)
  83. {
  84. for(Map.Entry<String,?> e : rowPattern.entrySet()) {
  85. if(!Objects.equals(e.getValue(), row.get(e.getKey()))) {
  86. return false;
  87. }
  88. }
  89. return true;
  90. }
  91. };
  92. }
  93. /**
  94. * Creates a filter based on a single value row pattern.
  95. *
  96. * @param columnPattern column to be matched
  97. * @param valuePattern value to be matched.
  98. * A table row will match the target if
  99. * {@code Objects.equals(valuePattern, row.get(columnPattern.getName()))}.
  100. * @return a filter which matches table rows which match the value in the
  101. * row pattern
  102. */
  103. public static RowFilter matchPattern(final Column columnPattern,
  104. final Object valuePattern)
  105. {
  106. return new RowFilter() {
  107. @Override
  108. public boolean matches(Row row)
  109. {
  110. return Objects.equals(valuePattern, columnPattern.getRowValue(row));
  111. }
  112. };
  113. }
  114. /**
  115. * Creates a filter which inverts the sense of the given filter (rows which
  116. * are matched by the given filter will not be matched by the returned
  117. * filter, and vice versa).
  118. *
  119. * @param filter filter which to invert
  120. *
  121. * @return a RowFilter which matches rows not matched by the given filter
  122. */
  123. public static RowFilter invert(final RowFilter filter)
  124. {
  125. return new RowFilter() {
  126. @Override
  127. public boolean matches(Row row)
  128. {
  129. return !filter.matches(row);
  130. }
  131. };
  132. }
  133. /**
  134. * Returns an iterable which filters the given iterable based on the given
  135. * rowFilter.
  136. *
  137. * @param rowFilter the filter criteria, may be {@code null}
  138. * @param iterable row iterable to filter
  139. *
  140. * @return a filtering iterable (or the given iterable if a {@code null}
  141. * filter was given)
  142. */
  143. @SuppressWarnings("unchecked")
  144. public static Iterable<Row> apply(RowFilter rowFilter,
  145. Iterable<? extends Row> iterable)
  146. {
  147. return((rowFilter != null) ? rowFilter.apply(iterable) :
  148. (Iterable<Row>)iterable);
  149. }
  150. /**
  151. * Iterable which creates a filtered view of a another row iterable.
  152. */
  153. private class FilterIterable implements Iterable<Row>
  154. {
  155. private final Iterable<? extends Row> _iterable;
  156. private FilterIterable(Iterable<? extends Row> iterable)
  157. {
  158. _iterable = iterable;
  159. }
  160. /**
  161. * Returns an iterator which iterates through the rows of the underlying
  162. * iterable, returning only rows for which the {@link RowFilter#matches}
  163. * method returns {@code true}
  164. */
  165. @Override
  166. public Iterator<Row> iterator()
  167. {
  168. return new Iterator<Row>() {
  169. private final Iterator<? extends Row> _iter = _iterable.iterator();
  170. private Row _next;
  171. @Override
  172. public boolean hasNext() {
  173. while(_iter.hasNext()) {
  174. _next = _iter.next();
  175. if(RowFilter.this.matches(_next)) {
  176. return true;
  177. }
  178. }
  179. _next = null;
  180. return false;
  181. }
  182. @Override
  183. public Row next() {
  184. if(_next == null) {
  185. throw new NoSuchElementException();
  186. }
  187. return _next;
  188. }
  189. };
  190. }
  191. }
  192. }