@@ -65,6 +65,8 @@ impl Document {
65
65
66
66
// when we recieive more than one change, we need to push back the changes based on the
67
67
// total range of the previous ones. This is because the ranges are always related to the original state.
68
+ // BUT: only for the statement range changes, not for the text changes
69
+ // this is why we pass both varaints to apply_change
68
70
let mut changes = Vec :: new ( ) ;
69
71
70
72
let mut offset: i64 = 0 ;
@@ -86,9 +88,9 @@ impl Document {
86
88
change
87
89
} ;
88
90
89
- changes. extend ( self . apply_change ( adjusted_change) ) ;
91
+ changes. extend ( self . apply_change ( adjusted_change, change ) ) ;
90
92
91
- offset += change . change_size ( ) ;
93
+ offset += adjusted_change . change_size ( ) ;
92
94
}
93
95
94
96
self . version = change. version ;
@@ -240,9 +242,17 @@ impl Document {
240
242
}
241
243
242
244
/// Applies a single change to the document and returns the affected statements
243
- fn apply_change ( & mut self , change : & ChangeParams ) -> Vec < StatementChange > {
245
+ ///
246
+ /// * `change`: The range-adjusted change to use for statement changes
247
+ /// * `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 > {
244
253
// if range is none, we have a full change
245
254
if change. range . is_none ( ) {
255
+ // doesnt matter what change since range is null
246
256
return self . apply_full_change ( change) ;
247
257
}
248
258
@@ -255,7 +265,7 @@ impl Document {
255
265
256
266
let change_range = change. range . unwrap ( ) ;
257
267
let previous_content = self . content . clone ( ) ;
258
- let new_content = change . apply_to_text ( & self . content ) ;
268
+ let new_content = original_change . apply_to_text ( & self . content ) ;
259
269
260
270
// we first need to determine the affected range and all affected statements, as well as
261
271
// the index of the prev and the next statement, if any. The full affected range is the
@@ -1560,28 +1570,29 @@ mod tests {
1560
1570
fn multiple_deletions_at_once ( ) {
1561
1571
let path = PgTPath :: new ( "test.sql" ) ;
1562
1572
1563
- let mut doc = Document :: new ( "\n \n \n \n ALTER TABLE ONLY \" public\" .\" sendout\" \n ADD CONSTRAINT \" sendout_organisation_id_fkey\" FOREIGN
1564
- KEY (\" organisation_id\" ) REFERENCES \" public\" .\" organisation\" (\" id\" ) ON UPDATE RESTRICT ON DELETE CASCADE;\n " . to_string ( ) , 0 ) ;
1573
+ let mut doc = Document :: new ( "ALTER TABLE ONLY public.omni_channel_message ADD CONSTRAINT omni_channel_message_organisation_id_fkey FOREIGN KEY (organisation_id) REFERENCES public.organisation(id) ON UPDATE RESTRICT ON DELETE CASCADE;" . to_string ( ) , 0 ) ;
1565
1574
1566
1575
let change = ChangeFileParams {
1567
1576
path : path. clone ( ) ,
1568
1577
version : 1 ,
1569
1578
changes : vec ! [
1570
1579
ChangeParams {
1571
- range: Some ( TextRange :: new( 31 . into( ) , 38 . into( ) ) ) ,
1572
- text: "te " . to_string( ) ,
1580
+ range: Some ( TextRange :: new( 60 . into( ) , 80 . into( ) ) ) ,
1581
+ text: "sendout " . to_string( ) ,
1573
1582
} ,
1574
1583
ChangeParams {
1575
- range: Some ( TextRange :: new( 60 . into( ) , 67 . into( ) ) ) ,
1576
- text: "te " . to_string( ) ,
1584
+ range: Some ( TextRange :: new( 24 . into( ) , 44 . into( ) ) ) ,
1585
+ text: "sendout " . to_string( ) ,
1577
1586
} ,
1578
1587
] ,
1579
1588
} ;
1580
1589
1581
1590
let changed = doc. apply_file_change ( & change) ;
1582
1591
1583
- assert_eq ! ( doc. content, "\n \n \n \n ALTER TABLE ONLY \" public\" .\" te\" \n ADD CONSTRAINT \" te_organisation_id_fkey\" FOREIGN
1584
- KEY (\" organisation_id\" ) REFERENCES \" public\" .\" organisation\" (\" id\" ) ON UPDATE RESTRICT ON DELETE CASCADE;\n " ) ;
1592
+ assert_eq ! (
1593
+ doc. content,
1594
+ "ALTER TABLE ONLY public.sendout ADD CONSTRAINT sendout_organisation_id_fkey FOREIGN KEY (organisation_id) REFERENCES public.organisation(id) ON UPDATE RESTRICT ON DELETE CASCADE;"
1595
+ ) ;
1585
1596
1586
1597
assert_eq ! ( changed. len( ) , 2 ) ;
1587
1598
@@ -1592,28 +1603,29 @@ KEY (\"organisation_id\") REFERENCES \"public\".\"organisation\"(\"id\") ON UPDA
1592
1603
fn multiple_additions_at_once ( ) {
1593
1604
let path = PgTPath :: new ( "test.sql" ) ;
1594
1605
1595
- let mut doc = Document :: new ( "\n \n \n \n ALTER TABLE ONLY \" public\" .\" sendout\" \n ADD CONSTRAINT \" sendout_organisation_id_fkey\" FOREIGN
1596
- KEY (\" organisation_id\" ) REFERENCES \" public\" .\" organisation\" (\" id\" ) ON UPDATE RESTRICT ON DELETE CASCADE;\n " . to_string ( ) , 0 ) ;
1606
+ let mut doc = Document :: new ( "ALTER TABLE ONLY public.sendout ADD CONSTRAINT sendout_organisation_id_fkey FOREIGN KEY (organisation_id) REFERENCES public.organisation(id) ON UPDATE RESTRICT ON DELETE CASCADE;" . to_string ( ) , 0 ) ;
1597
1607
1598
1608
let change = ChangeFileParams {
1599
1609
path : path. clone ( ) ,
1600
1610
version : 1 ,
1601
1611
changes : vec ! [
1602
1612
ChangeParams {
1603
- range: Some ( TextRange :: new( 31 . into( ) , 38 . into( ) ) ) ,
1613
+ range: Some ( TextRange :: new( 47 . into( ) , 54 . into( ) ) ) ,
1604
1614
text: "omni_channel_message" . to_string( ) ,
1605
1615
} ,
1606
1616
ChangeParams {
1607
- range: Some ( TextRange :: new( 60 . into( ) , 67 . into( ) ) ) ,
1617
+ range: Some ( TextRange :: new( 24 . into( ) , 31 . into( ) ) ) ,
1608
1618
text: "omni_channel_message" . to_string( ) ,
1609
1619
} ,
1610
1620
] ,
1611
1621
} ;
1612
1622
1613
1623
let changed = doc. apply_file_change ( & change) ;
1614
1624
1615
- assert_eq ! ( doc. content, "\n \n \n \n ALTER TABLE ONLY \" public\" .\" omni_channel_message\" \n ADD CONSTRAINT \" omni_channel_message_organisation_id_fkey\" FOREIGN
1616
- KEY (\" organisation_id\" ) REFERENCES \" public\" .\" organisation\" (\" id\" ) ON UPDATE RESTRICT ON DELETE CASCADE;\n " ) ;
1625
+ assert_eq ! (
1626
+ doc. content,
1627
+ "ALTER TABLE ONLY public.omni_channel_message ADD CONSTRAINT omni_channel_message_organisation_id_fkey FOREIGN KEY (organisation_id) REFERENCES public.organisation(id) ON UPDATE RESTRICT ON DELETE CASCADE;"
1628
+ ) ;
1617
1629
1618
1630
assert_eq ! ( changed. len( ) , 2 ) ;
1619
1631
@@ -1663,6 +1675,38 @@ KEY (\"organisation_id\") REFERENCES \"public\".\"organisation\"(\"id\") ON UPDA
1663
1675
assert_document_integrity ( & doc) ;
1664
1676
}
1665
1677
1678
+ #[ test]
1679
+ fn test_content_out_of_sync ( ) {
1680
+ let path = PgTPath :: new ( "test.sql" ) ;
1681
+ let initial_content = "select 1, 2, 2232231313393319 from unknown_users;\n " ;
1682
+
1683
+ let mut doc = Document :: new ( initial_content. to_string ( ) , 0 ) ;
1684
+
1685
+ let change1 = ChangeFileParams {
1686
+ path : path. clone ( ) ,
1687
+ version : 1 ,
1688
+ changes : vec ! [
1689
+ ChangeParams {
1690
+ range: Some ( TextRange :: new( 29 . into( ) , 29 . into( ) ) ) ,
1691
+ text: "3" . to_string( ) ,
1692
+ } ,
1693
+ ChangeParams {
1694
+ range: Some ( TextRange :: new( 30 . into( ) , 30 . into( ) ) ) ,
1695
+ text: "1" . to_string( ) ,
1696
+ } ,
1697
+ ] ,
1698
+ } ;
1699
+
1700
+ let _changes = doc. apply_file_change ( & change1) ;
1701
+
1702
+ assert_eq ! (
1703
+ doc. content,
1704
+ "select 1, 2, 223223131339331931 from unknown_users;\n "
1705
+ ) ;
1706
+
1707
+ assert_document_integrity ( & doc) ;
1708
+ }
1709
+
1666
1710
#[ test]
1667
1711
fn test_comments_only ( ) {
1668
1712
let path = PgTPath :: new ( "test.sql" ) ;
0 commit comments