When removing a key that does exist then an updated GitDbBranch is returned

This commit is contained in:
Paul Campbell 2018-06-15 09:35:18 +01:00
parent 50a304a941
commit d6f8bcbc0f
5 changed files with 160 additions and 5 deletions

View file

@ -46,7 +46,7 @@ public interface GitDBBranch {
* @param key the key to place the value under * @param key the key to place the value under
* @param value the value (must be Serializable) * @param value the value (must be Serializable)
* @return an updated branch containing the new key/value * @return an updated branch containing the new key/value
* @throws IOException if there was an error writing the value * @throws IOException if there was an error writing the key/value
*/ */
GitDBBranch put(String key, String value) throws IOException; GitDBBranch put(String key, String value) throws IOException;
@ -55,6 +55,7 @@ public interface GitDBBranch {
* *
* @param key the key to remove * @param key the key to remove
* @return an updated branch without the key, or the original if the key was not found * @return an updated branch without the key, or the original if the key was not found
* @throws IOException if there was an error removing the key/value
*/ */
GitDBBranch remove(String key); GitDBBranch remove(String key) throws IOException;
} }

View file

@ -85,7 +85,17 @@ class GitDBBranchImpl implements GitDBBranch {
} }
@Override @Override
public GitDBBranch remove(final String key) { public GitDBBranch remove(final String key) throws IOException {
final Optional<ObjectId> newTree = gitDBRepo.removeKey(branchRef, KEY_PREFIX + key);
if (newTree.isPresent()) {
final Ref newBranch =
gitDBRepo.writeCommit(
branchRef, newTree.get(),
commitMessageForRemove(key),
userName,
userEmailAddress);
return select(newBranch, gitDBRepo, userName, userEmailAddress);
}
return this; return this;
} }
@ -93,4 +103,8 @@ class GitDBBranchImpl implements GitDBBranch {
return String.format("Add key [%s] = [%s]", key, value); return String.format("Add key [%s] = [%s]", key, value);
} }
private String commitMessageForRemove(final String key) {
return String.format("Remove Key [%s]", key);
}
} }

View file

@ -41,6 +41,7 @@ class GitDBRepo {
private final ValueWriter valueWriter; private final ValueWriter valueWriter;
private final KeyWriter keyWriter; private final KeyWriter keyWriter;
private final CommitWriter commitWriter; private final CommitWriter commitWriter;
private final KeyRemover keyRemover;
/** /**
* Creates a new instance of this class. * Creates a new instance of this class.
@ -52,6 +53,7 @@ class GitDBRepo {
valueWriter = new ValueWriter(repository); valueWriter = new ValueWriter(repository);
keyWriter = new KeyWriter(repository); keyWriter = new KeyWriter(repository);
commitWriter = new CommitWriter(repository); commitWriter = new CommitWriter(repository);
keyRemover = new KeyRemover(repository);
} }
/** /**
@ -157,11 +159,11 @@ class GitDBRepo {
/** /**
* Add the key/value to the repo, returning the tree containing the update. * Add the key/value to the repo, returning the tree containing the update.
* *
* <p>N.B. this creates a tree that has not been committed remains unaware of the update.</p> * <p>N.B. this creates a tree that has not been committed, the branch remains unaware of the update.</p>
* *
* @param branchRef the branch to start from * @param branchRef the branch to start from
* @param key the key to place the value under * @param key the key to place the value under
* @param value the value (must be Serializable) * @param value the value
* @return the id of the updated tree containing the update * @return the id of the updated tree containing the update
* @throws IOException if there was an error writing the value * @throws IOException if there was an error writing the value
*/ */
@ -210,4 +212,19 @@ class GitDBRepo {
) throws IOException { ) throws IOException {
return commitWriter.write(treeId, ObjectId.zeroId(), initMessage, initUser, initEmail); return commitWriter.write(treeId, ObjectId.zeroId(), initMessage, initUser, initEmail);
} }
/**
* Remove the key from the branch, returning the tree containing the update.
*
* <p>N.B. this creates a tree that has not been committed, the branch remains unaware of the update.</p>
*
* @param branchRef the branch to start from
* @param key the key to place the value under
* @return an Optional containing the id of the updated tree containing the update, if the key was found, or an
* empty Optional if there key was not found, the there was no changes made
* @throws IOException if there was an error writing the value
*/
Optional<ObjectId> removeKey(final Ref branchRef, final String key) throws IOException {
return keyRemover.remove(branchRef, key);
}
} }

View file

@ -0,0 +1,113 @@
/*
The MIT License (MIT)
Copyright (c) 2018 Paul Campbell
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package net.kemitix.gitdb.impl;
import lombok.RequiredArgsConstructor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.TreeFormatter;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Remove Key from the Git Repository.
*
* @author Paul Campbell (pcampbell@kemitix.net)
*/
@RequiredArgsConstructor
class KeyRemover {
private final Repository repository;
/**
* Sets the boolean to true if the key matches a NamedRevBlob's name.
*
* @param key the key to match
* @param removed the boolean to update
* @return a Consumer
*/
private static Consumer<GitTreeReader.NamedRevBlob> flagIfFound(final String key, final AtomicBoolean removed) {
return nvb -> {
if (nvb.getName().equals(key)) {
removed.set(true);
}
};
}
/**
* Filter to exclude named blobs where the name matches the key.
*
* @param key the key to match
* @return a Predicate
*/
private static Predicate<GitTreeReader.NamedRevBlob> isNotKey(final String key) {
return item -> !item.getName().equals(key);
}
/**
* Adds the named value blob to the tree formatter.
*
* @param treeFormatter the tree formatter to add to
* @return a Consumer
*/
private static Consumer<GitTreeReader.NamedRevBlob> addToTree(final TreeFormatter treeFormatter) {
return item -> treeFormatter.append(item.getName(), item.getRevBlob());
}
/**
* Remove a key from the repository.
*
* @param branchRef the branch to update
* @param key the key to remove
* @return the id of the updated tree
* @throws IOException if there is an error writing the value
*/
Optional<ObjectId> remove(final Ref branchRef, final String key) throws IOException {
final TreeFormatter treeFormatter = new TreeFormatter();
final AtomicBoolean removed = new AtomicBoolean(false);
new GitTreeReader(repository)
.stream(branchRef)
.peek(flagIfFound(key, removed))
.filter(isNotKey(key))
.forEach(addToTree(treeFormatter));
if (removed.get()) {
return Optional.of(insertTree(treeFormatter));
}
return Optional.empty();
}
/**
* Insert a tree into the repo, returning its id.
*
* @param treeFormatter the formatter containing the proposed tree's data.
* @return the name of the tree object.
* @throws IOException the object could not be stored.
*/
private ObjectId insertTree(final TreeFormatter treeFormatter) throws IOException {
return repository.getObjectDatabase().newInserter().insert(treeFormatter);
}
}

View file

@ -249,6 +249,16 @@ class GitDBTest implements WithAssertions {
} }
// When removing a key that does exist then a GitDbBranch is returned // When removing a key that does exist then a GitDbBranch is returned
@Test
void removeKey_whenExists_thenReturnUpdatedBranch() throws IOException {
//given
final GitDBBranch originalBranch = gitDBBranch().put("key-name", "value");
//when
final GitDBBranch updatedBranch = originalBranch.remove("key-name");
//then
assertThat(updatedBranch).isNotSameAs(originalBranch);
}
// When removing a key that does exist then original GitDbBranch can still find it // When removing a key that does exist then original GitDbBranch can still find it
// When removing a key that does exist then the updated GitDbBranch can't find it // When removing a key that does exist then the updated GitDbBranch can't find it