git_semantic/index/
mod.rs1mod builder;
2mod error;
3mod storage;
4
5pub use builder::IndexBuilder;
6pub use error::IndexError;
7pub use storage::IndexStorage;
8
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11
12use crate::git::CommitInfo;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct IndexEntry {
16 pub commit: CommitInfo,
17 pub embedding: Vec<f32>, }
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct IndexMetadata {
22 pub created_at: DateTime<Utc>,
23 pub updated_at: DateTime<Utc>,
24 pub total_commits: usize,
25 pub include_diffs: bool,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct SemanticIndex {
30 pub entries: Vec<IndexEntry>,
31 pub model_version: String,
32 pub last_commit: String,
33 pub metadata: IndexMetadata,
34}
35
36impl SemanticIndex {
37 pub fn new(model_version: String, last_commit: String, include_diffs: bool) -> Self {
38 let now = Utc::now();
39 Self {
40 entries: Vec::new(),
41 model_version,
42 last_commit,
43 metadata: IndexMetadata {
44 created_at: now,
45 updated_at: now,
46 total_commits: 0,
47 include_diffs,
48 },
49 }
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use crate::git::CommitInfo;
57
58 #[test]
59 fn test_semantic_index_new() {
60 let index =
61 SemanticIndex::new("bge-small-en-v1.5".to_string(), "abc1234".to_string(), true);
62 assert_eq!(index.model_version, "bge-small-en-v1.5");
63 assert_eq!(index.last_commit, "abc1234");
64 assert!(index.entries.is_empty());
65 assert_eq!(index.metadata.total_commits, 0);
66 assert!(index.metadata.include_diffs);
67 }
68
69 #[test]
70 fn test_semantic_index_quick_mode() {
71 let index = SemanticIndex::new(
72 "bge-small-en-v1.5".to_string(),
73 "abc1234".to_string(),
74 false,
75 );
76 assert!(!index.metadata.include_diffs);
77 }
78
79 #[test]
80 fn test_semantic_index_timestamps_are_set() {
81 let before = Utc::now();
82 let index = SemanticIndex::new("model".to_string(), "hash".to_string(), true);
83 let after = Utc::now();
84 assert!(index.metadata.created_at >= before && index.metadata.created_at <= after);
85 assert!(index.metadata.updated_at >= before && index.metadata.updated_at <= after);
86 }
87
88 #[test]
89 fn test_index_entry_serialization_roundtrip() {
90 let entry = IndexEntry {
91 commit: CommitInfo {
92 hash: "abc1234".to_string(),
93 author: "Alice".to_string(),
94 date: chrono::DateTime::parse_from_rfc3339("2024-06-15T12:00:00Z")
95 .unwrap()
96 .with_timezone(&Utc),
97 message: "test commit".to_string(),
98 diff_summary: "+added line".to_string(),
99 },
100 embedding: vec![0.1, 0.2, 0.3],
101 };
102
103 let mut index = SemanticIndex::new("model".to_string(), "abc1234".to_string(), true);
104 index.entries.push(entry);
105 index.metadata.total_commits = 1;
106
107 let serialized = bincode::serialize(&index).unwrap();
108 let deserialized: SemanticIndex = bincode::deserialize(&serialized).unwrap();
109
110 assert_eq!(deserialized.entries.len(), 1);
111 assert_eq!(deserialized.entries[0].commit.hash, "abc1234");
112 assert_eq!(deserialized.entries[0].commit.author, "Alice");
113 assert_eq!(deserialized.entries[0].embedding, vec![0.1, 0.2, 0.3]);
114 assert_eq!(deserialized.model_version, "model");
115 assert_eq!(deserialized.metadata.total_commits, 1);
116 assert!(deserialized.metadata.include_diffs);
117 }
118}