추세검색 설정 수정
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
package com.goldenchart.service;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.goldenchart.dto.TrendSearchRequest;
|
||||
import com.goldenchart.dto.TrendSearchResultDto;
|
||||
import com.goldenchart.dto.TrendSearchResultsResponse;
|
||||
import com.goldenchart.entity.GcAppSettings;
|
||||
import com.goldenchart.entity.GcTrendSearchSnapshot;
|
||||
import com.goldenchart.repository.GcAppSettingsRepository;
|
||||
import com.goldenchart.repository.GcTrendSearchSnapshotRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TrendSearchSnapshotService {
|
||||
|
||||
private static final TypeReference<List<TrendSearchResultDto>> RESULT_LIST_TYPE = new TypeReference<>() {};
|
||||
|
||||
private final GcTrendSearchSnapshotRepository snapshotRepo;
|
||||
private final GcAppSettingsRepository appSettingsRepo;
|
||||
private final TrendSearchService trendSearchService;
|
||||
private final TrendSearchSettingsHelper settingsHelper;
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public TrendSearchResultsResponse getResults(Long userId, String deviceId) {
|
||||
String scopeKey = TrendSearchScope.key(userId, deviceId);
|
||||
return snapshotRepo.findById(scopeKey)
|
||||
.map(this::toResponse)
|
||||
.orElse(TrendSearchResultsResponse.empty());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<TrendSearchResultDto> scanAndPersist(Long userId, String deviceId, TrendSearchRequest request) {
|
||||
GcAppSettings app = findAppSettings(userId, deviceId);
|
||||
TrendSearchRequest req = app != null
|
||||
? settingsHelper.mergeRequestWithSettings(request, app)
|
||||
: (request != null ? request : new TrendSearchRequest());
|
||||
List<TrendSearchResultDto> results = trendSearchService.scan(req);
|
||||
persist(scopeKey(userId, deviceId), userId, deviceId, req, results);
|
||||
return results;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void runScheduledScan(Long userId, String deviceId) {
|
||||
String scopeKey = TrendSearchScope.key(userId, deviceId);
|
||||
GcAppSettings app = findAppSettings(userId, deviceId);
|
||||
if (app == null) return;
|
||||
|
||||
TrendSearchRequest last = snapshotRepo.findById(scopeKey)
|
||||
.map(s -> settingsHelper.parseRequestJson(s.getRequestJson()))
|
||||
.orElse(null);
|
||||
TrendSearchRequest req = settingsHelper.buildRequest(app, last);
|
||||
List<TrendSearchResultDto> results = trendSearchService.scan(req);
|
||||
persist(scopeKey, userId, deviceId, req, results);
|
||||
log.debug("[TrendSearch] scheduled scan scope={} count={}", scopeKey, results.size());
|
||||
}
|
||||
|
||||
private void persist(String scopeKey, Long userId, String deviceId,
|
||||
TrendSearchRequest req, List<TrendSearchResultDto> results) {
|
||||
try {
|
||||
String resultsJson = mapper.writeValueAsString(results != null ? results : Collections.emptyList());
|
||||
String requestJson = mapper.writeValueAsString(req);
|
||||
GcTrendSearchSnapshot snap = snapshotRepo.findById(scopeKey).orElseGet(() ->
|
||||
GcTrendSearchSnapshot.builder().scopeKey(scopeKey).build());
|
||||
snap.setUserId(userId);
|
||||
snap.setDeviceId(deviceId);
|
||||
snap.setTimeframe(req.getTimeframe() != null ? req.getTimeframe() : "1d");
|
||||
snap.setScannedAt(LocalDateTime.now());
|
||||
snap.setRequestJson(requestJson);
|
||||
snap.setResultsJson(resultsJson);
|
||||
snapshotRepo.save(snap);
|
||||
} catch (Exception e) {
|
||||
log.warn("[TrendSearch] persist failed scope={}: {}", scopeKey, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private TrendSearchResultsResponse toResponse(GcTrendSearchSnapshot snap) {
|
||||
List<TrendSearchResultDto> list = Collections.emptyList();
|
||||
try {
|
||||
if (snap.getResultsJson() != null && !snap.getResultsJson().isBlank()) {
|
||||
list = mapper.readValue(snap.getResultsJson(), RESULT_LIST_TYPE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("[TrendSearch] deserialize results scope={}: {}", snap.getScopeKey(), e.getMessage());
|
||||
}
|
||||
Instant scannedAt = snap.getScannedAt() != null
|
||||
? snap.getScannedAt().atZone(ZoneId.systemDefault()).toInstant()
|
||||
: null;
|
||||
return TrendSearchResultsResponse.builder()
|
||||
.results(list)
|
||||
.timeframe(snap.getTimeframe())
|
||||
.scannedAt(scannedAt)
|
||||
.build();
|
||||
}
|
||||
|
||||
private GcAppSettings findAppSettings(Long userId, String deviceId) {
|
||||
if (userId != null) {
|
||||
return appSettingsRepo.findByUserId(userId).orElse(null);
|
||||
}
|
||||
if (deviceId != null && !deviceId.isBlank()) {
|
||||
return appSettingsRepo.findByDeviceId(deviceId).orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String scopeKey(Long userId, String deviceId) {
|
||||
return TrendSearchScope.key(userId, deviceId);
|
||||
}
|
||||
|
||||
/** 스케줄러: 마지막 스캔 시각 (없으면 epoch) */
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<LocalDateTime> lastScannedAt(Long userId, String deviceId) {
|
||||
return snapshotRepo.findById(TrendSearchScope.key(userId, deviceId))
|
||||
.map(GcTrendSearchSnapshot::getScannedAt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user