Newer
Older
book-metadata-service / src / main / java / ru / mcs / metadatabook / service / PivotIndexService.java
package ru.mcs.metadatabook.service;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.mcs.metadatabook.entity.MtData;
import ru.mcs.metadatabook.entity.MtField;
import ru.mcs.metadatabook.entity.MtFieldHistory;
import ru.mcs.metadatabook.entity.MtIndex;
import ru.mcs.metadatabook.repository.MtIndexRepository;

import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;

/**
 * Синхронизация типизированных индексов (mt_indexes) и истории изменений (mt_field_history)
 * при записи/обновлении mt_data. Вызывается из BookWriteService после каждого сохранения.
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PivotIndexService {

    @PersistenceContext
    private EntityManager entityManager;

    private final MtIndexRepository indexRepository;

    @Transactional
    public void syncIndexes(MtData data, List<MtField> indexedFields) {
        Integer orgId = data.getOrgId();
        UUID guid = data.getGuid();

        indexRepository.deleteByOrgIdAndGuid(orgId, guid);

        for (MtField field : indexedFields) {
            String value = data.getValue(field.getFieldNum());
            if (value == null || value.isBlank()) continue;

            MtIndex index = MtIndex.builder()
                    .orgId(orgId)
                    .objId(data.getObjId())
                    .fieldNum(field.getFieldNum())
                    .guid(guid)
                    .build();

            populateIndexValue(index, field.getDataType(), value);
            entityManager.persist(index);
        }
    }

    /**
     * Пишет запись в историю, если значение слота реально изменилось.
     * Вызывать ДО применения нового значения в MtData (нужен oldValue).
     */
    @Transactional
    public void recordHistoryIfChanged(MtData data, int fieldNum, String newValue, String dataType) {
        String oldValue = data.getValue(fieldNum);
        if (java.util.Objects.equals(oldValue, newValue)) {
            return;
        }

        MtFieldHistory history = MtFieldHistory.builder()
                .orgId(data.getOrgId())
                .objId(data.getObjId())
                .guid(data.getGuid())
                .fieldNum(fieldNum)
                .oldValue(oldValue)
                .newValue(newValue)
                .dataType(dataType)
                .changedAt(OffsetDateTime.now())
                .build();

        entityManager.persist(history);
    }

    private void populateIndexValue(MtIndex index, String dataType, String value) {
        switch (dataType) {
            case "text", "email", "url", "phone", "picklist", "lookup" ->
                    index.setStringValue(value.toLowerCase().trim());
            case "number", "currency", "percent" -> {
                try {
                    index.setNumValue(new BigDecimal(value));
                } catch (NumberFormatException e) {
                    log.warn("Invalid number value for index: {}", value);
                }
            }
            case "date", "datetime" -> {
                try {
                    index.setDateValue(OffsetDateTime.parse(value));
                } catch (Exception e) {
                    log.warn("Invalid date value for index: {}", value);
                }
            }
            default -> index.setStringValue(value.toLowerCase().trim());
        }
    }
}