@@ -26,9 +26,10 @@ use super::{ActionCommit, TransactionAction};
2626use crate :: error:: { Error , ErrorKind , Result } ;
2727use crate :: spec:: {
2828 DataContentType , DataFile , ManifestContentType , ManifestEntry , ManifestEntryRef , ManifestFile ,
29- ManifestStatus , Operation ,
29+ ManifestStatus , Operation , SnapshotRef ,
3030} ;
3131use crate :: table:: Table ;
32+ use crate :: transaction:: validate:: SnapshotValidator ;
3233
3334/// Transaction action for rewriting files.
3435pub struct RewriteFilesAction {
@@ -41,7 +42,12 @@ pub struct RewriteFilesAction {
4142 deleted_delete_files : Vec < DataFile > ,
4243}
4344
44- pub struct RewriteFilesOperation ;
45+ pub struct RewriteFilesOperation {
46+ added_data_files : Vec < DataFile > ,
47+ added_delete_files : Vec < DataFile > ,
48+ deleted_data_files : Vec < DataFile > ,
49+ deleted_delete_files : Vec < DataFile > ,
50+ }
4551
4652impl RewriteFilesAction {
4753 pub fn new ( ) -> Self {
@@ -122,13 +128,16 @@ impl TransactionAction for RewriteFilesAction {
122128 self . deleted_delete_files . clone ( ) ,
123129 ) ;
124130
125- // todo need to figure out validation
126- // 1. validate replace and added files
127- // 2. validate no new deletes using the starting snapshot id
131+ let rewrite_operation = RewriteFilesOperation {
132+ added_data_files : self . added_data_files . clone ( ) ,
133+ added_delete_files : self . added_delete_files . clone ( ) ,
134+ deleted_data_files : self . deleted_data_files . clone ( ) ,
135+ deleted_delete_files : self . deleted_delete_files . clone ( ) ,
136+ } ;
128137
129138 // todo should be able to configure merge manifest process
130139 snapshot_producer
131- . commit ( RewriteFilesOperation , DefaultManifestProcess )
140+ . commit ( rewrite_operation , DefaultManifestProcess )
132141 . await
133142 }
134143}
@@ -168,6 +177,36 @@ fn copy_with_deleted_status(entry: &ManifestEntryRef) -> Result<ManifestEntry> {
168177 Ok ( builder. build ( ) )
169178}
170179
180+ impl SnapshotValidator for RewriteFilesOperation {
181+ fn validate ( & self , _table : & Table , _snapshot : Option < & SnapshotRef > ) -> Result < ( ) > {
182+ // Validate replaced and added files
183+ if self . deleted_data_files . is_empty ( ) && self . deleted_delete_files . is_empty ( ) {
184+ return Err ( Error :: new (
185+ ErrorKind :: DataInvalid ,
186+ "Files to delete cannot be empty" ,
187+ ) ) ;
188+ }
189+ if self . deleted_data_files . is_empty ( ) && !self . added_data_files . is_empty ( ) {
190+ return Err ( Error :: new (
191+ ErrorKind :: DataInvalid ,
192+ "Data files to add must be empty because there's no data file to be rewritten" ,
193+ ) ) ;
194+ }
195+ if self . deleted_delete_files . is_empty ( ) && !self . added_delete_files . is_empty ( ) {
196+ return Err ( Error :: new (
197+ ErrorKind :: DataInvalid ,
198+ "Delete files to add must be empty because there's no delete file to be rewritten" ,
199+ ) ) ;
200+ }
201+
202+ // todo add use_starting_seq_number to help the validation
203+ // todo validate no new deletes since the current base
204+ // if there are replaced data files, there cannot be any new row-level deletes for those data files
205+
206+ Ok ( ( ) )
207+ }
208+ }
209+
171210impl SnapshotProduceOperation for RewriteFilesOperation {
172211 fn operation ( & self ) -> Operation {
173212 Operation :: Replace
0 commit comments