@@ -69,28 +69,19 @@ impl Document {
69
69
// this is why we pass both varaints to apply_change
70
70
let mut changes = Vec :: new ( ) ;
71
71
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] ) ) ;
94
85
}
95
86
96
87
self . version = change. version ;
@@ -245,11 +236,7 @@ impl Document {
245
236
///
246
237
/// * `change`: The range-adjusted change to use for statement changes
247
238
/// * `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 > {
253
240
// if range is none, we have a full change
254
241
if change. range . is_none ( ) {
255
242
// doesnt matter what change since range is null
@@ -265,7 +252,7 @@ impl Document {
265
252
266
253
let change_range = change. range . unwrap ( ) ;
267
254
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 ) ;
269
256
270
257
// we first need to determine the affected range and all affected statements, as well as
271
258
// the index of the prev and the next statement, if any. The full affected range is the
@@ -1676,9 +1663,15 @@ mod tests {
1676
1663
}
1677
1664
1678
1665
#[ test]
1679
- fn test_content_out_of_sync ( ) {
1666
+ fn test_another_issue ( ) {
1680
1667
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
+ "# ;
1682
1675
1683
1676
let mut doc = Document :: new ( initial_content. to_string ( ) , 0 ) ;
1684
1677
@@ -1687,22 +1680,27 @@ mod tests {
1687
1680
version : 1 ,
1688
1681
changes : vec ! [
1689
1682
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( ) ,
1692
1685
} ,
1693
1686
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( ) ,
1696
1689
} ,
1697
1690
] ,
1698
1691
} ;
1699
1692
1700
1693
let _changes = doc. apply_file_change ( & change1) ;
1701
1694
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) ;
1706
1704
1707
1705
assert_document_integrity ( & doc) ;
1708
1706
}
0 commit comments