Skip to content

Commit b02a27a

Browse files
committed
fix: Fixed the issue in JdbcChatMemoryRepository where executing saveAll would update the timestamps of all historical messages to the current timestamp.
Signed-off-by: Sun Yuhan <[email protected]> Signed-off-by: Sun Yuhan <[email protected]>
1 parent 1ede664 commit b02a27a

File tree

5 files changed

+20
-9
lines changed

5 files changed

+20
-9
lines changed

memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/HsqldbChatMemoryRepositoryDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class HsqldbChatMemoryRepositoryDialect implements JdbcChatMemoryReposito
2323

2424
@Override
2525
public String getSelectMessagesSql() {
26-
return "SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY timestamp ASC";
26+
return "SELECT content, type, timestamp FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY timestamp ASC";
2727
}
2828

2929
@Override

memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/JdbcChatMemoryRepository.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.time.Instant;
2424
import java.util.ArrayList;
2525
import java.util.List;
26+
import java.util.Map;
27+
import java.util.Optional;
2628
import java.util.concurrent.atomic.AtomicLong;
2729

2830
import org.springframework.ai.chat.memory.ChatMemoryRepository;
@@ -53,6 +55,9 @@ public class JdbcChatMemoryRepository implements ChatMemoryRepository {
5355

5456
private final JdbcChatMemoryRepositoryDialect dialect;
5557

58+
public static final String JDBC_MESSAGE_TS = JdbcChatMemoryRepository.class.getSimpleName()
59+
+ "_message_timestamp";
60+
5661
private JdbcChatMemoryRepository(JdbcTemplate jdbcTemplate, JdbcChatMemoryRepositoryDialect dialect) {
5762
Assert.notNull(jdbcTemplate, "jdbcTemplate cannot be null");
5863
Assert.notNull(dialect, "dialect cannot be null");
@@ -104,11 +109,14 @@ private AddBatchPreparedStatement(String conversationId, List<Message> messages)
104109
@Override
105110
public void setValues(PreparedStatement ps, int i) throws SQLException {
106111
var message = this.messages.get(i);
112+
Long timestamp = Optional.ofNullable(message.getMetadata())
113+
.map(metadata -> (long) metadata.getOrDefault(JDBC_MESSAGE_TS, instantSeq.get()))
114+
.orElse(instantSeq.get());
107115

108116
ps.setString(1, this.conversationId);
109117
ps.setString(2, message.getText());
110118
ps.setString(3, message.getMessageType().name());
111-
ps.setTimestamp(4, new Timestamp(instantSeq.getAndIncrement()));
119+
ps.setTimestamp(4, new Timestamp(timestamp));
112120
}
113121

114122
@Override
@@ -124,15 +132,18 @@ private static class MessageRowMapper implements RowMapper<Message> {
124132
public Message mapRow(ResultSet rs, int i) throws SQLException {
125133
var content = rs.getString(1);
126134
var type = MessageType.valueOf(rs.getString(2));
135+
long timestamp = rs.getLong(3);
136+
137+
Map<String, Object> metadata = Map.of(JDBC_MESSAGE_TS, timestamp);
127138

128139
return switch (type) {
129-
case USER -> new UserMessage(content);
130-
case ASSISTANT -> new AssistantMessage(content);
131-
case SYSTEM -> new SystemMessage(content);
140+
case USER -> UserMessage.builder().text(content).metadata(metadata).build();
141+
case ASSISTANT -> new AssistantMessage(content, metadata);
142+
case SYSTEM -> SystemMessage.builder().text(content).metadata(metadata).build();
132143
// The content is always stored empty for ToolResponseMessages.
133144
// If we want to capture the actual content, we need to extend
134145
// AddBatchPreparedStatement to support it.
135-
case TOOL -> new ToolResponseMessage(List.of());
146+
case TOOL -> new ToolResponseMessage(List.of(), metadata);
136147
};
137148
}
138149

memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/MysqlChatMemoryRepositoryDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class MysqlChatMemoryRepositoryDialect implements JdbcChatMemoryRepositor
2626

2727
@Override
2828
public String getSelectMessagesSql() {
29-
return "SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY `timestamp` DESC LIMIT ?";
29+
return "SELECT content, type, `timestamp` FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY `timestamp` DESC LIMIT ?";
3030
}
3131

3232
@Override

memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/PostgresChatMemoryRepositoryDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class PostgresChatMemoryRepositoryDialect implements JdbcChatMemoryReposi
2626

2727
@Override
2828
public String getSelectMessagesSql() {
29-
return "SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY \"timestamp\"";
29+
return "SELECT content, type, \"timestamp\" FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY \"timestamp\"";
3030
}
3131

3232
@Override

memory/repository/spring-ai-model-chat-memory-repository-jdbc/src/main/java/org/springframework/ai/chat/memory/repository/jdbc/SqlServerChatMemoryRepositoryDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class SqlServerChatMemoryRepositoryDialect implements JdbcChatMemoryRepos
2626

2727
@Override
2828
public String getSelectMessagesSql() {
29-
return "SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY [timestamp] ASC";
29+
return "SELECT content, type, [timestamp] FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY [timestamp] ASC";
3030
}
3131

3232
@Override

0 commit comments

Comments
 (0)