From e3db529c97d51c370c9045d8e9ec275e594c5fed Mon Sep 17 00:00:00 2001 From: HuitaePark Date: Wed, 29 Jul 2026 10:12:30 +0900 Subject: [PATCH] Preserve Oracle vector store metadata Serialize OracleJsonValue metadata when re-adding documents returned by OracleVectorStore. Add an integration test covering the metadata retrieve-and-add round trip. Fixes #3838 Signed-off-by: HuitaePark --- .../vectorstore/oracle/OracleVectorStore.java | 3 ++ .../oracle/OracleVectorStoreIT.java | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java b/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java index c4a4821995..76f67a49ed 100644 --- a/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java +++ b/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java @@ -231,6 +231,9 @@ else if (o instanceof Double) { else if (o instanceof Boolean) { gen.write(key, (Boolean) o); } + else if (o instanceof OracleJsonValue oracleJsonValue) { + gen.write(key, oracleJsonValue); + } } gen.writeEnd(); } diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java index 98ada06842..e945b813a1 100644 --- a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java @@ -31,6 +31,7 @@ import javax.sql.DataSource; import oracle.jdbc.pool.OracleDataSource; +import oracle.sql.json.OracleJsonValue; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -289,6 +290,49 @@ public void documentUpdate(String distanceType) { }); } + @Test + void shouldPreserveMetadataWhenRetrievedDocumentIsAddedAgain() { + this.contextRunner + .withPropertyValues("test.spring.ai.vectorstore.oracle.distanceType=COSINE", + "test.spring.ai.vectorstore.oracle.searchAccuracy=" + OracleVectorStore.DEFAULT_SEARCH_ACCURACY) + .run(context -> { + VectorStore vectorStore = context.getBean(VectorStore.class); + + Document original = new Document(UUID.randomUUID().toString(), "Spring AI Oracle metadata round trip", + Map.of("conversationId", "conversation-123")); + + vectorStore.add(List.of(original)); + + SearchRequest searchRequest = SearchRequest.builder() + .query("Spring AI Oracle metadata round trip") + .topK(1) + .similarityThresholdAll() + .build(); + + List firstResults = vectorStore.similaritySearch(searchRequest); + + assertThat(firstResults).hasSize(1); + + Document retrieved = firstResults.get(0); + + assertThat(retrieved.getId()).isEqualTo(original.getId()); + assertThat(retrieved.getMetadata().get("conversationId")).isInstanceOfSatisfying(OracleJsonValue.class, + value -> assertThat(value.asJsonString().getString()).isEqualTo("conversation-123")); + + // Re-add the document returned by OracleVectorStore. + vectorStore.add(List.of(retrieved)); + + List secondResults = vectorStore.similaritySearch(searchRequest); + + assertThat(secondResults).hasSize(1); + assertThat(secondResults.get(0).getMetadata().get("conversationId")).isInstanceOfSatisfying( + OracleJsonValue.class, + value -> assertThat(value.asJsonString().getString()).isEqualTo("conversation-123")); + + dropTable(context, ((OracleVectorStore) vectorStore).getTableName()); + }); + } + @ParameterizedTest(name = "{0} : {displayName} ") @ValueSource(strings = { "COSINE", "DOT" }) public void searchWithThreshold(String distanceType) {