More flexible delete and query api (#1790)

Replaces the filter and delete by repository api's with a more flexible api, which allows to filter and delete by any id part.
This commit is contained in:
Sebastian Sdorra
2021-09-01 16:19:19 +02:00
committed by GitHub
parent ea7964d224
commit 70fba6c990
14 changed files with 346 additions and 102 deletions

View File

@@ -26,8 +26,6 @@ package sonia.scm.repository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -109,7 +107,7 @@ class RepositoryIndexerTest {
when(index.getDetails().getType()).then(ic -> String.class);
indexer.createDeleteTask(heartOfGold).update(index);
verify(index.delete()).byRepository(heartOfGold);
verify(index.delete().by(Repository.class, heartOfGold)).execute();
}
@Test
@@ -135,7 +133,8 @@ class RepositoryIndexerTest {
verify(searchEngine.forIndices().forResource(heartOfGold)).batch(captor.capture());
captor.getValue().update(index);
verify(index.delete()).byRepository(heartOfGold);
verify(index.delete().by(Repository.class, heartOfGold)).execute();
}
@Test

View File

@@ -31,6 +31,7 @@ import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.ByteBuffersDirectory;
@@ -158,7 +159,24 @@ class LuceneIndexTest {
}
try (LuceneIndex<Storable> index = createIndex(Storable.class)) {
index.delete().byRepository("4212");
index.delete().by(Repository.class, "4212").execute();
}
assertHits("value", "content", 1);
}
@Test
void shouldDeleteByMultipleFields() throws IOException {
Id<Storable> base = ONE.and(Repository.class, "4211");
try (LuceneIndex<Storable> index = createIndex(Storable.class)) {
index.store(base.and(String.class, "1"), null, new Storable("content"));
index.store(base.and(String.class, "2"), null, new Storable("content"));
index.store(base.and(String.class, "2"), null, new Storable("content"));
}
try (LuceneIndex<Storable> index = createIndex(Storable.class)) {
index.delete().by(Repository.class, "4211").and(String.class, "2").execute();
}
assertHits("value", "content", 1);
@@ -233,11 +251,11 @@ class LuceneIndexTest {
}
@Test
void shouldThrowSearchEngineExceptionOnDeleteByRepository() throws IOException {
when(writer.deleteDocuments(any(Term.class))).thenThrow(new IOException("failed to delete"));
void shouldThrowSearchEngineExceptionOnDeleteBy() throws IOException {
when(writer.deleteDocuments(any(Query.class))).thenThrow(new IOException("failed to delete"));
Index.Deleter<Storable> deleter = index.delete();
assertThrows(SearchEngineException.class, () -> deleter.byRepository("42"));
Index.DeleteBy deleter = index.delete().by(Repository.class, "42");
assertThrows(SearchEngineException.class, deleter::execute);
}
@Test

View File

@@ -49,11 +49,13 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.repository.Repository;
import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -277,16 +279,9 @@ class LuceneQueryBuilderTest {
writer.addDocument(repositoryDoc("Awesome content three", "fgh"));
}
QueryResult result;
try (DirectoryReader reader = DirectoryReader.open(directory)) {
SearchableTypeResolver resolver = new SearchableTypeResolver(Simple.class);
LuceneSearchableType searchableType = resolver.resolve(Simple.class);
when(opener.openForRead(searchableType, "default")).thenReturn(reader);
LuceneQueryBuilder<Simple> builder = new LuceneQueryBuilder<>(
opener, "default", searchableType, new StandardAnalyzer()
);
result = builder.repository("cde").execute("content:awesome");
}
QueryResult result = query(
Simple.class, "content:awesome", builder -> builder.filter(Repository.class, "cde")
);
assertThat(result.getTotalHits()).isOne();
@@ -297,6 +292,24 @@ class LuceneQueryBuilderTest {
});
}
@Test
void shouldFilterByIdParts() throws IOException {
try (IndexWriter writer = writer()) {
writer.addDocument(idPartsDoc("Awesome content one", "abc", "one"));
writer.addDocument(idPartsDoc("Awesome content two", "abc", "two"));
writer.addDocument(idPartsDoc("Awesome content three", "cde", "two"));
}
QueryResult result = query(
Simple.class, "content:awesome",
builder -> builder.filter(Repository.class, "abc").filter(String.class, "two")
);
List<Hit> hits = result.getHits();
assertThat(hits).hasSize(1)
.allSatisfy(hit -> assertValueField(hit, "content", "Awesome content two"));
}
@Test
void shouldReturnStringFields() throws IOException {
try (IndexWriter writer = writer()) {
@@ -549,6 +562,17 @@ class LuceneQueryBuilderTest {
}
private <T> QueryResult query(Class<?> type, String queryString, Integer start, Integer limit) throws IOException {
return query(type, queryString, builder -> {
if (start != null) {
builder.start(start);
}
if (limit != null) {
builder.limit(limit);
}
});
}
private <T> QueryResult query(Class<T> type, String queryString, Consumer<LuceneQueryBuilder<T>> consumer) throws IOException {
try (DirectoryReader reader = DirectoryReader.open(directory)) {
SearchableTypeResolver resolver = new SearchableTypeResolver(type);
LuceneSearchableType searchableType = resolver.resolve(type);
@@ -557,12 +581,7 @@ class LuceneQueryBuilderTest {
LuceneQueryBuilder<T> builder = new LuceneQueryBuilder<>(
opener, "default", searchableType, new StandardAnalyzer()
);
if (start != null) {
builder.start(start);
}
if (limit != null) {
builder.limit(limit);
}
consumer.accept(builder);
return builder.execute(queryString);
}
}
@@ -576,14 +595,12 @@ class LuceneQueryBuilderTest {
private Document simpleDoc(String content) {
Document document = new Document();
document.add(new TextField("content", content, Field.Store.YES));
// document.add(new StringField(FieldNames.TYPE, "simple", Field.Store.YES));
return document;
}
private Document permissionDoc(String content, String permission) {
Document document = new Document();
document.add(new TextField("content", content, Field.Store.YES));
// document.add(new StringField(FieldNames.TYPE, "simple", Field.Store.YES));
document.add(new StringField(FieldNames.PERMISSION, permission, Field.Store.YES));
return document;
}
@@ -591,11 +608,18 @@ class LuceneQueryBuilderTest {
private Document repositoryDoc(String content, String repository) {
Document document = new Document();
document.add(new TextField("content", content, Field.Store.YES));
// document.add(new StringField(FieldNames.TYPE, "simple", Field.Store.YES));
document.add(new StringField(FieldNames.REPOSITORY, repository, Field.Store.YES));
return document;
}
private Document idPartsDoc(String content, String repository, String other) {
Document document = new Document();
document.add(new TextField("content", content, Field.Store.YES));
document.add(new StringField(FieldNames.REPOSITORY, repository, Field.Store.YES));
document.add(new StringField("_string", other, Field.Store.YES));
return document;
}
private Document inetOrgPersonDoc(String firstName, String lastName, String displayName, String carLicense) {
Document document = new Document();
document.add(new TextField("firstName", firstName, Field.Store.YES));
@@ -603,14 +627,12 @@ class LuceneQueryBuilderTest {
document.add(new TextField("displayName", displayName, Field.Store.YES));
document.add(new TextField("carLicense", carLicense, Field.Store.YES));
document.add(new StringField(FieldNames.ID, lastName, Field.Store.YES));
// document.add(new StringField(FieldNames.TYPE, "inetOrgPerson", Field.Store.YES));
return document;
}
private Document personDoc(String lastName) {
Document document = new Document();
document.add(new TextField("lastName", lastName, Field.Store.YES));
// document.add(new StringField(FieldNames.TYPE, "person", Field.Store.YES));
return document;
}
@@ -623,14 +645,6 @@ class LuceneQueryBuilderTest {
document.add(new StringField("boolValue", String.valueOf(boolValue), Field.Store.YES));
document.add(new LongPoint("instantValue", instantValue.toEpochMilli()));
document.add(new StoredField("instantValue", instantValue.toEpochMilli()));
// document.add(new StringField(FieldNames.TYPE, "types", Field.Store.YES));
return document;
}
private Document denyDoc(String value) {
Document document = new Document();
document.add(new TextField("value", value, Field.Store.YES));
// document.add(new StringField(FieldNames.TYPE, "deny", Field.Store.YES));
return document;
}
@@ -679,11 +693,4 @@ class LuceneQueryBuilderTest {
private String content;
}
@Getter
@IndexedType(permission = "deny:4711")
static class Deny {
@Indexed(defaultQuery = true)
private String value;
}
}