Add semrack index postgresql
All checks were successful
Maven build / build (push) Successful in 3m17s

This commit is contained in:
Guillaume Dugas
2025-11-19 23:31:18 +01:00
parent de339f9554
commit 03b1e0851b
62 changed files with 1301 additions and 318 deletions

View File

@@ -16,6 +16,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security</artifactId>

View File

@@ -0,0 +1,13 @@
package fr.codeanddata.semrack.core;
import fr.codeanddata.semrack.core.models.IndexSearchResult;
import fr.codeanddata.semrack.core.models.SearchRequest;
import io.smallrye.mutiny.Uni;
public interface SemdocIndex {
Uni<Long> count(SearchRequest request);
Uni<Boolean> exist(SearchRequest query);
Uni<Void> index(String documentId);
Uni<IndexSearchResult> search(SearchRequest searchRequest);
Uni<Void> clear(String documentId);
}

View File

@@ -1,14 +1,12 @@
package fr.codeanddata.semrack.core;
import fr.codeanddata.semrack.core.models.SearchRequest;
import fr.codeanddata.semrack.core.models.SearchResult;
import fr.codeanddata.semrack.core.models.SemrackDocument;
import io.smallrye.mutiny.Uni;
import java.util.List;
public interface SemdocStorage {
Uni<SemrackDocument> readDocument(String uid);
Uni<SearchResult> searchDocument(SearchRequest query);
Uni<Long> countDocuments(SearchRequest request);
Uni<Boolean> documentsExist(SearchRequest query);
Uni<SemrackDocument> get(String uid);
Uni<List<SemrackDocument>> get(List<String> uids);
Uni<SemrackDocument> storeDocument(SemrackDocument document);
}

View File

