This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package fr.codeanddata.semrack.storage.postgres.entities;
|
||||
|
||||
import fr.codeanddata.semrack.core.models.SemrackDocument;
|
||||
import fr.codeanddata.semrack.core.models.Document;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
@@ -23,5 +23,5 @@ public class SemrackDocumentEntity extends PanacheEntity implements Serializable
|
||||
String uid;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
SemrackDocument document;
|
||||
Document document;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package fr.codeanddata.semrack.storage.postgres.storage;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import fr.codeanddata.semrack.core.Storage;
|
||||
import fr.codeanddata.semrack.core.models.Document;
|
||||
import fr.codeanddata.semrack.core.models.StorageGet;
|
||||
import fr.codeanddata.semrack.core.utils.UIDGenerator;
|
||||
import fr.codeanddata.semrack.storage.postgres.entities.SemrackDocumentEntity;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ApplicationScoped
|
||||
public class JpaStorage implements Storage, PanacheRepository<SemrackDocumentEntity> {
|
||||
|
||||
@Inject
|
||||
UIDGenerator generator;
|
||||
|
||||
@Inject
|
||||
ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
@WithSession
|
||||
public Uni<Document> get(String uid, StorageGet request) {
|
||||
final List<String> fields = selectFields(request);
|
||||
return getSession()
|
||||
.chain(session -> session.createNativeQuery("select " + String.join(",", fields) + " from semrack_document where uid = ?1")
|
||||
.setParameter(1, uid)
|
||||
.getSingleResult())
|
||||
.map(result -> mapDocument(result, request));
|
||||
}
|
||||
|
||||
@Override
|
||||
@WithSession
|
||||
public Uni<List<Document>> get(List<String> uids, StorageGet request) {
|
||||
final List<String> fields = selectFields(request);
|
||||
return getSession()
|
||||
.chain(session -> session.createNativeQuery("select " + String.join(",", fields) + " from semrack_document where uid in ?1")
|
||||
.setParameter(1, uids)
|
||||
.getResultList())
|
||||
.map(results -> mapDocuments(results, request));
|
||||
}
|
||||
|
||||
@WithTransaction
|
||||
@Override
|
||||
public Uni<Document> storeDocument(Document document) {
|
||||
if (document.getUid() == null) {
|
||||
return createDocument(document)
|
||||
.call(this::flush);
|
||||
} else {
|
||||
return find("uid = ?1", document.getUid())
|
||||
.count()
|
||||
.chain(n -> n == 0 ? createDocument(document) : updateDocument(document))
|
||||
.call(this::flush);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO err : handle existing document
|
||||
@WithTransaction
|
||||
Uni<Document> createDocument(Document document) {
|
||||
final String uid = document.getUid() == null ? generator.apply(document) : document.getUid();
|
||||
document.setUid(uid);
|
||||
final SemrackDocumentEntity entity = SemrackDocumentEntity.builder()
|
||||
.uid(uid)
|
||||
.document(document)
|
||||
.build();
|
||||
return persist(entity).map(SemrackDocumentEntity::getDocument);
|
||||
}
|
||||
|
||||
// TODO err : document not exists
|
||||
@WithTransaction
|
||||
Uni<Document> updateDocument(Document document) {
|
||||
return update("uid = ?1, document = ?2 WHERE uid = ?1", document.getUid(), document)
|
||||
.map(x -> document);
|
||||
}
|
||||
|
||||
List<String> selectFields(StorageGet request) {
|
||||
final List<String> fields = new ArrayList<>(List.of(
|
||||
"uid as _uid",
|
||||
(Optional.ofNullable(request.getAnnotationsSource()).orElse(false) ? "document->'annotations'" : "null") + " as _annotations",
|
||||
(Optional.ofNullable(request.getMetadataSource()).orElse(false) ? "document->'metadata'" : "null") + " as _metadata"
|
||||
));
|
||||
|
||||
if (request.getFields() != null) {
|
||||
int i = 0;
|
||||
for (String field : request.getFields().values()) {
|
||||
fields.add("jsonb_path_query(document, '$.metadata." + field + "') as field_" + i++);
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
Document mapDocument(Object result, StorageGet request) {
|
||||
final Map<String, Integer> fieldMap = buildFieldMap(request);
|
||||
final List<Object> resultList = objectMapper.convertValue(result, new TypeReference<>() {
|
||||
});
|
||||
final Object oAnnotations = resultList.get(fieldMap.get("_annotations"));
|
||||
final Object oMetadata = resultList.get(fieldMap.get("_metadata"));
|
||||
final Map<String, Object> annotations = oAnnotations == null ? null : objectMapper.convertValue(oAnnotations, new TypeReference<>() {
|
||||
});
|
||||
final Map<String, Object> metadata = oMetadata == null ? null : objectMapper.convertValue(oMetadata, new TypeReference<>() {
|
||||
});
|
||||
|
||||
final Map<String, Object> fields = new HashMap<>();
|
||||
if (request.getFields() != null) {
|
||||
for (final String field : request.getFields().keySet()) {
|
||||
fields.put(field, resultList.get(fieldMap.get(field)));
|
||||
}
|
||||
}
|
||||
|
||||
return Document.builder()
|
||||
.uid((String) resultList.get(fieldMap.get("_uid")))
|
||||
.annotations(annotations)
|
||||
.metadata(metadata)
|
||||
.fields(fields.isEmpty() ? null : fields)
|
||||
.build();
|
||||
}
|
||||
|
||||
List<Document> mapDocuments(List<Object> results, StorageGet request) {
|
||||
return results.stream().map(doc -> mapDocument(doc, request)).toList();
|
||||
}
|
||||
|
||||
Map<String, Integer> buildFieldMap(StorageGet request) {
|
||||
final Map<String, Integer> fieldsMap = new HashMap<>(Map.of(
|
||||
"_uid", 0,
|
||||
"_annotations", 1,
|
||||
"_metadata", 2
|
||||
));
|
||||
|
||||
if (request.getFields() != null) {
|
||||
Integer i = 3;
|
||||
for (String field : request.getFields().keySet()) {
|
||||
fieldsMap.put(field, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return fieldsMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
package fr.codeanddata.semrack.storage.postgres.storage;
|
||||
|
||||
import fr.codeanddata.semrack.core.SemdocStorage;
|
||||
import fr.codeanddata.semrack.core.models.SemrackDocument;
|
||||
import fr.codeanddata.semrack.core.services.SemrackLookupService;
|
||||
import fr.codeanddata.semrack.core.utils.UIDGenerator;
|
||||
import fr.codeanddata.semrack.storage.postgres.entities.SemrackDocumentEntity;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ApplicationScoped
|
||||
public class SemdocJpaStorage implements SemdocStorage, PanacheRepository<SemrackDocumentEntity> {
|
||||
|
||||
@Inject
|
||||
UIDGenerator generator;
|
||||
|
||||
@Inject
|
||||
SemrackLookupService lookupService;
|
||||
|
||||
@Override
|
||||
@WithSession
|
||||
public Uni<SemrackDocument> get(String uid) {
|
||||
return find("uid = ?1", uid)
|
||||
.firstResult().map(d -> Optional.ofNullable(d).map(SemrackDocumentEntity::getDocument).orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@WithSession
|
||||
public Uni<List<SemrackDocument>> get(List<String> uids) {
|
||||
return find("uid in ?1", uids).list()
|
||||
.map(d -> d.stream().map(SemrackDocumentEntity::getDocument).toList());
|
||||
}
|
||||
|
||||
@WithTransaction
|
||||
@Override
|
||||
public Uni<SemrackDocument> storeDocument(SemrackDocument document) {
|
||||
if (document.getUid() == null) {
|
||||
return createDocument(document);
|
||||
} else {
|
||||
return find("uid = ?1", document.getUid())
|
||||
.count()
|
||||
.chain(n -> n == 0 ? createDocument(document) : updateDocument(document));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO err : handle existing document
|
||||
@WithTransaction
|
||||
Uni<SemrackDocument> createDocument(SemrackDocument document) {
|
||||
final String uid = document.getUid() == null ? generator.apply(document) : document.getUid();
|
||||
document.setUid(uid);
|
||||
final SemrackDocumentEntity entity = SemrackDocumentEntity.builder()
|
||||
.uid(uid)
|
||||
.document(document)
|
||||
.build();
|
||||
return persist(entity).map(SemrackDocumentEntity::getDocument);
|
||||
}
|
||||
|
||||
// TODO err : document not exists
|
||||
@WithTransaction
|
||||
Uni<SemrackDocument> updateDocument(SemrackDocument document) {
|
||||
return update("uid = ?1, document = ?2 WHERE uid = ?1", document.getUid(), document)
|
||||
.map(x -> document);
|
||||
}
|
||||
|
||||
// Uni<SearchResult> search(SearchRequest request) {
|
||||
// final String baseQuery = buildBaseQuery(request);
|
||||
//
|
||||
// final StringBuilder sorting = new StringBuilder();
|
||||
// if (request.getSort() != null && !request.getSort().isEmpty()) {
|
||||
// sorting.append(" ORDER BY ");
|
||||
// sorting.append(String.join(", ", request.getSort().stream().map(sort -> sort.getField() + " " + Optional.ofNullable(sort.getDirection()).orElse(SemrackSortDirection.asc).name()).toList()));
|
||||
// }
|
||||
//
|
||||
// final StringBuilder paginate = new StringBuilder();
|
||||
// if (request.getPaginate() != null) {
|
||||
// final SemrackPagination pagination = request.getPaginate();
|
||||
// final Integer size = pagination.getSize() == null ? 200 : pagination.getSize();
|
||||
// final Integer page = pagination.getPage() == null ? 0 : pagination.getPage();
|
||||
//
|
||||
// paginate.append(" LIMIT ").append(size).append(" OFFSET ").append(size * page);
|
||||
// }
|
||||
//
|
||||
// return getSession()
|
||||
// .chain(s -> {
|
||||
// final SearchResult searchResult = SearchResult.builder().build();
|
||||
// return countDocuments(request)
|
||||
// .invoke(count -> searchResult.setPagination(PaginationInfo.builder()
|
||||
// .page(Optional.ofNullable(request.getPaginate()).map(SemrackPagination::getPage).orElse(0))
|
||||
// .size(Optional.ofNullable(request.getPaginate()).map(SemrackPagination::getSize).orElse(0))
|
||||
// .total(count)
|
||||
// .build()))
|
||||
// .call(() -> s
|
||||
// .createNativeQuery(baseQuery + sorting + paginate, Object.class).getResultList()
|
||||
// .invoke(results -> searchResult.setDocuments(project(request.getFields(), results))))
|
||||
// .map(count -> searchResult);
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// String buildBaseQuery(SearchRequest request) {
|
||||
// final String lookup = lookupService.lookup(request.getFilter());
|
||||
// final String whereClause = lookup.isEmpty() ? "" : " WHERE " + lookup;
|
||||
//
|
||||
// if (request.getFields() == null || request.getFields().isEmpty()) {
|
||||
// return "SELECT document FROM semrack_document" + whereClause;
|
||||
// } else {
|
||||
// return "SELECT " + toJsonbPathExtract(request.getFields()) + " FROM semrack_document" + whereClause;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// String toJsonbPathExtract(List<String> fields) {
|
||||
// return String.join(",", fields.stream().map(field -> {
|
||||
// final String serializedField = "'" + String.join("','", field.split("\\.")) + "'";
|
||||
// return "jsonb_extract_path(document, " + serializedField + ")";
|
||||
// }).toList());
|
||||
// }
|
||||
//
|
||||
// List<SemrackDocument> project(List<String> fields, Object results) {
|
||||
// final List<?> projectedResults = objectMapper.convertValue(results, List.class);
|
||||
// if (fields == null || fields.isEmpty()) {
|
||||
// return projectedResults.stream().map(result -> objectMapper.convertValue(result, SemrackDocument.class)).toList();
|
||||
// } else {
|
||||
// return projectedResults.stream().map(result -> {
|
||||
// final List<Object> row = fields.size() == 1 ? List.of(result) : objectMapper.convertValue(result, new TypeReference<>() {
|
||||
// });
|
||||
// final List<Object> rowMut = new ArrayList<>(row);
|
||||
// final List<String> fieldCp = new ArrayList<>(fields);
|
||||
// final Map<String, Object> document = new HashMap<>();
|
||||
// while (!fieldCp.isEmpty() && !row.isEmpty()) {
|
||||
// final String field = fieldCp.removeFirst();
|
||||
// final Object value = rowMut.removeFirst();
|
||||
// pathMapper.map(field, document, value);
|
||||
// }
|
||||
// return objectMapper.convertValue(document, SemrackDocument.class);
|
||||
// }).toList();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Reference in New Issue
Block a user