/* * 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.torod.impl.memory; import com.torodb.core.cursors.Cursor; import com.torodb.core.cursors.IteratorCursor; import com.torodb.core.cursors.TransformCursor; import com.torodb.core.document.ToroDocument; import com.torodb.core.exceptions.user.CollectionNotFoundException; import com.torodb.core.exceptions.user.IndexNotFoundException; import com.torodb.core.language.AttributeReference; import com.torodb.core.util.AttributeRefKvDocResolver; import com.torodb.kvdocument.values.KvDocument; import com.torodb.kvdocument.values.KvValue; import com.torodb.torod.CollectionInfo; import com.torodb.torod.IndexInfo; import com.torodb.torod.TorodTransaction; import com.torodb.torod.cursors.DocTorodCursor; import com.torodb.torod.cursors.TorodCursor; import org.jooq.lambda.tuple.Tuple2; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.json.Json; /** * */ public abstract class MemoryTorodTransaction implements TorodTransaction { private boolean closed = false; private final MemoryTorodConnection connection; public MemoryTorodTransaction(MemoryTorodConnection connection) { this.connection = connection; } protected abstract MemoryData.MdTransaction getTransaction(); @Override public boolean isClosed() { return closed; } @Override public MemoryTorodConnection getConnection() { return connection; } @Override public boolean existsDatabase(String dbName) { return getTransaction().existsDatabase(dbName); } @Override public boolean existsCollection(String dbName, String colName) { return getTransaction().existsCollection(dbName, colName); } @Override public List<String> getDatabases() { return getTransaction().streamDbs().collect(Collectors.toList()); } @Override public long countAll(String dbName, String colName) { return getTransaction().streamCollection(dbName, colName).count(); } @Override public TorodCursor findAll(String dbName, String colName) { return createCursor(getTransaction().streamCollection(dbName, colName)); } Stream<ToroDocument> streamByAttRef(String dbName, String colName, AttributeReference attRef, KvValue<?> value) { return getTransaction().streamCollection(dbName, colName) .filter(doc -> { Optional<KvValue<?>> resolved = AttributeRefKvDocResolver.resolve( attRef, doc.getRoot()); return resolved.isPresent() && value.equals(resolved.get()); }); } @Override public TorodCursor findByAttRef(String dbName, String colName, AttributeReference attRef, KvValue<?> value) { return createCursor(streamByAttRef(dbName, colName, attRef, value)); } @Override public TorodCursor findByAttRefIn(String dbName, String colName, AttributeReference attRef, Collection<KvValue<?>> values) { return createCursor(getTransaction().streamCollection(dbName, colName) .filter(doc -> { Optional<KvValue<?>> resolved = AttributeRefKvDocResolver.resolve( attRef, doc.getRoot()); return resolved.isPresent() && values.contains(resolved.get()); }) ); } @Override public Cursor<Tuple2<Integer, KvValue<?>>> findByAttRefInProjection(String dbName, String colName, AttributeReference attRef, Collection<KvValue<?>> values) { Cursor<ToroDocument> docCursor = findByAttRefIn(dbName, colName, attRef, values) .asDocCursor(); return new TransformCursor<>(docCursor, (toroDoc) -> { Optional<KvValue<?>> resolved = AttributeRefKvDocResolver.resolve(attRef, toroDoc.getRoot()); assert resolved.isPresent(); return new Tuple2<>(toroDoc.getId(), resolved.get()); }); } @Override public TorodCursor fetch(String dbName, String colName, Cursor<Integer> didCursor) { Map<Integer, KvDocument> colData = getTransaction().data.get(dbName, colName); return createCursor(didCursor.getRemaining().stream() .map(did -> new Tuple2<>(did, colData.get(did))) .filter(tuple -> tuple.v2 != null) .map(tuple -> new ToroDocument(tuple.v1, tuple.v2)) ); } private TorodCursor createCursor(Stream<ToroDocument> docsStream) { return new DocTorodCursor(new IteratorCursor<>(docsStream.iterator())); } @Override public long getDatabaseSize(String dbName) { throw new UnsupportedOperationException("Not supported yet."); //TODO: Implement when necessary } @Override public long getCollectionSize(String dbName, String colName) { throw new UnsupportedOperationException("Not supported yet."); //TODO: Implement when necessary } @Override public long getDocumentsSize(String dbName, String colName) { throw new UnsupportedOperationException("Not supported yet."); //TODO: Implement when necessary } @Override public Stream<CollectionInfo> getCollectionsInfo(String dbName) { return getTransaction().data.row(dbName).keySet().stream() .map(colName -> getCollectionInfoPrivate(colName)); } @Override public CollectionInfo getCollectionInfo(String dbName, String colName) throws CollectionNotFoundException { if (!getTransaction().data.contains(dbName, colName)) { throw new CollectionNotFoundException(dbName, colName); } return getCollectionInfoPrivate(colName); } private CollectionInfo getCollectionInfoPrivate(String colName) { return new CollectionInfo(colName, Json.createObjectBuilder().build()); } @Override public Stream<IndexInfo> getIndexesInfo(String dbName, String colName) { Map<String, IndexInfo> indexesOnTable = getTransaction().getIndexes() .get(dbName, colName); if (indexesOnTable == null) { return Stream.empty(); } return indexesOnTable.values().stream(); } @Override public IndexInfo getIndexInfo(String dbName, String colName, String idxName) throws IndexNotFoundException { return getIndexesInfo(dbName, colName) .filter(index -> index.getName().equals(idxName)) .findAny().orElseThrow(() -> new IndexNotFoundException(dbName, colName, idxName)); } @Override public void close() { if (!closed) { closed = true; getTransaction().close(); connection.onTransactionClosed(this); } } }