@@ -62,238 +62,6 @@ impl ObjectDiffOperation {
6262 Self { database }
6363 }
6464
65- /// Get the object definition at a specific change
66- fn get_object_at_change (
67- & self ,
68- object_name : & str ,
69- change_id : & str ,
70- ) -> Result < ObjectDefinition , ObjectsTreeError > {
71- info ! (
72- "Getting object '{}' at change ID '{}'" ,
73- object_name, change_id
74- ) ;
75-
76- // Get the change
77- let change = self
78- . database
79- . index ( )
80- . get_change ( change_id)
81- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
82- . ok_or_else ( || {
83- ObjectsTreeError :: SerializationError ( format ! ( "Change '{}' not found" , change_id) )
84- } ) ?;
85-
86- // Find the object in the change's modified or added objects
87- let object_info = change
88- . modified_objects
89- . iter ( )
90- . chain ( change. added_objects . iter ( ) )
91- . find ( |obj| {
92- obj. object_type == VcsObjectType :: MooObject && obj. name == object_name
93- } )
94- . ok_or_else ( || {
95- ObjectsTreeError :: SerializationError ( format ! (
96- "Object '{}' not found in change '{}'" ,
97- object_name, change_id
98- ) )
99- } ) ?;
100-
101- // Get the SHA256 for this specific version
102- let sha256 = self
103- . database
104- . refs ( )
105- . get_ref (
106- VcsObjectType :: MooObject ,
107- object_name,
108- Some ( object_info. version ) ,
109- )
110- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
111- . ok_or_else ( || {
112- ObjectsTreeError :: SerializationError ( format ! (
113- "Object '{}' version {} not found in refs" ,
114- object_name, object_info. version
115- ) )
116- } ) ?;
117-
118- // Get the object content
119- let object_dump = self
120- . database
121- . objects ( )
122- . get ( & sha256)
123- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
124- . ok_or_else ( || {
125- ObjectsTreeError :: SerializationError ( format ! (
126- "Object '{}' content not found" ,
127- object_name
128- ) )
129- } ) ?;
130-
131- // Parse the object definition
132- self . database
133- . objects ( )
134- . parse_object_dump ( & object_dump)
135- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) )
136- }
137-
138- /// Compute the baseline state of an object at a specific point in history
139- /// If baseline_change_id is None, compiles up to (but not including) target_change_id
140- /// If baseline_change_id is Some, compiles up to and including baseline_change_id
141- fn get_baseline_object (
142- & self ,
143- object_name : & str ,
144- target_change_id : & str ,
145- baseline_change_id : Option < & str > ,
146- ) -> Result < Option < ObjectDefinition > , ObjectsTreeError > {
147- info ! (
148- "Computing baseline state for object '{}' (target: {}, baseline: {:?})" ,
149- object_name, target_change_id, baseline_change_id
150- ) ;
151-
152- // Get the change order
153- let change_order = self
154- . database
155- . index ( )
156- . get_change_order ( )
157- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?;
158-
159- // Find the position to stop at
160- let stop_position = if let Some ( baseline_id) = baseline_change_id {
161- // Find the baseline change position and include it
162- change_order
163- . iter ( )
164- . position ( |id| id == baseline_id)
165- . map ( |pos| pos + 1 ) // +1 to include the baseline change
166- . ok_or_else ( || {
167- ObjectsTreeError :: SerializationError ( format ! (
168- "Baseline change '{}' not found in change order" ,
169- baseline_id
170- ) )
171- } ) ?
172- } else {
173- // Find the target change position and exclude it
174- change_order
175- . iter ( )
176- . position ( |id| id == target_change_id)
177- . ok_or_else ( || {
178- ObjectsTreeError :: SerializationError ( format ! (
179- "Target change '{}' not found in change order" ,
180- target_change_id
181- ) )
182- } ) ?
183- } ;
184-
185- info ! ( "Computing baseline state up to position {}" , stop_position) ;
186-
187- // Build state up to stop_position by processing changes chronologically
188- let mut object_state: Option < ( String , u64 ) > = None ; // (name, version)
189- let mut object_exists = false ;
190-
191- for change_id in change_order. iter ( ) . take ( stop_position) {
192- let change = self
193- . database
194- . index ( )
195- . get_change ( change_id)
196- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
197- . ok_or_else ( || {
198- ObjectsTreeError :: SerializationError ( format ! (
199- "Change '{}' not found" ,
200- change_id
201- ) )
202- } ) ?;
203-
204- // Check if object was added
205- if change
206- . added_objects
207- . iter ( )
208- . any ( |obj| obj. object_type == VcsObjectType :: MooObject && obj. name == object_name)
209- {
210- object_state = Some ( ( object_name. to_string ( ) , 1 ) ) ;
211- object_exists = true ;
212- info ! ( "Object '{}' was added in change '{}'" , object_name, change_id) ;
213- }
214-
215- // Check if object was modified
216- if let Some ( obj_info) = change
217- . modified_objects
218- . iter ( )
219- . find ( |obj| obj. object_type == VcsObjectType :: MooObject && obj. name == object_name)
220- {
221- if let Some ( ( name, version) ) = & object_state {
222- object_state = Some ( ( name. clone ( ) , version + 1 ) ) ;
223- } else {
224- // Modified but not seen before, treat as existing
225- object_state = Some ( ( object_name. to_string ( ) , obj_info. version ) ) ;
226- }
227- object_exists = true ;
228- info ! ( "Object '{}' was modified in change '{}'" , object_name, change_id) ;
229- }
230-
231- // Check if object was renamed
232- if let Some ( renamed) = change. renamed_objects . iter ( ) . find ( |r| {
233- r. from . object_type == VcsObjectType :: MooObject && r. from . name == object_name
234- } ) {
235- if let Some ( ( _, version) ) = object_state {
236- object_state = Some ( ( renamed. to . name . clone ( ) , version) ) ;
237- info ! (
238- "Object '{}' was renamed to '{}' in change '{}'" ,
239- object_name, renamed. to. name, change_id
240- ) ;
241- }
242- }
243-
244- // Check if object was deleted
245- if change
246- . deleted_objects
247- . iter ( )
248- . any ( |obj| obj. object_type == VcsObjectType :: MooObject && obj. name == object_name)
249- {
250- object_state = None ;
251- object_exists = false ;
252- info ! ( "Object '{}' was deleted in change '{}'" , object_name, change_id) ;
253- }
254- }
255-
256- // If object doesn't exist at this point, return None
257- if !object_exists || object_state. is_none ( ) {
258- info ! ( "Object '{}' does not exist in baseline state" , object_name) ;
259- return Ok ( None ) ;
260- }
261-
262- let ( final_name, final_version) = object_state. unwrap ( ) ;
263-
264- // Get the object at this state
265- let sha256 = self
266- . database
267- . refs ( )
268- . get_ref ( VcsObjectType :: MooObject , & final_name, Some ( final_version) )
269- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
270- . ok_or_else ( || {
271- ObjectsTreeError :: SerializationError ( format ! (
272- "Baseline object '{}' version {} not found in refs" ,
273- final_name, final_version
274- ) )
275- } ) ?;
276-
277- let object_dump = self
278- . database
279- . objects ( )
280- . get ( & sha256)
281- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
282- . ok_or_else ( || {
283- ObjectsTreeError :: SerializationError ( format ! (
284- "Baseline object '{}' content not found" ,
285- final_name
286- ) )
287- } ) ?;
288-
289- let object_def = self
290- . database
291- . objects ( )
292- . parse_object_dump ( & object_dump)
293- . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?;
294-
295- Ok ( Some ( object_def) )
296- }
29765
29866 /// Compute verb-level diff using Myers algorithm
29967 fn compute_verb_diff ( & self , old_lines : & [ String ] , new_lines : & [ String ] ) -> Vec < DiffLine > {
@@ -443,38 +211,44 @@ impl ObjectDiffOperation {
443211 ) ;
444212 }
445213
446- // Get the target object state
447- let target_obj = self . get_object_at_change ( & request. object_name , & target_change_id) ?;
214+ // Get the change to find the object version
215+ let change = self
216+ . database
217+ . index ( )
218+ . get_change ( & target_change_id)
219+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
220+ . ok_or_else ( || {
221+ ObjectsTreeError :: SerializationError ( format ! (
222+ "Change '{}' not found" ,
223+ target_change_id
224+ ) )
225+ } ) ?;
226+
227+ // Find the object in the change
228+ let object_info = change
229+ . modified_objects
230+ . iter ( )
231+ . chain ( change. added_objects . iter ( ) )
232+ . find ( |obj| {
233+ obj. object_type == VcsObjectType :: MooObject && obj. name == request. object_name
234+ } )
235+ . ok_or_else ( || {
236+ ObjectsTreeError :: SerializationError ( format ! (
237+ "Object '{}' not found in change '{}'" ,
238+ request. object_name, target_change_id
239+ ) )
240+ } ) ?;
448241
449- // Get the baseline object state
450- let baseline_obj = self . get_baseline_object (
242+ // Use compare_object_versions to get the correct diff (same as change/status)
243+ use crate :: object_diff:: compare_object_versions;
244+ let object_change = compare_object_versions (
245+ & self . database ,
451246 & request. object_name ,
452- & target_change_id,
453- baseline_change_id. as_deref ( ) ,
247+ object_info. version ,
248+ Some ( & change. verb_rename_hints ) ,
249+ Some ( & change. property_rename_hints ) ,
454250 ) ?;
455251
456- // Use object_diff to identify which verbs changed
457- let mut object_change = ObjectChange :: new ( request. object_name . clone ( ) ) ;
458-
459- if let Some ( ref baseline) = baseline_obj {
460- compare_object_definitions_with_meta (
461- baseline,
462- & target_obj,
463- & mut object_change,
464- None ,
465- None ,
466- None ,
467- None ,
468- ) ;
469- } else {
470- // No baseline - all verbs are new
471- for verb in & target_obj. verbs {
472- if let Some ( first_name) = verb. names . first ( ) {
473- object_change. verbs_added . insert ( first_name. as_string ( ) ) ;
474- }
475- }
476- }
477-
478252 info ! (
479253 "Found {} modified verbs, {} added verbs, {} deleted verbs, {} renamed verbs" ,
480254 object_change. verbs_modified. len( ) ,
@@ -483,6 +257,75 @@ impl ObjectDiffOperation {
483257 object_change. verbs_renamed. len( )
484258 ) ;
485259
260+ // Get the target object definition for decompiling verbs
261+ let target_sha256 = self
262+ . database
263+ . refs ( )
264+ . get_ref (
265+ VcsObjectType :: MooObject ,
266+ & request. object_name ,
267+ Some ( object_info. version ) ,
268+ )
269+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
270+ . ok_or_else ( || {
271+ ObjectsTreeError :: SerializationError ( format ! (
272+ "Object '{}' version {} not found in refs" ,
273+ request. object_name, object_info. version
274+ ) )
275+ } ) ?;
276+
277+ let target_content = self
278+ . database
279+ . objects ( )
280+ . get ( & target_sha256)
281+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
282+ . ok_or_else ( || {
283+ ObjectsTreeError :: SerializationError ( format ! (
284+ "Object '{}' content not found" ,
285+ request. object_name
286+ ) )
287+ } ) ?;
288+
289+ let target_obj = self
290+ . database
291+ . objects ( )
292+ . parse_object_dump ( & target_content)
293+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?;
294+
295+ // Get baseline object if there's a previous version
296+ let baseline_version = object_info. version . saturating_sub ( 1 ) ;
297+ let baseline_obj = if baseline_version > 0 {
298+ let baseline_sha256 = self
299+ . database
300+ . refs ( )
301+ . get_ref ( VcsObjectType :: MooObject , & request. object_name , Some ( baseline_version) )
302+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?;
303+
304+ if let Some ( sha256) = baseline_sha256 {
305+ let baseline_content = self
306+ . database
307+ . objects ( )
308+ . get ( & sha256)
309+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?
310+ . ok_or_else ( || {
311+ ObjectsTreeError :: SerializationError ( format ! (
312+ "Baseline object content not found"
313+ ) )
314+ } ) ?;
315+
316+ Some (
317+ self . database
318+ . objects ( )
319+ . parse_object_dump ( & baseline_content)
320+ . map_err ( |e| ObjectsTreeError :: SerializationError ( e. to_string ( ) ) ) ?,
321+ )
322+ } else {
323+ None
324+ }
325+ } else {
326+ None
327+ } ;
328+
486329 // Build the response with verb diffs
487330 let mut verb_changes = Vec :: new ( ) ;
488331
0 commit comments