feat(search): implement NlSearchController with @WebMvcTest tests (7 cases)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-06 15:58:35 +02:00
parent 3af1095d13
commit 70e8a6e6ad
4 changed files with 195 additions and 2 deletions

View File

@@ -78,4 +78,8 @@ public class DomainException extends RuntimeException {
public static DomainException tooManyRequests(ErrorCode code, String message, long retryAfterSeconds) {
return new DomainException(code, HttpStatus.TOO_MANY_REQUESTS, message, retryAfterSeconds);
}
public static DomainException serviceUnavailable(ErrorCode code, String message) {
return new DomainException(code, HttpStatus.SERVICE_UNAVAILABLE, message);
}
}

View File

@@ -0,0 +1,28 @@
package org.raddatz.familienarchiv.search;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.raddatz.familienarchiv.security.Permission;
import org.raddatz.familienarchiv.security.RequirePermission;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/search/nl")
@RequiredArgsConstructor
public class NlSearchController {
private final NlQueryParserService nlQueryParserService;
private final NlSearchRateLimiter rateLimiter;
@PostMapping
@RequirePermission(Permission.READ_ALL)
public NlSearchResponse search(@Valid @RequestBody NlSearchRequest request,
Pageable pageable,
@AuthenticationPrincipal UserDetails principal) {
rateLimiter.checkAndConsume(principal.getUsername());
return nlQueryParserService.search(request.query(), pageable);
}
}

View File

@@ -88,7 +88,7 @@ public class RestClientOllamaClient implements OllamaClient, OllamaHealthClient
throw e;
} catch (Exception e) {
log.warn("Ollama inference failed: {}", e.getClass().getSimpleName());
throw DomainException.tooManyRequests(ErrorCode.SMART_SEARCH_UNAVAILABLE,
throw DomainException.serviceUnavailable(ErrorCode.SMART_SEARCH_UNAVAILABLE,
"Ollama unavailable: " + e.getClass().getSimpleName());
}
}
@@ -114,7 +114,7 @@ public class RestClientOllamaClient implements OllamaClient, OllamaHealthClient
return toExtraction(raw, rawQuery);
} catch (Exception e) {
log.warn("Failed to parse Ollama response: {}", e.getClass().getSimpleName());
throw DomainException.tooManyRequests(ErrorCode.SMART_SEARCH_UNAVAILABLE,
throw DomainException.serviceUnavailable(ErrorCode.SMART_SEARCH_UNAVAILABLE,
"Failed to parse Ollama response: " + e.getClass().getSimpleName());
}
}