/** * Copyright (C) 2014-2019 Expedia Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hotels.plunger; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import cascading.tuple.Fields; import cascading.tuple.Tuple; import cascading.tuple.TupleEntry; public class Data { private final List<Tuple> tuples; private Fields sortFields; private final Fields declaredFields; private Fields withFields = Fields.ALL; Data(Fields declaredFields, List<Tuple> tuples) { this.declaredFields = declaredFields; this.tuples = tuples; } /** * Specifies that the returned results be ordered by the specified {@link Fields}. Assume natural ordering of the * input types. */ public Data orderBy(Fields... fields) { if (fields != null && fields.length > 0) { sortFields = Fields.merge(fields); } return this; } /** * Specifies that the returned results be restricted to the specified {@link Fields}. */ public Data withFields(Fields... fields) { if (fields != null && fields.length > 0) { for (Fields fieldsElement : fields) { // this check seems unnecessary, but Fields.merge() doesn't seem to handle this case if (fieldsElement == Fields.ALL) { withFields = Fields.ALL; return this; } } withFields = Fields.merge(fields); } return this; } /** * Returns the result as a {@link Tuple} list. */ public List<Tuple> asTupleList() { List<Tuple> sorted = new ArrayList<Tuple>(tuples); if (sortFields != null && sortFields.size() > 0) { Collections.sort(sorted, new TupleComparator(declaredFields, sortFields)); } Fields selectedFields = selectedFields(); List<Tuple> selected = new ArrayList<Tuple>(sorted.size()); for (Tuple tuple : sorted) { Tuple filtered = new Tuple(tuple).remove(declaredFields, selectedFields); selected.add(filtered); } return Collections.unmodifiableList(selected); } /** * Returns the result as a {@link TupleEntry} list. */ public List<TupleEntry> asTupleEntryList() { List<Tuple> tuples = asTupleList(); Fields selectedFields = selectedFields(); List<TupleEntry> tupleEntries = new ArrayList<TupleEntry>(tuples.size()); for (Tuple tuple : tuples) { tupleEntries.add(new TupleEntry(selectedFields, tuple, true)); } return Collections.unmodifiableList(tupleEntries); } public PrettyPrinter prettyPrinter() { return new PrettyPrinter(this); } /** * Returns the set of {@link Fields} selected on this result. */ Fields selectedFields() { return declaredFields.select(withFields); } List<Tuple> getTuples() { return tuples; } Fields getDeclaredFields() { return declaredFields; } @Override public int hashCode() { return Objects.hash(declaredFields, tuples); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Data other = (Data) obj; return Objects.equals(declaredFields, other.declaredFields) && Objects.equals(tuples, other.tuples); } @Override public String toString() { return prettyPrinter().toString(); } /** * Create a tap that contains the tuples in this instance. * @return a source tap */ public TupleListTap toTap() { return new TupleListTap(declaredFields, tuples); } }