@@ -69,28 +69,19 @@ impl Document {
6969 // this is why we pass both varaints to apply_change
7070 let mut changes = Vec :: new ( ) ;
7171
72- let mut offset: i64 = 0 ;
73-
74- for change in & change. changes {
75- let adjusted_change = if offset != 0 && change. range . is_some ( ) {
76- & ChangeParams {
77- text : change. text . clone ( ) ,
78- range : change. range . map ( |range| {
79- let start = u32:: from ( range. start ( ) ) ;
80- let end = u32:: from ( range. end ( ) ) ;
81- TextRange :: new (
82- TextSize :: from ( ( start as i64 + offset) . try_into ( ) . unwrap_or ( 0 ) ) ,
83- TextSize :: from ( ( end as i64 + offset) . try_into ( ) . unwrap_or ( 0 ) ) ,
84- )
85- } ) ,
86- }
87- } else {
88- change
89- } ;
90-
91- changes. extend ( self . apply_change ( adjusted_change, change) ) ;
92-
93- offset += adjusted_change. change_size ( ) ;
72+ let mut change_indices: Vec < usize > = ( 0 ..change. changes . len ( ) ) . collect ( ) ;
73+ change_indices. sort_by ( |& a, & b| {
74+ match ( change. changes [ a] . range , change. changes [ b] . range ) {
75+ ( Some ( range_a) , Some ( range_b) ) => range_b. start ( ) . cmp ( & range_a. start ( ) ) ,
76+ ( Some ( _) , None ) => std:: cmp:: Ordering :: Greater , // full changes will never be sent in a batch so this does not matter
77+ ( None , Some ( _) ) => std:: cmp:: Ordering :: Less ,
78+ ( None , None ) => std:: cmp:: Ordering :: Equal ,
79+ }
80+ } ) ;
81+
82+ // Sort changes by start position and process from last to first to avoid position invalidation
83+ for & idx in & change_indices {
84+ changes. extend ( self . apply_change ( & change. changes [ idx] ) ) ;
9485 }
9586
9687 self . version = change. version ;
@@ -245,11 +236,7 @@ impl Document {
245236 ///
246237 /// * `change`: The range-adjusted change to use for statement changes
247238 /// * `original_change`: The original change to use for text changes (yes, this is a bit confusing, and we might want to refactor this entire thing at some point.)
248- fn apply_change (
249- & mut self ,
250- change : & ChangeParams ,
251- original_change : & ChangeParams ,
252- ) -> Vec < StatementChange > {
239+ fn apply_change ( & mut self , change : & ChangeParams ) -> Vec < StatementChange > {
253240 // if range is none, we have a full change
254241 if change. range . is_none ( ) {
255242 // doesnt matter what change since range is null
@@ -265,7 +252,7 @@ impl Document {
265252
266253 let change_range = change. range . unwrap ( ) ;
267254 let previous_content = self . content . clone ( ) ;
268- let new_content = original_change . apply_to_text ( & self . content ) ;
255+ let new_content = change . apply_to_text ( & self . content ) ;
269256
270257 // we first need to determine the affected range and all affected statements, as well as
271258 // the index of the prev and the next statement, if any. The full affected range is the
@@ -1676,9 +1663,15 @@ mod tests {
16761663 }
16771664
16781665 #[ test]
1679- fn test_content_out_of_sync ( ) {
1666+ fn test_another_issue ( ) {
16801667 let path = PgTPath :: new ( "test.sql" ) ;
1681- let initial_content = "select 1, 2, 2232231313393319 from unknown_users;\n " ;
1668+ let initial_content = r#"
1669+
1670+
1671+
1672+ ALTER TABLE ONLY "public"."campaign_contact_list"
1673+ ADD CONSTRAINT "campaign_contact_list_contact_list_id_fkey" FOREIGN KEY ("contact_list_id") REFERENCES "public"."contact_list"("id") ON UPDATE RESTRICT ON DELETE CASCADE;
1674+ "# ;
16821675
16831676 let mut doc = Document :: new ( initial_content. to_string ( ) , 0 ) ;
16841677
@@ -1687,22 +1680,27 @@ mod tests {
16871680 version : 1 ,
16881681 changes : vec ! [
16891682 ChangeParams {
1690- range: Some ( TextRange :: new( 29 . into( ) , 29 . into( ) ) ) ,
1691- text: "3 " . to_string( ) ,
1683+ range: Some ( TextRange :: new( 31 . into( ) , 39 . into( ) ) ) ,
1684+ text: "journey_node " . to_string( ) ,
16921685 } ,
16931686 ChangeParams {
1694- range: Some ( TextRange :: new( 30 . into( ) , 30 . into( ) ) ) ,
1695- text: "1 " . to_string( ) ,
1687+ range: Some ( TextRange :: new( 74 . into( ) , 82 . into( ) ) ) ,
1688+ text: "journey_node " . to_string( ) ,
16961689 } ,
16971690 ] ,
16981691 } ;
16991692
17001693 let _changes = doc. apply_file_change ( & change1) ;
17011694
1702- assert_eq ! (
1703- doc. content,
1704- "select 1, 2, 223223131339331931 from unknown_users;\n "
1705- ) ;
1695+ let expected_content = r#"
1696+
1697+
1698+
1699+ ALTER TABLE ONLY "public"."journey_node_contact_list"
1700+ ADD CONSTRAINT "journey_node_contact_list_contact_list_id_fkey" FOREIGN KEY ("contact_list_id") REFERENCES "public"."contact_list"("id") ON UPDATE RESTRICT ON DELETE CASCADE;
1701+ "# ;
1702+
1703+ assert_eq ! ( doc. content, expected_content) ;
17061704
17071705 assert_document_integrity ( & doc) ;
17081706 }
0 commit comments