@@ -24,7 +24,7 @@ public class AnnotateWriteInterceptor implements SemdocWriteInterceptor {
final Map<String, Object> directives = context.getDirectives();
if (directives.containsKey(ANNOTATE_KEY)) {
final Map<String, Object> annotate = objectMapper.convertValue(directives.get(ANNOTATE_KEY), new TypeReference<Map<String, Object>>() {});
final Map<String, Object> annotate = objectMapper.convertValue(directives.get(ANNOTATE_KEY), new TypeReference<>() {});
annotate.keySet().forEach(key -> context.getNextDocument().getAnnotations().put(CUSTOM_PREFIX + key, annotate.get(key)));
}

View File

@@ -0,0 +1,15 @@
package fr.codeanddata.semrack.core.models;
import lombok.*;
import java.util.List;
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class IndexSearchResult {
List<String> uids;
PaginationInfo pagination;
}

View File

@@ -0,0 +1,15 @@
package fr.codeanddata.semrack.core.models;
import fr.codeanddata.semrack.core.utils.Traverser;
import lombok.*;
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TraverserPath {
Traverser.PathTypes type;
String fullPath;
Object value;
}

View File

@@ -1,9 +1,9 @@
package fr.codeanddata.semrack.core.repositories;
import fr.codeanddata.semrack.core.SemdocStorage;
import fr.codeanddata.semrack.core.SemdocWriteInterceptor;
import fr.codeanddata.semrack.core.exceptions.SemrackRuntimeException;
import fr.codeanddata.semrack.core.models.*;
import fr.codeanddata.semrack.core.storages.SemdocStorageProxy;
import fr.codeanddata.semrack.core.utils.UIDGenerator;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
@@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicReference;
public class SemdocRepository {
@Inject
SemdocStorage semdocStorage;
SemdocStorageProxy semdocStorage;
@Inject
@Any
@@ -28,10 +28,14 @@ public class SemdocRepository {
@Inject
UIDGenerator uidGenerator;
Uni<SearchResult> searchDocument(SearchRequest query) {
public Uni<SearchResult> searchDocument(SearchRequest query) {
return semdocStorage.searchDocument(query);
}
public Uni<SemrackDocument> get(String documentId) {
return semdocStorage.readDocument(documentId);
}
public Uni<SemrackDocument> pushDocument(PushDocumentRequest pushDocument) {
return Optional.ofNullable(pushDocument.getUid()).map(semdocStorage::readDocument).orElse(Uni.createFrom().nullItem())
.chain(currentDocument -> {

View File

@@ -0,0 +1,35 @@
package fr.codeanddata.semrack.core.services;
import fr.codeanddata.semrack.core.SemdocIndex;
import fr.codeanddata.semrack.core.models.IndexSearchResult;
import fr.codeanddata.semrack.core.models.SearchRequest;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class SemrackIndexService {
@Inject
SemdocIndex semdocIndex;
public Uni<Void> index(String documentId) {
return semdocIndex.index(documentId);
}
public Uni<IndexSearchResult> search(SearchRequest searchRequest) {
return semdocIndex.search(searchRequest);
}
public Uni<Long> count(SearchRequest request) {
return semdocIndex.count(request);
}
public Uni<Boolean> exist(SearchRequest query) {
return semdocIndex.exist(query);
}
public Uni<Void> clear(String documentId) {
return semdocIndex.clear(documentId);
}
}

View File

@@ -0,0 +1,46 @@
package fr.codeanddata.semrack.core.storages;
import fr.codeanddata.semrack.core.SemdocIndex;
import fr.codeanddata.semrack.core.SemdocStorage;
import fr.codeanddata.semrack.core.models.SearchRequest;
import fr.codeanddata.semrack.core.models.SearchResult;
import fr.codeanddata.semrack.core.models.SemrackDocument;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class SemdocStorageProxy {
@Inject
SemdocStorage storage;
@Inject
SemdocIndex index;
public Uni<SemrackDocument> readDocument(String uid) {
return storage.get(uid);
}
public Uni<SearchResult> searchDocument(SearchRequest query) {
return index.search(query)
.chain(searchResult -> storage.get(searchResult.getUids())
.map(documents -> SearchResult.builder()
.documents(documents)
.pagination(searchResult.getPagination())
.build()));
}
public Uni<Long> countDocuments(SearchRequest request) {
return index.count(request);
}
public Uni<Boolean> documentsExist(SearchRequest query) {
return index.exist(query);
}
public Uni<SemrackDocument> storeDocument(SemrackDocument document) {
return storage.storeDocument(document)
.call(x -> index.index(x.getUid()));
}
}

View File

@@ -0,0 +1,91 @@
package fr.codeanddata.semrack.core.utils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.codeanddata.semrack.core.models.TraverserPath;
import io.vertx.core.json.Json;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.*;
import java.util.function.Function;
@ApplicationScoped
public class Traverser implements Function<Object, List<TraverserPath>> {
@Inject
ObjectMapper mapper;
@Override
public List<TraverserPath> apply(Object o) {
return parse("", o);
}
public enum PathTypes {
UNKNOWN,
STRING,
NUMBER,
BOOLEAN,
LIST,
OBJECT
}
List<TraverserPath> parse(String basePath, Object data) {
final List<TraverserPath> paths = new ArrayList<>();
PathTypes type = PathTypes.UNKNOWN;
if (data instanceof String) {
type = PathTypes.STRING;
} else if (data instanceof Boolean) {
type = PathTypes.BOOLEAN;
} else if (data instanceof Number) {
type = PathTypes.NUMBER;
} else if (data instanceof Collection) {
type = PathTypes.LIST;
} else if (data instanceof Map) {
type = PathTypes.OBJECT;
}
switch (type) {
case PathTypes.LIST:
final Collection<?> values = mapper.convertValue(data, Collection.class);
paths.add(TraverserPath.builder()
.fullPath(basePath)
.value(null)
.type(PathTypes.LIST)
.build());
int i = 0;
for (Iterator<?> it = values.iterator(); it.hasNext(); i++) {
final String fullPath = basePath + "[" + i + "]";
final Object value = it.next();
paths.addAll(parse(fullPath, value));
}
break;
case PathTypes.OBJECT:
paths.add(TraverserPath.builder()
.fullPath(basePath)
.value(null)
.type(PathTypes.OBJECT)
.build());
final Map<String, ?> map = mapper.convertValue(data, new TypeReference<>() {
});
for (Map.Entry<String, ?> entry : map.entrySet()) {
final String fullPath = basePath + "." + entry.getKey();
final Object value = entry.getValue();
paths.addAll(parse(fullPath, value));
}
break;
default:
paths.add(TraverserPath.builder()
.type(type)
.fullPath(basePath)
.value(data)
.build());
break;
}
return paths;
}
}