public Builder add(Slice slice) { assert comparator.compare(slice.start(), slice.end()) <= 0; if (slices.size() > 0 && comparator.compare(slices.get(slices.size() - 1).end(), slice.start()) > 0) needsNormalizing = true; slices.add(slice); return this; }
/** * Given an array of slices (potentially overlapping and in any order) and return an equivalent * array of non-overlapping slices in clustering order. * * @param slices an array of slices. This may be modified by this method. * @return the smallest possible array of non-overlapping slices in clustering order. If the * original slices are already non-overlapping and in comparator order, this may or may not * return the provided slices directly. */ private List<Slice> normalize(List<Slice> slices) { if (slices.size() <= 1) return slices; Collections.sort( slices, new Comparator<Slice>() { @Override public int compare(Slice s1, Slice s2) { int c = comparator.compare(s1.start(), s2.start()); if (c != 0) return c; return comparator.compare(s1.end(), s2.end()); } }); List<Slice> slicesCopy = new ArrayList<>(slices.size()); Slice last = slices.get(0); for (int i = 1; i < slices.size(); i++) { Slice s2 = slices.get(i); boolean includesStart = last.includes(comparator, s2.start()); boolean includesFinish = last.includes(comparator, s2.end()); if (includesStart && includesFinish) continue; if (!includesStart && !includesFinish) { slicesCopy.add(last); last = s2; continue; } if (includesStart) { last = Slice.make(last.start(), s2.end()); continue; } assert !includesFinish; } slicesCopy.add(last); return slicesCopy; }
public String toCQLString(CFMetaData metadata) { StringBuilder sb = new StringBuilder(); // In CQL, condition are expressed by column, so first group things that way, // i.e. for each column, we create a list of what each slice contains on that column int clusteringSize = metadata.clusteringColumns().size(); List<List<ComponentOfSlice>> columnComponents = new ArrayList<>(clusteringSize); for (int i = 0; i < clusteringSize; i++) { List<ComponentOfSlice> perSlice = new ArrayList<>(); columnComponents.add(perSlice); for (int j = 0; j < slices.length; j++) { ComponentOfSlice c = ComponentOfSlice.fromSlice(i, slices[j]); if (c != null) perSlice.add(c); } } boolean needAnd = false; for (int i = 0; i < clusteringSize; i++) { ColumnDefinition column = metadata.clusteringColumns().get(i); List<ComponentOfSlice> componentInfo = columnComponents.get(i); if (componentInfo.isEmpty()) break; // For a given column, there is only 3 cases that CQL currently generates: // 1) every slice are EQ with the same value, it's a simple '=' relation. // 2) every slice are EQ but with different values, it's a IN relation. // 3) every slice aren't EQ but have the same values, we have inequality relations. // Note that this doesn't cover everything that ReadCommand can express, but // as it's all that CQL support for now, we'll ignore other cases (which would then // display a bogus query but that's not the end of the world). // TODO: we should improve this at some point. ComponentOfSlice first = componentInfo.get(0); if (first.isEQ()) { if (needAnd) sb.append(" AND "); needAnd = true; sb.append(column.name); Set<ByteBuffer> values = new LinkedHashSet<>(); for (int j = 0; j < componentInfo.size(); j++) values.add(componentInfo.get(j).startValue); if (values.size() == 1) { sb.append(" = ").append(column.type.getString(first.startValue)); } else { sb.append(" IN ("); int j = 0; for (ByteBuffer value : values) sb.append(j++ == 0 ? "" : ", ").append(column.type.getString(value)); sb.append(")"); } } else { // As said above, we assume (without checking) that this means all ComponentOfSlice for // this column // are the same, so we only bother about the first. if (first.startValue != null) { if (needAnd) sb.append(" AND "); needAnd = true; sb.append(column.name) .append(first.startInclusive ? " >= " : " > ") .append(column.type.getString(first.startValue)); } if (first.endValue != null) { if (needAnd) sb.append(" AND "); needAnd = true; sb.append(column.name) .append(first.endInclusive ? " <= " : " < ") .append(column.type.getString(first.endValue)); } } } return sb.toString(); }