/* * 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.google.common.base.Preconditions; import com.torodb.core.TableRef; import com.torodb.core.annotations.DoNotChange; import org.jooq.lambda.Seq; import org.jooq.lambda.tuple.Tuple2; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; /** * */ public class ImmutableMetaCollection implements MetaCollection { private final String name; private final String identifier; private final Map<TableRef, ImmutableMetaDocPart> docPartsByTableRef; private final Map<String, ImmutableMetaDocPart> docPartsByIdentifier; private final Map<String, ImmutableMetaIndex> indexesByName; public ImmutableMetaCollection(String colName, String colId, Iterable<ImmutableMetaDocPart> docParts, Iterable<ImmutableMetaIndex> indexes) { this.name = colName; this.identifier = colId; HashMap<TableRef, ImmutableMetaDocPart> byTableRef = new HashMap<>(); HashMap<String, ImmutableMetaDocPart> byDbName = new HashMap<>(); for (ImmutableMetaDocPart table : docParts) { byTableRef.put(table.getTableRef(), table); byDbName.put(table.getIdentifier(), table); } this.docPartsByTableRef = Collections.unmodifiableMap(byTableRef); this.docPartsByIdentifier = Collections.unmodifiableMap(byDbName); HashMap<String, ImmutableMetaIndex> indexesByName = new HashMap<>(); for (ImmutableMetaIndex index : indexes) { indexesByName.put(index.getName(), index); } this.indexesByName = Collections.unmodifiableMap(indexesByName); } public ImmutableMetaCollection(String colName, String colId, @DoNotChange Map<String, ImmutableMetaDocPart> docPartsById, Map<String, ImmutableMetaIndex> indexesByName) { this.name = colName; this.identifier = colId; this.docPartsByIdentifier = docPartsById; this.docPartsByTableRef = new HashMap<>(); for (ImmutableMetaDocPart table : docPartsById.values()) { docPartsByTableRef.put(table.getTableRef(), table); } this.indexesByName = indexesByName; } @Override public String getName() { return name; } @Override public String getIdentifier() { return identifier; } @Override public Stream<ImmutableMetaDocPart> streamContainedMetaDocParts() { return docPartsByIdentifier.values().stream(); } @Override public ImmutableMetaDocPart getMetaDocPartByIdentifier(String tableDbName) { return docPartsByIdentifier.get(tableDbName); } @Override public ImmutableMetaDocPart getMetaDocPartByTableRef(TableRef tableRef) { return docPartsByTableRef.get(tableRef); } @Override public Stream<ImmutableMetaIndex> streamContainedMetaIndexes() { return indexesByName.values().stream(); } @Override public ImmutableMetaIndex getMetaIndexByName(String indexName) { return indexesByName.get(indexName); } @Override public List<Tuple2<MetaIndex, List<String>>> getMissingIndexesForNewField( MutableMetaDocPart docPart, MetaField newField) { return getMissingIndexesForNewField(streamContainedMetaIndexes(), docPart, newField); } protected List<Tuple2<MetaIndex, List<String>>> getMissingIndexesForNewField( Stream<? extends MetaIndex> containedMetaIndexes, MutableMetaDocPart docPart, MetaField newField) { return containedMetaIndexes .filter(index -> index.getMetaIndexFieldByTableRefAndName(docPart.getTableRef(), newField .getName()) != null) .flatMap(index -> Seq.seq(index.iteratorMetaDocPartIndexesIdentifiers(docPart)) .filter(identifiers -> identifiers.contains(newField.getIdentifier())) .map(identifiers -> new Tuple2<MetaIndex, List<String>>(index, identifiers))) .collect(Collectors.groupingBy(missingIndexEntry -> missingIndexEntry.v2())) .entrySet() .stream() .map(groupedMissingIndexEntries -> groupedMissingIndexEntries.getValue().get(0)) .collect(Collectors.toList()); } public static class Builder { private boolean built = false; private final String name; private final String identifier; private final Map<String, ImmutableMetaDocPart> docPartsByIdentifier; private final Map<String, ImmutableMetaIndex> indexesByName; public Builder(String name, String identifier) { this.name = name; this.identifier = identifier; this.docPartsByIdentifier = new HashMap<>(); this.indexesByName = new HashMap<>(); } public Builder(String name, String identifier, int expectedDocParts, int expectedIndexes) { this.name = name; this.identifier = identifier; this.docPartsByIdentifier = new HashMap<>(expectedDocParts); this.indexesByName = new HashMap<>(expectedIndexes); } public Builder(ImmutableMetaCollection other) { this.name = other.getName(); this.identifier = other.getIdentifier(); docPartsByIdentifier = new HashMap<>(other.docPartsByIdentifier); this.indexesByName = new HashMap<>(other.indexesByName); } public Builder put(ImmutableMetaDocPart.Builder tableBuilder) { return put(tableBuilder.build()); } public Builder put(ImmutableMetaDocPart table) { Preconditions.checkState(!built, "This builder has already been built"); docPartsByIdentifier.put(table.getIdentifier(), table); return this; } public Builder put(ImmutableMetaIndex.Builder indexBuilder) { return put(indexBuilder.build()); } public Builder put(ImmutableMetaIndex index) { Preconditions.checkState(!built, "This builder has already been built"); indexesByName.put(index.getName(), index); return this; } public Builder remove(MetaIndex index) { Preconditions.checkState(!built, "This builder has already been built"); indexesByName.remove(index.getName()); return this; } public ImmutableMetaCollection build() { Preconditions.checkState(!built, "This builder has already been built"); Preconditions.checkState( docPartsByIdentifier.values().isEmpty() || docPartsByIdentifier.values().stream() .anyMatch((dp) -> dp.getTableRef().isRoot()), "Tryng to create a MetaCollection without a root doc part" ); built = true; return new ImmutableMetaCollection(name, identifier, docPartsByIdentifier, indexesByName); } } @Override public String toString() { return defautToString(); } }