/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.torodb.core.transaction.metainf;
import com.torodb.core.TableRef;
import com.torodb.core.annotations.DoNotChange;
import com.torodb.core.transaction.metainf.ImmutableMetaIndex.Builder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
*
*/
public class WrapperMutableMetaIndex implements MutableMetaIndex {
private final ImmutableMetaIndex wrapped;
/**
* This map contains all fields contained by wrapper and all new fields
*/
private final Map<TableRef, List<ImmutableMetaIndexField>> newFields;
/**
* This list just contains the fields that have been added on this wrapper but not on the wrapped
* object.
*/
private final List<ImmutableMetaIndexField> addedFields;
private final Consumer<WrapperMutableMetaIndex> changeConsumer;
public WrapperMutableMetaIndex(ImmutableMetaIndex wrapped,
Consumer<WrapperMutableMetaIndex> changeConsumer) {
this.wrapped = wrapped;
newFields = new HashMap<>();
wrapped.iteratorFields().forEachRemaining((field) ->
newFields.computeIfAbsent(field.getTableRef(), t -> new ArrayList<>()).add(field)
);
addedFields = new ArrayList<>();
this.changeConsumer = changeConsumer;
}
@Override
public ImmutableMetaIndexField addMetaIndexField(TableRef tableRef, String name,
FieldIndexOrdering ordering) throws
IllegalArgumentException {
if (getMetaIndexFieldByTableRefAndName(tableRef, name) != null) {
throw new IllegalArgumentException("There is another field with tableRef " + tableRef
+ " whose name is " + name);
}
ImmutableMetaIndexField newField = new ImmutableMetaIndexField(
size(),
tableRef,
name,
ordering);
newFields.computeIfAbsent(tableRef, t -> new ArrayList<>()).add(newField);
addedFields.add(newField);
changeConsumer.accept(this);
return newField;
}
@Override
@DoNotChange
public Iterable<ImmutableMetaIndexField> getAddedMetaIndexFields() {
return addedFields;
}
@Override
public ImmutableMetaIndex immutableCopy() {
if (addedFields.isEmpty()) {
return wrapped;
} else {
ImmutableMetaIndex.Builder builder = new Builder(wrapped);
for (ImmutableMetaIndexField addedField : addedFields) {
builder.add(addedField);
}
return builder.build();
}
}
@Override
public String getName() {
return wrapped.getName();
}
@Override
public boolean isUnique() {
return wrapped.isUnique();
}
@Override
public int size() {
return newFields.values().stream()
.collect(Collectors.summingInt(l -> l.size()));
}
@Override
public Iterator<? extends ImmutableMetaIndexField> iteratorFields() {
return newFields.values().stream().flatMap(list -> list.stream()).iterator();
}
@Override
public Iterator<? extends ImmutableMetaIndexField> iteratorMetaIndexFieldByTableRef(
TableRef tableRef) {
return newFields.computeIfAbsent(tableRef, t -> new ArrayList<>()).iterator();
}
@Override
public Stream<TableRef> streamTableRefs() {
return newFields.keySet().stream();
}
@Override
public ImmutableMetaIndexField getMetaIndexFieldByPosition(int position) {
if (position < wrapped.size()) {
return wrapped.getMetaIndexFieldByPosition(position);
}
return addedFields.get(position - wrapped.size());
}
@Override
public ImmutableMetaIndexField getMetaIndexFieldByTableRefAndName(TableRef tableRef,
String fieldName) {
return newFields.computeIfAbsent(tableRef, t -> new ArrayList<>()).stream()
.filter(f -> f.getName().equals(fieldName))
.findAny()
.orElse(null);
}
@Override
public MetaIndexField getMetaIndexFieldByTableRefAndPosition(TableRef tableRef, int position) {
return newFields.computeIfAbsent(tableRef, t -> new ArrayList<>()).get(position);
}
@Override
public boolean isCompatible(MetaDocPart docPart, MetaDocPartIndex docPartIndex) {
return wrapped.isCompatible(docPart, docPartIndex,
iteratorMetaIndexFieldByTableRef(docPart.getTableRef()));
}
@Override
public boolean isCompatible(MetaDocPart docPart) {
return wrapped.isCompatible(docPart,
iteratorMetaIndexFieldByTableRef(docPart.getTableRef()));
}
@Override
public boolean isMatch(MetaDocPart docPart, List<String> identifiers,
MetaDocPartIndex docPartIndex) {
return wrapped.isMatch(docPart, identifiers, docPartIndex,
iteratorMetaIndexFieldByTableRef(docPart.getTableRef()), false);
}
@Override
public boolean isMatch(MetaIndex index) {
return wrapped.isMatch(index,
iteratorFields());
}
@Override
public boolean isSubMatch(MetaDocPart docPart, List<String> identifiersSublist,
MetaDocPartIndex docPartIndex) {
return wrapped.isMatch(docPart, identifiersSublist, docPartIndex,
iteratorMetaIndexFieldByTableRef(docPart.getTableRef()), true);
}
@Override
public Iterator<List<String>> iteratorMetaDocPartIndexesIdentifiers(MetaDocPart docPart) {
return wrapped.iteratorMetaDocPartIndexesIdentifiers(docPart,
iteratorMetaIndexFieldByTableRef(docPart.getTableRef()));
}
@Override
public String toString() {
return defautToString();
}
}