name:
src/main/java/io/protobase/f7/models/CellQuery.java
-rw-r--r--
5383
1package io.protobase.f7.models;
2
3import com.google.common.base.MoreObjects;
4import com.google.common.collect.Range;
5import io.protobase.f7.errors.ValueException;
6import io.protobase.f7.utils.AlphaUtils;
7
8import java.util.Objects;
9import java.util.Optional;
10
11/**
12 * A range query represents a query of one or more cells over a single grid. It is composed of two dimensional ranges:
13 * rows and columns, both of which can be unbounded at the lower, or upper ends of the range.
14 */
15public class CellQuery extends BaseObject {
16 /**
17 * Name of the grid being queried.
18 */
19 private String grid;
20 /**
21 * Range of columns.
22 */
23 private Range<Integer> columns;
24 /**
25 * Range of rows.
26 */
27 private Range<Integer> rows;
28
29 public CellQuery(String grid, Range<Integer> columns, Range<Integer> rows) {
30 this.grid = grid;
31 this.columns = columns;
32 this.rows = rows;
33 }
34
35 public static Builder builder() {
36 return new Builder();
37 }
38
39 public static Builder builder(CellQuery query) {
40 return new Builder(query);
41 }
42
43 public Optional<String> getGrid() {
44 return Optional.ofNullable(grid);
45 }
46
47 public Integer getStartColumn() {
48 return columns.lowerEndpoint();
49 }
50
51 public Integer getEndColumn() {
52 return columns.upperEndpoint();
53 }
54
55 public Integer getStartRow() {
56 return rows.lowerEndpoint();
57 }
58
59 public Integer getEndRow() {
60 return rows.upperEndpoint();
61 }
62
63 /**
64 * Does this query intersect with the other one?
65 *
66 * @param other - other query.
67 * @return true if at least one cell overlaps.
68 */
69 public boolean intersects(CellQuery other) {
70 return other.columns.isConnected(this.columns) && other.rows.isConnected(this.rows);
71 }
72
73 /**
74 * Bound this query using an upper column and upper row. Will default to the lower of the upper column passed in,
75 * and the upper column bound existing on the columns range. Same for rows.
76 *
77 * @param upperColumn - upper endpoint for columns to default to.
78 * @param upperRow - upper endpoint of rows to default to.
79 * @return bounded query.
80 */
81 public CellQuery toBounded(int upperColumn, int upperRow) {
82 if (!Range.closed(0, upperColumn).isConnected(columns) && !Range.closed(0, upperRow).isConnected(rows)) {
83 return this;
84 }
85 return CellQuery.builder(this)
86 .columnsBetween(this.columns.lowerEndpoint(),
87 Math.min(upperColumn, columns.hasUpperBound() ? columns.upperEndpoint() : upperColumn))
88 .rowsBetween(this.rows.lowerEndpoint(),
89 Math.min(upperRow, rows.hasUpperBound() ? rows.upperEndpoint() : upperRow))
90 .build();
91 }
92
93 @Override
94 public Object[] significantAttributes() {
95 return new Object[]{
96 grid,
97 columns,
98 rows
99 };
100 }
101
102 @Override
103 public String toString() {
104 return MoreObjects.toStringHelper(this)
105 .add("grid", grid)
106 .add("columns", columns)
107 .add("rows", rows)
108 .toString();
109 }
110
111 public static class Builder {
112 private String gridName;
113 private Range<Integer> columns;
114 private Range<Integer> rows;
115
116 public Builder() {
117 }
118
119 public Builder(CellQuery query) {
120 this.gridName = query.grid;
121 this.columns = query.columns;
122 this.rows = query.rows;
123 }
124
125 public Builder grid(String gridName) {
126 this.gridName = gridName;
127 return this;
128 }
129
130 public Builder columnsBetween(String low, String high) {
131 columns = Range.closed(AlphaUtils.columnToInt(low), AlphaUtils.columnToInt(high));
132 return this;
133 }
134
135 public Builder columnsBetween(int low, int high) {
136 columns = Range.closed(low, high);
137 return this;
138 }
139
140 public Builder rowsBetween(String low, String high) {
141 rows = Range.closed(Integer.parseInt(low) - 1, Integer.parseInt(high) - 1);
142 return this;
143 }
144
145 public Builder rowsBetween(int low, int high) {
146 rows = Range.closed(low, high);
147 return this;
148 }
149
150 public Builder openColumnsStartingAt(String startColumn) {
151 columns = Range.atLeast(AlphaUtils.columnToInt(startColumn));
152 return this;
153 }
154
155 public Builder openColumnsStartingAt(int startColumn) {
156 columns = Range.atLeast(startColumn);
157 return this;
158 }
159
160 public Builder openColumnsStartingAtZero() {
161 columns = Range.atLeast(0);
162 return this;
163 }
164
165 public Builder openRowsStartingAt(String startRow) {
166 rows = Range.atLeast(Integer.parseInt(startRow) - 1);
167 return this;
168 }
169
170 public Builder openRowsStartingAt(int startRow) {
171 rows = Range.atLeast(startRow);
172 return this;
173 }
174
175 public Builder openRowsStartingAtZero() {
176 rows = Range.atLeast(0);
177 return this;
178 }
179
180 public Builder expand(CellQuery query) {
181 if (Objects.isNull(columns)) {
182 columns = query.columns;
183 } else {
184 columns = columns.span(query.columns);
185 }
186 if (Objects.isNull(rows)) {
187 rows = query.rows;
188 } else {
189 rows = rows.span(query.rows);
190 }
191 if (Objects.nonNull(gridName) && !gridName.equals(query.getGrid().get())) {
192 throw new ValueException("Different grid names.");
193 } else {
194 gridName = query.getGrid().get();
195 }
196 return this;
197 }
198
199 public CellQuery build() {
200 return new CellQuery(gridName, Objects.requireNonNull(columns), Objects.requireNonNull(rows));
201 }
202 }
203}